923 lines
18 KiB
C
923 lines
18 KiB
C
#
|
|
/*
|
|
|
|
C compiler, part 2
|
|
|
|
|
|
*/
|
|
|
|
#include "c1h.c"
|
|
|
|
char maprel[] { EQUAL, NEQUAL, GREATEQ, GREAT, LESSEQ,
|
|
LESS, GREATQP, GREATP, LESSEQP, LESSP
|
|
};
|
|
|
|
char notrel[] { NEQUAL, EQUAL, GREAT, GREATEQ, LESS,
|
|
LESSEQ, GREATP, GREATQP, LESSP, LESSEQP
|
|
};
|
|
|
|
struct tconst czero { CON, INT, 0, 0};
|
|
struct tconst cone { CON, INT, 0, 1};
|
|
struct tconst fczero { SFCON, DOUBLE, 0, 0 };
|
|
|
|
struct table *cregtab;
|
|
|
|
int nreg 3;
|
|
int isn 10000;
|
|
int namsiz 8;
|
|
|
|
main(argc, argv)
|
|
char *argv[];
|
|
{
|
|
extern fout;
|
|
|
|
if (argc<4) {
|
|
error("Arg count");
|
|
exit(1);
|
|
}
|
|
if(fopen(argv[1], ascbuf)<0) {
|
|
error("Missing temp file");
|
|
exit(1);
|
|
}
|
|
if ((fout = creat(argv[3], 0666)) < 0) {
|
|
error("Can't create %s", argv[3]);
|
|
exit(1);
|
|
}
|
|
spacep = treespace;
|
|
getree();
|
|
/*
|
|
* If any floating-point instructions
|
|
* were used, generate a reference which
|
|
* pulls in the floating-point part of printf.
|
|
*/
|
|
if (nfloat)
|
|
printf(".globl fltused\n");
|
|
/*
|
|
* tack on the string file.
|
|
*/
|
|
close(ascbuf[0]);
|
|
if (fopen(argv[2], ascbuf)<0) {
|
|
error("Missing temp file");
|
|
exit(1);
|
|
}
|
|
printf(".globl\n.data\n");
|
|
getree();
|
|
flush();
|
|
exit(nerror!=0);
|
|
}
|
|
|
|
/*
|
|
* Given a tree, a code table, and a
|
|
* count of available registers, find the code table
|
|
* for the appropriate operator such that the operands
|
|
* are of the right type and the number of registers
|
|
* required is not too large.
|
|
* Return a ptr to the table entry or 0 if none found.
|
|
*/
|
|
char *match(atree, table, nrleft)
|
|
struct tnode *atree;
|
|
struct table *table;
|
|
{
|
|
int op, d1, d2, t1, t2, dope;
|
|
struct tnode *p2;
|
|
register struct tnode *p1, *tree;
|
|
register struct optab *opt;
|
|
|
|
if ((tree=atree)==0)
|
|
return(0);
|
|
if (table==lsptab)
|
|
table = sptab;
|
|
if ((op = tree->op)==0)
|
|
return(0);
|
|
dope = opdope[op];
|
|
if ((dope&LEAF) == 0)
|
|
p1 = tree->tr1;
|
|
else
|
|
p1 = tree;
|
|
t1 = p1->type;
|
|
d1 = dcalc(p1, nrleft);
|
|
if ((dope&BINARY)!=0) {
|
|
p2 = tree->tr2;
|
|
/*
|
|
* If a subtree starts off with a conversion operator,
|
|
* try for a match with the conversion eliminated.
|
|
* E.g. int = double can be done without generating
|
|
* the converted int in a register by
|
|
* movf double,fr0; movfi fr0,int .
|
|
*/
|
|
if(opdope[p1->op]&CNVRT && (opdope[p2->op]&CNVRT)==0) {
|
|
tree->tr1 = p1->tr1;
|
|
if (opt = match(tree, table, nrleft))
|
|
return(opt);
|
|
tree->tr1 = p1;
|
|
} else if (opdope[p2->op]&CNVRT && (opdope[p1->op]&CNVRT)==0) {
|
|
tree->tr2 = p2->tr1;
|
|
if (opt = match(tree, table, nrleft))
|
|
return(opt);
|
|
tree->tr2 = p2;
|
|
}
|
|
t2 = p2->type;
|
|
d2 = dcalc(p2, nrleft);
|
|
}
|
|
for (; table->op!=op; table++)
|
|
if (table->op==0)
|
|
return(0);
|
|
for (opt = table->tabp; opt->tabdeg1!=0; opt++) {
|
|
if (d1 > (opt->tabdeg1&077)
|
|
|| (opt->tabdeg1 >= 0100 && (p1->op != STAR)))
|
|
continue;
|
|
if (notcompat(p1, opt->tabtyp1, op)) {
|
|
continue;
|
|
}
|
|
if ((opdope[op]&BINARY)!=0 && p2!=0) {
|
|
if (d2 > (opt->tabdeg2&077)
|
|
|| (opt->tabdeg2 >= 0100) && (p2->op != STAR) )
|
|
continue;
|
|
if (notcompat(p2,opt->tabtyp2, 0))
|
|
continue;
|
|
}
|
|
return(opt);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Given a tree, a code table, and a register,
|
|
* produce code to evaluate the tree with the appropriate table.
|
|
* Registers reg and upcan be used.
|
|
* If there is a value, it is desired that it appear in reg.
|
|
* The routine returns the register in which the value actually appears.
|
|
* This routine must work or there is an error.
|
|
* If the table called for is cctab, sptab, or efftab,
|
|
* and tree can't be done using the called-for table,
|
|
* another try is made.
|
|
* If the tree can't be compiled using cctab, regtab is
|
|
* used and a "tst" instruction is produced.
|
|
* If the tree can't be compiled using sptab,
|
|
* regtab is used and the register is pushed on the stack.
|
|
* If the tree can't be compiled using efftab,
|
|
* just use regtab.
|
|
* Regtab must succeed or an "op not found" error results.
|
|
*
|
|
* A number of special cases are recognized, and
|
|
* there is an interaction with the optimizer routines.
|
|
*/
|
|
rcexpr(atree, atable, reg)
|
|
struct tnode *atree;
|
|
struct table *atable;
|
|
{
|
|
register r;
|
|
int modf, nargs, recurf;
|
|
register struct tnode *tree;
|
|
register struct table *table;
|
|
|
|
table = atable;
|
|
recurf = 0;
|
|
if (reg<0) {
|
|
recurf++;
|
|
reg = ~reg;
|
|
if (reg>=020) {
|
|
reg =- 020;
|
|
recurf++;
|
|
}
|
|
}
|
|
if((tree=atree)==0)
|
|
return(0);
|
|
switch (tree->op) {
|
|
|
|
/*
|
|
* A conditional branch
|
|
*/
|
|
case CBRANCH:
|
|
cbranch(optim(tree->btree), tree->lbl, tree->cond, 0);
|
|
return(0);
|
|
|
|
/*
|
|
* An initializing expression
|
|
*/
|
|
case INIT:
|
|
if (tree->tr1->op == AMPER)
|
|
tree->tr1 = tree->tr1->tr1;
|
|
if (tree->tr1->op==NAME)
|
|
pname(tree->tr1);
|
|
else if (tree->tr1==CON)
|
|
psoct(tree->tr1->value);
|
|
else
|
|
error("Illegal initialization");
|
|
putchar('\n');
|
|
return(0);
|
|
|
|
/*
|
|
* Put the value of an expression in r0,
|
|
* for a switch or a return
|
|
*/
|
|
case RFORCE:
|
|
if((r=rcexpr(tree->tr1, regtab, reg)) != 0)
|
|
printf("mov%c r%d,r0\n", isfloat(tree->tr1), r);
|
|
return(0);
|
|
|
|
/*
|
|
* sequential execution
|
|
*/
|
|
case COMMA:
|
|
rcexpr(tree->tr1, efftab, reg);
|
|
atree = tree = tree->tr2;
|
|
break;
|
|
|
|
/*
|
|
* In the generated &~ operator,
|
|
* fiddle things so a PDP-11 "bit"
|
|
* instruction will be produced when cctab is used.
|
|
*/
|
|
case NAND:
|
|
if (table==cctab) {
|
|
tree->op = TAND;
|
|
tree->tr2 = optim(block(1, COMPL, INT, 0, tree->tr2));
|
|
}
|
|
break;
|
|
|
|
|
|
/*
|
|
* Handle a subroutine call. It has to be done
|
|
* here because if cexpr got called twice, the
|
|
* arguments might be compiled twice.
|
|
* There is also some fiddling so the
|
|
* first argument, in favorable circumstances,
|
|
* goes to (sp) instead of -(sp), reducing
|
|
* the amount of stack-popping.
|
|
*/
|
|
case CALL:
|
|
r = 0;
|
|
nargs = 0;
|
|
modf = 0;
|
|
if (tree->tr1->op!=NAME) { /* get nargs right */
|
|
nargs++;
|
|
nstack++;
|
|
}
|
|
tree = tree->tr2;
|
|
if(tree->op) {
|
|
while (tree->op==COMMA) {
|
|
r =+ comarg(tree->tr2, &modf);
|
|
tree = tree->tr1;
|
|
nargs++;
|
|
}
|
|
r =+ comarg(tree, &modf);
|
|
nargs++;
|
|
}
|
|
tree = atree;
|
|
tree->op = CALL2;
|
|
if (modf && tree->tr1->op==NAME && tree->tr1->class==EXTERN)
|
|
tree->op = CALL1;
|
|
cexpr(tree, regtab, reg);
|
|
popstk(r);
|
|
nstack =- nargs;
|
|
if (table==efftab || table==regtab)
|
|
return(0);
|
|
r = 0;
|
|
goto fixup;
|
|
|
|
/*
|
|
* Longs need special treatment.
|
|
*/
|
|
case ASLSH:
|
|
case LSHIFT:
|
|
if (tree->type==LONG) {
|
|
if (tree->tr2->op==ITOL)
|
|
tree->tr2 = tree->tr2->tr1;
|
|
if (tree->op==ASLSH)
|
|
tree->op = ASLSHL;
|
|
else
|
|
tree->op = LLSHIFT;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Try to change * and / to shifts.
|
|
*/
|
|
case TIMES:
|
|
case DIVIDE:
|
|
case ASTIMES:
|
|
case ASDIV:
|
|
tree = pow2(tree);
|
|
}
|
|
/*
|
|
* Try to find postfix ++ and -- operators that can be
|
|
* pulled out and done after the rest of the expression
|
|
*/
|
|
if (table!=cctab && table!=cregtab && recurf<2
|
|
&& (opdope[tree->op]&LEAF)==0) {
|
|
if (r=delay(&atree, table, reg)) {
|
|
tree = atree;
|
|
table = efftab;
|
|
reg = r-1;
|
|
}
|
|
}
|
|
/*
|
|
* Basically, try to reorder the computation
|
|
* so reg = x+y is done as reg = x; reg =+ y
|
|
*/
|
|
if (recurf==0 && reorder(&atree, table, reg)) {
|
|
if (table==cctab && atree->op==NAME)
|
|
return(reg);
|
|
}
|
|
tree = atree;
|
|
if (table==efftab && tree->op==NAME)
|
|
return(reg);
|
|
if ((r=cexpr(tree, table, reg))>=0)
|
|
return(r);
|
|
if (table!=regtab) {
|
|
if((r=cexpr(tree, regtab, reg))>=0) {
|
|
fixup:
|
|
modf = isfloat(tree);
|
|
if (table==sptab || table==lsptab) {
|
|
if (tree->type==LONG) {
|
|
printf("mov\tr%d,-(sp)\n",r+1);
|
|
nstack++;
|
|
}
|
|
printf("mov%c r%d,%c(sp)\n", modf, r,
|
|
table==sptab? '-':0);
|
|
nstack++;
|
|
}
|
|
if (table==cctab)
|
|
printf("tst%c r%d\n", modf, r);
|
|
return(r);
|
|
}
|
|
}
|
|
if (tree->op>0 && tree->op<RFORCE && opntab[tree->op])
|
|
error("No code table for op: %s", opntab[tree->op]);
|
|
else
|
|
error("No code table for op %d", tree->op);
|
|
return(reg);
|
|
}
|
|
|
|
/*
|
|
* Try to compile the tree with the code table using
|
|
* registers areg and up. If successful,
|
|
* return the register where the value actually ended up.
|
|
* If unsuccessful, return -1.
|
|
*
|
|
* Most of the work is the macro-expansion of the
|
|
* code table.
|
|
*/
|
|
cexpr(atree, table, areg)
|
|
struct tnode *atree;
|
|
struct table *table;
|
|
{
|
|
int c, r;
|
|
register struct tnode *p, *p1, *tree;
|
|
struct table *ctable;
|
|
struct tnode *p2;
|
|
char *string;
|
|
int reg, reg1, rreg, flag, opd;
|
|
char *opt;
|
|
|
|
tree = atree;
|
|
reg = areg;
|
|
p1 = tree->tr2;
|
|
c = tree->op;
|
|
opd = opdope[c];
|
|
/*
|
|
* When the value of a relational or a logical expression is
|
|
* desired, more work must be done.
|
|
*/
|
|
if ((opd&RELAT||c==LOGAND||c==LOGOR||c==EXCLA) && table!=cctab) {
|
|
cbranch(tree, c=isn++, 1, reg);
|
|
rcexpr(&czero, table, reg);
|
|
branch(isn, 0);
|
|
label(c);
|
|
rcexpr(&cone, table, reg);
|
|
label(isn++);
|
|
return(reg);
|
|
}
|
|
if(c==QUEST) {
|
|
if (table==cctab)
|
|
return(-1);
|
|
cbranch(tree->tr1, c=isn++, 0, reg);
|
|
flag = nstack;
|
|
rreg = rcexpr(p1->tr1, table, reg);
|
|
nstack = flag;
|
|
branch(r=isn++, 0);
|
|
label(c);
|
|
reg = rcexpr(p1->tr2, table, rreg);
|
|
if (rreg!=reg)
|
|
printf("mov%c r%d,r%d\n",
|
|
isfloat(tree),reg,rreg);
|
|
label(r);
|
|
return(rreg);
|
|
}
|
|
reg = oddreg(tree, reg);
|
|
reg1 = reg+1;
|
|
/*
|
|
* long values take 2 registers.
|
|
*/
|
|
if (tree->type==LONG && tree->op!=ITOL)
|
|
reg1++;
|
|
/*
|
|
* Leaves of the expression tree
|
|
*/
|
|
if ((r = chkleaf(tree, table, reg)) >= 0)
|
|
return(r);
|
|
/*
|
|
* x + (-1) is better done as x-1.
|
|
*/
|
|
|
|
if ((tree->op==PLUS||tree->op==ASPLUS) &&
|
|
(p1=tree->tr2)->op == CON && p1->value == -1) {
|
|
p1->value = 1;
|
|
tree->op =+ (MINUS-PLUS);
|
|
}
|
|
if (table==cregtab)
|
|
table = regtab;
|
|
/*
|
|
* The following peculiar code depends on the fact that
|
|
* if you just want the codition codes set, efftab
|
|
* will generate the right code unless the operator is
|
|
* postfix ++ or --. Unravelled, if the table is
|
|
* cctab and the operator is not special, try first
|
|
* for efftab; if the table isn't, if the operator is,
|
|
* or the first match fails, try to match
|
|
* with the table actually asked for.
|
|
*/
|
|
if (table!=cctab || c==INCAFT || c==DECAFT
|
|
|| (opt = match(tree, efftab, nreg-reg)) == 0)
|
|
if ((opt=match(tree, table, nreg-reg))==0)
|
|
return(-1);
|
|
string = opt->tabstring;
|
|
p1 = tree->tr1;
|
|
p2 = 0;
|
|
if (opdope[tree->op]&BINARY)
|
|
p2 = tree->tr2;
|
|
loop:
|
|
/*
|
|
* The 0200 bit asks for a tab.
|
|
*/
|
|
if ((c = *string++) & 0200) {
|
|
c =& 0177;
|
|
putchar('\t');
|
|
}
|
|
switch (c) {
|
|
|
|
case '\0':
|
|
if (!isfloat(tree))
|
|
if (tree->op==DIVIDE || tree->op==ASDIV)
|
|
reg--;
|
|
return(reg);
|
|
|
|
/* A1 */
|
|
case 'A':
|
|
p = p1;
|
|
goto adr;
|
|
|
|
/* A2 */
|
|
case 'B':
|
|
p = p2;
|
|
goto adr;
|
|
|
|
adr:
|
|
c = 0;
|
|
if (*string=='\'') {
|
|
c = 1;
|
|
string++;
|
|
} else if (*string=='+') {
|
|
c = 2;
|
|
string++;
|
|
}
|
|
pname(p, c);
|
|
goto loop;
|
|
|
|
/* I */
|
|
case 'M':
|
|
if ((c = *string)=='\'')
|
|
string++;
|
|
else
|
|
c = 0;
|
|
prins(tree->op, c, instab);
|
|
goto loop;
|
|
|
|
/* B1 */
|
|
case 'C':
|
|
if ((opd&LEAF) != 0)
|
|
p = tree;
|
|
else
|
|
p = p1;
|
|
goto pbyte;
|
|
|
|
/* BF */
|
|
case 'P':
|
|
p = tree;
|
|
goto pb1;
|
|
|
|
/* B2 */
|
|
case 'D':
|
|
p = p2;
|
|
pbyte:
|
|
if (p->type==CHAR)
|
|
putchar('b');
|
|
pb1:
|
|
if (isfloat(p))
|
|
putchar('f');
|
|
goto loop;
|
|
|
|
/* BE */
|
|
case 'L':
|
|
if (p1->type==CHAR || p2->type==CHAR)
|
|
putchar('b');
|
|
p = tree;
|
|
goto pb1;
|
|
|
|
/* F */
|
|
case 'G':
|
|
p = p1;
|
|
flag = 01;
|
|
goto subtre;
|
|
|
|
/* S */
|
|
case 'K':
|
|
p = p2;
|
|
flag = 02;
|
|
goto subtre;
|
|
|
|
/* H */
|
|
case 'H':
|
|
p = tree;
|
|
flag = 04;
|
|
|
|
subtre:
|
|
ctable = regtab;
|
|
c = *string++ - 'A';
|
|
if (*string=='!') {
|
|
string++;
|
|
c =| 020; /* force right register */
|
|
}
|
|
if ((c&02)!=0)
|
|
ctable = sptab;
|
|
if ((c&04)!=0)
|
|
ctable = cctab;
|
|
if ((flag&01) && ctable==regtab && (c&01)==0
|
|
&& (tree->op==DIVIDE||tree->op==MOD
|
|
|| tree->op==ASDIV||tree->op==ASMOD))
|
|
ctable = cregtab;
|
|
if ((c&01)!=0) {
|
|
p = p->tr1;
|
|
if(collcon(p) && ctable!=sptab) {
|
|
if (p->op==STAR)
|
|
p = p->tr1;
|
|
p = p->tr1;
|
|
}
|
|
}
|
|
if (table==lsptab && ctable==sptab)
|
|
ctable = lsptab;
|
|
if (c&010)
|
|
r = reg1;
|
|
else
|
|
if (opdope[p->op]&LEAF || p->degree < 2)
|
|
r = reg;
|
|
else
|
|
r = areg;
|
|
rreg = rcexpr(p, ctable, r);
|
|
if (ctable!=regtab && ctable!=cregtab)
|
|
goto loop;
|
|
if (c&010) {
|
|
if (c&020 && rreg!=reg1)
|
|
printf("mov%c r%d,r%d\n",
|
|
isfloat(tree),rreg,reg1);
|
|
else
|
|
reg1 = rreg;
|
|
} else if (rreg!=reg)
|
|
if ((c&020)==0 && oddreg(tree, 0)==0 && (flag&04 ||
|
|
flag&01
|
|
&& xdcalc(p2, nreg-rreg-1) <= (opt->tabdeg2&077)
|
|
|| flag&02
|
|
&& xdcalc(p1,nreg-rreg-1) <= (opt->tabdeg1&077))) {
|
|
reg = rreg;
|
|
reg1 = rreg+1;
|
|
} else
|
|
printf("mov%c\tr%d,r%d\n",
|
|
isfloat(tree), rreg, reg);
|
|
goto loop;
|
|
|
|
/* R */
|
|
case 'I':
|
|
r = reg;
|
|
if (*string=='-') {
|
|
string++;
|
|
r--;
|
|
}
|
|
goto preg;
|
|
|
|
/* R1 */
|
|
case 'J':
|
|
r = reg1;
|
|
preg:
|
|
if (*string=='+') {
|
|
string++;
|
|
r++;
|
|
}
|
|
if (r>nreg)
|
|
error("Register overflow: simplify expression");
|
|
printf("r%d", r);
|
|
goto loop;
|
|
|
|
case '-': /* check -(sp) */
|
|
if (*string=='(') {
|
|
nstack++;
|
|
if (table!=lsptab)
|
|
putchar('-');
|
|
goto loop;
|
|
}
|
|
break;
|
|
|
|
case ')': /* check (sp)+ */
|
|
putchar(')');
|
|
if (*string=='+')
|
|
nstack--;
|
|
goto loop;
|
|
|
|
/* #1 */
|
|
case '#':
|
|
p = p1->tr1;
|
|
goto nmbr;
|
|
|
|
/* #2 */
|
|
case '"':
|
|
p = p2->tr1;
|
|
|
|
nmbr:
|
|
if(collcon(p)) {
|
|
if (p->op==STAR) {
|
|
printf("*");
|
|
p = p->tr1;
|
|
}
|
|
if ((p = p->tr2)->op == CON) {
|
|
if (p->value)
|
|
psoct(p->value);
|
|
} else if (p->op==AMPER)
|
|
pname(p->tr1, 0);
|
|
}
|
|
goto loop;
|
|
|
|
case 'T': /* "tst R" if 1st op not in cctab */
|
|
if (dcalc(p1, 5)>12 && !match(p1, cctab, 10))
|
|
printf("tst r%d\n", reg);
|
|
goto loop;
|
|
case 'V': /* adc or sbc as required for longs */
|
|
switch(tree->op) {
|
|
case PLUS:
|
|
case ASPLUS:
|
|
case INCBEF:
|
|
case INCAFT:
|
|
printf("adc");
|
|
break;
|
|
|
|
case MINUS:
|
|
case ASMINUS:
|
|
case NEG:
|
|
case DECBEF:
|
|
case DECAFT:
|
|
printf("sbc");
|
|
break;
|
|
|
|
default:
|
|
while ((c = *string++)!='\n' && c!='\0');
|
|
break;
|
|
}
|
|
goto loop;
|
|
}
|
|
putchar(c);
|
|
goto loop;
|
|
}
|
|
|
|
/*
|
|
* This routine just calls sreorder (below)
|
|
* on the subtrees and then on the tree itself.
|
|
* It returns non-zero if anything changed.
|
|
*/
|
|
reorder(treep, table, reg)
|
|
struct tnode **treep;
|
|
struct table *table;
|
|
{
|
|
register r, r1;
|
|
register struct tnode *p;
|
|
|
|
p = *treep;
|
|
if (opdope[p->op]&LEAF)
|
|
return(0);
|
|
r1 = 0;
|
|
while(sreorder(&p->tr1, table, reg))
|
|
r1++;
|
|
if (opdope[p->op]&BINARY)
|
|
while(sreorder(&p->tr2, table, reg))
|
|
r1++;
|
|
r = 0;
|
|
while (sreorder(treep, table, reg))
|
|
r++;
|
|
*treep = optim(*treep);
|
|
return(r);
|
|
}
|
|
|
|
/*
|
|
* Basically this routine carries out two kinds of optimization.
|
|
* First, it observes that "x + (reg = y)" where actually
|
|
* the = is any assignment op is better done as "reg=y; x+reg".
|
|
* In this case rcexpr is called to do the first part and the
|
|
* tree is modified so the name of the register
|
|
* replaces the assignment.
|
|
* Moreover, expressions like "reg = x+y" are best done as
|
|
* "reg = x; reg =+ y" (so long as "reg" and "y" are not the same!).
|
|
*/
|
|
sreorder(treep, table, reg)
|
|
struct tnode **treep;
|
|
struct table *table;
|
|
{
|
|
register struct tnode *p, *p1;
|
|
|
|
p = *treep;
|
|
if (opdope[p->op]&LEAF)
|
|
return(0);
|
|
if (p->op==PLUS)
|
|
if (reorder(&p->tr2, table, reg))
|
|
*treep = p = optim(p);
|
|
p1 = p->tr1;
|
|
if (p->op==STAR || p->op==PLUS) {
|
|
if (reorder(&p->tr1, table, reg))
|
|
*treep = p = optim(p);
|
|
p1 = p->tr1;
|
|
}
|
|
if (p1->op==NAME) switch(p->op) {
|
|
case ASLSH:
|
|
case ASRSH:
|
|
case ASSIGN:
|
|
if (p1->class != REG || isfloat(p->tr2))
|
|
return(0);
|
|
if (p->op==ASSIGN) switch (p->tr2->op) {
|
|
case TIMES:
|
|
case DIVIDE:
|
|
if (!ispow2(p->tr2))
|
|
break;
|
|
p->tr2 = pow2(p->tr2);
|
|
case PLUS:
|
|
case MINUS:
|
|
case AND:
|
|
case NAND:
|
|
case OR:
|
|
case EXOR:
|
|
case LSHIFT:
|
|
case RSHIFT:
|
|
p1 = p->tr2->tr2;
|
|
if (xdcalc(p1) > 12
|
|
|| p1->op==NAME
|
|
&&(p1->nloc==p->tr1->nloc
|
|
|| p1->regno==p->tr1->nloc))
|
|
return(0);
|
|
p1 = p->tr2;
|
|
p->tr2 = p1->tr1;
|
|
if (p1->tr1->op!=NAME
|
|
|| p1->tr1->class!=REG
|
|
|| p1->tr1->nloc!=p->tr1->nloc)
|
|
rcexpr(p, efftab, reg);
|
|
p->tr2 = p1->tr2;
|
|
p->op = p1->op + ASPLUS - PLUS;
|
|
*treep = p;
|
|
return(1);
|
|
}
|
|
goto OK;
|
|
|
|
case ASTIMES:
|
|
case ASDIV:
|
|
if (!ispow2(p))
|
|
return(0);
|
|
case ASPLUS:
|
|
case ASMINUS:
|
|
case ASSAND:
|
|
case ASSNAND:
|
|
case ASOR:
|
|
case ASXOR:
|
|
case DECBEF:
|
|
case INCBEF:
|
|
OK:
|
|
if (table==cctab||table==cregtab)
|
|
reg =+ 020;
|
|
rcexpr(optim(p), efftab, ~reg);
|
|
*treep = p1;
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Delay handles postfix ++ and --
|
|
* It observes that "x + y++" is better
|
|
* treated as "x + y; y++".
|
|
* If the operator is ++ or -- itself,
|
|
* it calls rcexpr to load the operand, letting
|
|
* the calling instance of rcexpr to do the
|
|
* ++ using efftab.
|
|
* Otherwise it uses sdelay to search for inc/dec
|
|
* among the operands.
|
|
*/
|
|
delay(treep, table, reg)
|
|
struct tnode **treep;
|
|
{
|
|
register struct tnode *p, *p1;
|
|
register r;
|
|
|
|
p = *treep;
|
|
if (table!=efftab && (p->op==INCAFT||p->op==DECAFT)
|
|
&& p->tr1->op==NAME) {
|
|
return(1+rcexpr(p->tr1, table, reg));
|
|
}
|
|
p1 = 0;
|
|
if (opdope[p->op]&BINARY)
|
|
p1 = sdelay(&p->tr2);
|
|
if (p1==0)
|
|
p1 = sdelay(&p->tr1);
|
|
if (p1) {
|
|
r = rcexpr(optim(p), table, reg);
|
|
*treep = p1;
|
|
return(r+1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
sdelay(ap)
|
|
struct tnode **ap;
|
|
{
|
|
register struct tnode *p, *p1;
|
|
|
|
p = *ap;
|
|
if ((p->op==INCAFT||p->op==DECAFT) && p->tr1->op==NAME) {
|
|
*ap = ncopy(p->tr1);
|
|
return(p);
|
|
}
|
|
if (p->op==STAR || p->op==PLUS)
|
|
if (p1=sdelay(&p->tr1))
|
|
return(p1);
|
|
if (p->op==PLUS)
|
|
return(sdelay(&p->tr2));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Copy a tree node for a register variable.
|
|
* Used by sdelay because if *reg-- is turned
|
|
* into *reg; reg-- the *reg will in turn
|
|
* be changed to some offset class, accidentally
|
|
* modifying the reg--.
|
|
*/
|
|
ncopy(ap)
|
|
struct tname *ap;
|
|
{
|
|
register struct tname *p;
|
|
|
|
p = ap;
|
|
if (p->class!=REG)
|
|
return(p);
|
|
return(block(3, NAME, p->type, p->elsize, p->tr1,
|
|
p->offset, p->nloc));
|
|
}
|
|
|
|
/*
|
|
* If the tree can be immediately loaded into a register,
|
|
* produce code to do so and return success.
|
|
*/
|
|
chkleaf(atree, table, reg)
|
|
struct tnode *atree;
|
|
{
|
|
struct tnode lbuf;
|
|
register struct tnode *tree;
|
|
|
|
tree = atree;
|
|
if (tree->op!=STAR && dcalc(tree, nreg-reg) > 12)
|
|
return(-1);
|
|
lbuf.op = LOAD;
|
|
lbuf.type = tree->type;
|
|
lbuf.degree = tree->degree;
|
|
lbuf.tr1 = tree;
|
|
return(rcexpr(&lbuf, table, reg));
|
|
}
|
|
|
|
/*
|
|
* Compile a function argument.
|
|
* If the stack is currently empty, put it in (sp)
|
|
* rather than -(sp); this will save a pop.
|
|
* Return the number of bytes pushed,
|
|
* for future popping.
|
|
*/
|
|
comarg(atree, flagp)
|
|
int *flagp;
|
|
{
|
|
register struct tnode *tree;
|
|
register retval;
|
|
|
|
tree = atree;
|
|
if (nstack || isfloat(tree) || tree->type==LONG) {
|
|
rcexpr(tree, sptab, 0);
|
|
retval = arlength(tree->type);
|
|
} else {
|
|
(*flagp)++;
|
|
rcexpr(tree, lsptab, 0);
|
|
retval = 0;
|
|
}
|
|
return(retval);
|
|
}
|