Add original unix v6
This commit is contained in:
+922
@@ -0,0 +1,922 @@
|
||||
#
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user