Interdata_v6/usr/source/c/c10.c
#
/*
C compiler, part 2
*/
#include "c1.h"
#define dbprint(op) /* */
#ifdef DEBUG
#define dbprint(op) printf("\t. %s", opntab[op]) /***/
#endif
/*
* If using OS/MT CAL assembler, read string file first, since
* it contains ENTRY definitions for functions
*/
#ifdef unix
#define FILE1 argv[1]
#define FILE2 argv[2]
#else
#define FILE1 argv[2]
#define FILE2 argv[1]
#endif
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};
struct tconst cone { CON, INT, 1};
struct table cregtab[1], lsptab[1];
int nreg 6; /***/
int isn 10000;
main(argc, argv)
char *argv[];
{
/***/ register i;
extern fout;
if (argc<4) {
error("Arg count");
exit(1);
}
if(fopen(FILE1, ascbuf)<0) {
error("Missing temp file");
exit(1);
}
if ((fout = creat(argv[3], 0666)) < 0) {
error("Can't create %s", argv[3]);
exit(1);
}
/***
*** Write register equates
***/
/***/ for (i = 0; i < 16; i++)
/***/ printf("r%d equ %d\n", i, i);
/***/ printf("sp equ 7\nrf equ 15\n");
funcbase = curbase = coremax = sbrk(0);
getree();
/***/ printf(" align adc\n");
/***/ sdata();
/*
* If any floating-point instructions
* were used, generate a reference which
* pulls in the floating-point part of printf.
*/
if (nfloat)
/***/ printf("\textrn fltused\n\tdc\tfltused\n");
/*
* tack on the string file.
*/
close(ascbuf[0]);
if (fopen(FILE2, ascbuf)<0) {
error("Missing temp file");
exit(1);
}
getree();
/***/ printf(" end\n");
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, dope;
register struct tnode *p2;
register struct tnode *p1, *tree;
register struct optab *opt;
if ((tree=atree)==0)
return(0);
if ((op = tree->op)==0)
return(0);
if (table == lsptab)
table = sptab;
dope = opdope[op];
if ((dope&LEAF) == 0)
p1 = tree->tr1;
else
p1 = tree;
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
&& (opdope[p1->tr1->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
&& (opdope[p2->tr1->op]&CNVRT)==0) {
tree->tr2 = p2->tr1;
if (opt = match(tree, table, nrleft))
return(opt);
tree->tr2 = p2;
}
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 (op != AMPER && 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;
/***
*** Kludge for SHORT - mh and dh don't mean what
*** you think, so special case is required.
*** This should really be handled by a new
*** code table category.
***/
/***/ if (p2->type==SHORT && opt->tabtyp2==1
/***/ && (op==TIMES || op==ASTIMES || op==DIVIDE
/***/ || op==ASDIV || op==MOD || op==ASMOD))
/***/ 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++;
}
}
again:
if((tree=atree)==0)
return(0);
if (opdope[tree->op]&RELAT && tree->tr2->op==CON && tree->tr2->value==0
&& table==cctab)
tree = atree = tree->tr1;
/*
* fieldselect(...) : in efftab mode,
* ignore the select, otherwise
* do the shift and mask.
*/
if (tree->op == FSELT) {
if (table==efftab)
atree = tree = tree->tr1;
else {
tree->op = FSEL;
atree = tree = optim(tree);
}
}
switch (tree->op) {
/*
* An initializing expression
*/
case INIT:
tree = optim(tree);
doinit(tree->type, tree->tr1);
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)
movreg(r, 0, tree->tr1);
return(0);
/*
* sequential execution
*/
case SEQNC:
rcexpr(tree->tr1, efftab, reg);
atree = tree = tree->tr2;
goto again;
/*
* 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 || tree->tr1->class!=EXTERN) {
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;
***/
/***/ /* Find length of arguments and adjust stack */
/***/ nargs = pstack;
/***/ r = 0;
/***/ tree = tree->tr2;
/***/ if (tree->op) {
/***/ while (tree->op == COMMA) {
/***/ r =+ arlength(tree->tr2->type);
/***/ tree = tree->tr1;
/***/ }
/***/ r =+ arlength(tree->type);
/***/ r =/ NCPW;
/***/ if ((modf = nstack+r) > pstack)
/***/ setstk(modf);
/***/ if (modf < pstack) {
/***/ nstack =+ pstack-modf;
/***/ r =+ pstack-modf;
/***/ }
/***/ /* Compile arguments onto stack */
/***/ tree = atree->tr2;
/***/ while (tree->op == COMMA) {
/***/ comarg(tree->tr2);
/***/ tree = tree->tr1;
/***/ }
/***/ comarg(tree);
/***/ }
/***/ tree = atree;
/***/ tree->op = CALL1;
/***/ cexpr(tree, regtab, reg);
/***/ if (pstack != nargs)
/***/ setstk(nargs);
/***/ nstack =- r;
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;
else
tree->tr2 = optim(tnode(LTOI,INT,tree->tr2));
if (tree->op==ASLSH)
tree->op = ASLSHL;
else
tree->op = LLSHIFT;
}
break;
/*
* Try to change * to shift.
*/
case TIMES:
case ASTIMES:
tree = pow2(tree);
break;
/***
*** Interdata special: change --, -= to ++, += to use AM instruction
***/
/***/ case ASMINUS:
/***/ if (tree->tr2->op != CON)
/***/ break;
/***/ case DECBEF:
/***/ case DECAFT:
/***/ if (table==efftab || table==cctab) {
/***/ tree->op =+ (ASPLUS-ASMINUS);
/***/ tree->tr2->value = -tree->tr2->value;
/***/ }
}
/*
* 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 && (table!=cctab||(opdope[tree->op]&RELAT)==0)) {
if((r=cexpr(tree, regtab, reg))>=0) {
fixup:
/***/ modf = ishfloat(tree);
if (table==sptab) {
/***/ if(tree->type==LONG)
/***/ printf("\tsta\tr%d,%d(sp)\n",
/***/ r+1, (pstack-nstack+1)*NCPW);
/***/ printf("\tst%c\tr%d,%d(sp)\n", modf,
/***/ modf=='e'? r*2 : r, (pstack-nstack)*NCPW);
}
/***/ if (table==lsptab) {
/***/ printf("\tst%c\tr%d,%d(r14)\n", modf,
/***/ modf=='e'? r*2 : r, NCPW*(ntemp-1));
/***/ }
if (table==cctab)
/***/ movreg(r, r, tree);
return(r);
}
}
/*
* There's a last chance for this operator
*/
if (tree->op==LTOI) {
r = rcexpr(tree->tr1, regtab, reg);
if (r >= 0) {
r++;
goto fixup;
}
}
if (tree->type == STRUCT)
error("Illegal operation on structure");
else 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;
register 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)
movreg(reg, rreg, tree->tr2);
label(r);
return(rreg);
}
reg = oddreg(tree, reg);
reg1 = reg+1;
/*
* long values take 2 registers.
*/
if ((tree->type==LONG||opd&RELAT&&tree->tr1->type==LONG) && tree->op!=ITOL)
reg1++;
/*
* Leaves of the expression tree
*/
if ((r = chkleaf(tree, table, reg)) >= 0)
return(r);
/*
* Because of a peculiarity of the PDP11 table
* char = *intreg++ and *--intreg cannot go through.
*/
/***
if (tree->tr1->type==CHAR && tree->tr2->type!=CHAR
&& (tree->tr2->op==AUTOI||tree->tr2->op==AUTOD))
tree->tr2 = tnode(LOAD, tree->tr2->type, tree->tr2);
***/
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
*** ASSIGN or
* 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.
*/
r = nreg - reg;
/***/ if (table!=cctab || c==ASSIGN
/***/ || c==INCAFT || c==DECAFT || tree->type==LONG
|| (opt = match(tree, efftab, r)) == 0)
if ((opt=match(tree, table, r))==0)
return(-1);
string = opt->tabstring;
p1 = tree->tr1;
if (p1->op==FCON && p1->value>0) {
/***
*** Warning -- lark's vomit
*** (won't work on the 7/16)
***/
/***/ printf(" impur\nL%d\tdc\ty'%x'\n pure\n", p1->value, p1->fvalue);
p1->value = -p1->value;
}
p2 = 0;
if (opdope[tree->op]&BINARY) {
p2 = tree->tr2;
if (p2->op==FCON && p2->value>0) {
/***/ printf(" impur\nL%d\tdc\ty'%x'\n pure\n",
/***/ p2->value, p2->fvalue);
p2->value = -p2->value;
}
}
loop:
/*
* The 0200 bit asks for a tab.
*/
if ((c = *string++) & 0200) {
c =& 0177;
putchar('\t');
}
switch (c) {
case '\n':
dbprint(tree->op);
break;
case '\0':
if (!isfloat(tree))
if (tree->op==MOD||tree->op==ASMOD)
reg--;
return(reg);
/* A1 */
case 'A':
p = p1;
goto adr;
/* A2 */
case 'B':
p = p2;
goto adr;
adr:
c = 0;
while (*string=='\'') {
c++;
string++;
}
if (*string=='+') {
c = 100;
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->op==CON || p->op==AMPER) {
#ifdef HALFW
/***/ putchar('h');
#endif
/***/ putchar('i');
/***/ goto loop;
/***/ }
/***/ if (p->op==NAME && p->class==REG) {
#ifdef HALFW
/***/ putchar('h');
#endif
/***/ putchar('r');
/***/ goto loop;
/***/ }
/***/ if (p->type==CHAR) {
/***/ putchar('b');
/***/ goto loop;
/***/ }
/***/ if (p->type==SHORT) {
/***/ putchar('h');
/***/ goto loop;
/***/ }
/***/ pb1:
/***/ if (c=ishfloat(p))
/***/ putchar(c);
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;
if (flag&04)
ctable = cregtab;
c = *string++ - 'A';
/***/ if ((c&020) && !reg) { /* nonzero register required */
/***/ reg = 1;
/***/ reg1 = 2;
/***/ }
if (*string=='!') {
string++;
c =| 020; /* force right register */
}
/***/ if ((c&02)!=0) {
/***/ ctable = lsptab;
/***/ if (++ntemp > maxtemp)
/***/ maxtemp = ntemp;
/***/ }
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!=lsptab) {
/***
if (p->op==STAR)
p = p->tr1;
***/
p = p->tr1;
}
}
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)
movreg(rreg, reg1, p);
else
reg1 = rreg;
} else if (rreg!=reg)
if ((c&020)==0 && oddreg(tree, 0)==0 && tree->type!=LONG
&& (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
movreg(rreg, reg, p);
goto loop;
/* R */
case 'I':
r = reg;
if (*string=='-') {
string++;
r--;
}
goto preg;
/* R1 */
case 'J':
r = reg1;
preg:
if (*string=='+') {
string++;
r++;
}
/***/ else if (*string==':') {
/***/ string++;
/***/ if (tree->op==MOD || tree->op==ASMOD)
/***/ r--;
/***/ }
/***/ else if (*string=='*') {
/***/ string++;
/***/ if (isfloat(tree) || tree->op==FTOI) {
/***/ r =* 2;
/***/ goto pregf;
/***/ }
/***/ }
if (r>nreg || r>=4 && tree->type==DOUBLE)
error("Register overflow: simplify expression");
/***/ pregf:
printf("r%d", r);
goto loop;
/***/ /* P */
/***/ case 'Q':
/***/ if (*string == '-') { /* push onto stack */
/***/ string++;
/***/ if (++ntemp > maxtemp)
/***/ maxtemp = ntemp;
/***/ goto loop;
/***/ }
/***/ /* reference to top word on stack */
/***/ if (table==sptab)
/***/ printf("%d(sp)", (pstack - nstack)*NCPW);
/***/ else
/***/ printf("%d(r14)", NCPW*(ntemp-1));
/***/ if (*string == '+') { /* pop stack */
/***/ string++;
/***/ ntemp--;
/***/ }
/***/ 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
/***/ putchar('0');
} else if (p->op==AMPER)
pname(p->tr1, 0);
}
/***/ else
/***/ putchar('0');
goto loop;
/*
* Certain adjustments for / % and PTOI
*/
case 'T':
c = reg-1;
/***
if (tree->op == PTOI) {
printf("bic r%d,r%d\nsbc r%d\n", c,c,c);
goto loop;
}
if (p1->type==UNSIGN || p1->type&XTYPE) {
printf("clr r%d\n", c);
goto loop;
}
if (dcalc(p1, 5)>12 && !match(p1, cctab, 10))
printf("tst r%d\n", reg);
printf("sxt r%d\n", c);
***/
/***/ if (tree->op==PTOI || p1->type==UNSIGN || p1->type&XTYPE) {
/***/ printf("\tlis\tr%d,0\n", c);
/***/ goto loop;
/***/ }
/***/ printf("\tldar\tr%d,r%d\n\tsraa\tr%d,31\n", c, reg, c);
goto loop;
/* adc sbc, clr, or sxt as required for longs */
/***
case 'V':
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;
case ASSIGN:
p = tree->tr2;
goto lcasev;
case ASDIV:
case ASMOD:
case ASULSH:
p = tree->tr1;
lcasev:
if (p->type!=LONG) {
if (p->type==UNSIGN || p->type&XTYPE)
printf("clr");
else
printf("sxt");
goto loop;
}
default:
while ((c = *string++)!='\n' && c!='\0');
break;
}
goto loop;
***/
/*
* Mask used in field assignments
*/
case 'Z':
/***/ psoct(~tree->mask);
goto loop;
/*
* Relational on long values.
* Might bug out early. E.g.,
* (long<0) can be determined with only 1 test.
*/
case 'X':
if (xlongrel(*string++ - '0'))
return(reg);
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, o;
register struct tnode *p;
p = *treep;
o = p->op;
if (opdope[o]&LEAF || o==LOGOR || o==LOGAND)
return(0);
while(sreorder(&p->tr1, regtab, reg))
;
if (opdope[o]&BINARY)
while(sreorder(&p->tr2, regtab, reg))
;
r = 0;
/***/ if (table!=cctab && table!=cregtab)
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 (opdope[p->op]&LEAF)
/***/ return(0);
/***/ if (p1->op==NAME && p1->class==REG) switch(p->op) {
case ASLSH:
case ASRSH:
case ASSIGN:
/***/ if (p1->type==CHAR||isfloat(p->tr2))
return(0);
if (p->op==ASSIGN) switch (p->tr2->op) {
case TIMES:
if (!ispow2(p->tr2))
break;
p->tr2 = pow2(p->tr2);
case PLUS:
case MINUS:
case AND:
case ANDN:
case OR:
case EXOR:
case LSHIFT:
case RSHIFT:
p1 = p->tr2->tr2;
if (xdcalc(p1, 16) > 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:
if (!ispow2(p))
return(0);
case ASPLUS:
case ASMINUS:
case ASAND:
case ASANDN:
case ASOR:
case ASXOR:
case INCBEF:
case DECBEF:
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 + reg++" is better
*** treated as "x + reg; reg++".
* 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 ((p->op==INCAFT||p->op==DECAFT)
/***/ && p->tr1->op==NAME && p->tr1->class==REG) {
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
/***/ && p->tr1->class==REG) {
*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, *q;
p = ap;
if (p->class!=REG)
return(p);
q = getblk(sizeof(*p));
q->op = p->op;
q->type = p->type;
q->class = p->class;
q->offset = p->offset;
q->nloc = p->nloc;
return(q);
}
/*
* 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);
/***/ if (tree->op==AMPER)
/***/ 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)
{
register struct tnode *tree;
register retval;
tree = atree;
/***/ if (tree->type == LONG)
/***/ nstack++;
/***/ nstack++;
/***/ rcexpr(tree, sptab, 0);
}
/*
* Compile an initializing expression
*/
doinit(atype, atree)
struct tnode *atree;
{
register struct tnode *tree;
register int type;
float sfval;
double fval;
long lval;
/***/ register val;
tree = atree;
type = atype;
if (type==CHAR) {
/***/ printf("\tdb\t");
if (tree->type&XTYPE)
goto illinit;
}
/***/ else
/***/ printf("\tdc\t");
if (type&XTYPE)
type = INT;
switch (type) {
case INT:
case UNSIGN:
/***/ case SHORT:
/***/ case CHAR:
if (tree->op==FTOI) {
if (tree->tr1->op!=FCON && tree->tr1->op!=SFCON)
goto illinit;
tree = tree->tr1;
tree->value = tree->fvalue;
tree->op = CON;
} else if (tree->op==LTOI) {
if (tree->tr1->op!=LCON)
goto illinit;
tree = tree->tr1;
lval = tree->lvalue;
tree->op = CON;
tree->value = lval;
}
/***/ if (tree->op == CON) {
/***/ val = tree->value;
/***/ if (type==SHORT) {
/***/ if (val < -0x8000 || val > 0xffff)
/***/ goto illinit;
/***/ printf("x'%x'\n", val&0xffff);
/***/ } else {
/***/ if (type==CHAR) {
/***/ if (val < -0x80 || val > 0xff)
/***/ goto illinit;
/***/ val =& 0xff;
/***/ }
/***/ psoct(val);
/***/ putchar('\n');
/***/ }
/***/ }
/***/ else if (tree->op==AMPER && type!=SHORT && type!=CHAR) {
pname(tree->tr1, 0);
putchar('\n');
} else
goto illinit;
return;
case DOUBLE:
case FLOAT:
if (tree->op==ITOF) {
if (tree->tr1->op==CON) {
fval = tree->tr1->value;
} else
goto illinit;
} else if (tree->op==FCON || tree->op==SFCON)
fval = tree->fvalue;
else if (tree->op==LTOF) {
if (tree->tr1->op!=LCON)
goto illinit;
fval = tree->tr1->lvalue;
} else
goto illinit;
/***
if (type==FLOAT) {
***/
sfval = fval;
/***/ psoct(sfval);
/***/ putchar('\n');
/***
} else
printf("%o; %o; %o; %o\n", fval);
***/
return;
/***
case LONG:
if (tree->op==FTOL) {
tree = tree->tr1;
if (tree->op==SFCON)
tree->op = FCON;
if (tree->op!= FCON)
goto illinit;
lval = tree->fvalue;
} else if (tree->op==ITOL) {
if (tree->tr1->op != CON)
goto illinit;
lval = tree->tr1->value;
} else if (tree->op==LCON)
lval = tree->lvalue;
else
goto illinit;
printf("%o; %o\n", lval);
return;
***/
}
illinit:
error("Illegal initialization");
}
/***
movreg(r0, r1, tree)
struct tnode *tree;
{
register char *s;
if (r0==r1)
return;
if (tree->type==LONG) {
s = "mov r%d,r%d\nmov r%d,r%d\n";
if (r0 < r1)
printf(s, r0+1,r1+1,r0,r1);
else
printf(s, r0,r1,r0+1,r1+1);
return;
}
printf("mov%c r%d,r%d\n", isfloat(tree), r0, r1);
}
***/
movreg(rsource, rdest, tree)
struct tnode *tree;
{
register r1, r2, modf;
r1 = rdest;
r2 = rsource;
if ((modf = ishfloat(tree)) == 'e') {
r1 =* 2;
r2 =* 2;
}
printf("\tl%cr\tr%d,r%d\n", modf, r1, r2);
}
/***
*** Adjust stack pointer up or down to ns
***/
setstk(ns)
{
register op, offset;
register char *s;
op = 's';
if ((offset = (ns-pstack)*NCPW) < 0) {
op = 'a';
offset = -offset;
}
s = (offset<16? "is" : (offset>>15? "ai" : "hi"));
printf("\t%c%s\tsp,%d\n", op, s, offset);
pstack = ns;
}