#ifndef lint
-static char sccsid[] = "@(#)local2.c 1.10 (Berkeley) %G%";
+static char sccsid[] = "@(#)local2.c 1.32 (Berkeley) 2/29/88";
#endif
# include "pass2.h"
# define BITMASK(n) ((1L<<n)-1)
# ifndef ONEPASS
+/*ARGSUSED*/
where(c){
fprintf( stderr, "%s, line %d: ", filename, lineno );
}
SETOFF(spoff,4);
#ifdef FORT
#ifndef FLEXNAMES
- printf( " .set .F%d,%d\n", ftnno, spoff );
+ printf( " .set .F%d,%ld\n", ftnno, spoff );
#else
/* SHOULD BE L%d ... ftnno but must change pc/f77 */
- printf( " .set LF%d,%d\n", ftnno, spoff );
+ printf( " .set LF%d,%ld\n", ftnno, spoff );
#endif
printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
#else
printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
printf( "L%d:\n", ftlab1);
if( maxoff > AUTOINIT )
- printf( " subl3 $%d,fp,sp\n", spoff);
+ printf( " subl3 $%ld,fp,sp\n", spoff);
printf( " jbr L%d\n", ftlab2);
#endif
ent_mask = 0;
register int r;
{
- ent_mask |= 1<<r;
+ if (!istreg(r))
+ ent_mask |= 1<<r;
return(rnames[r]);
}
case SHORT:
case USHORT:
- return(2);
+ return(SZSHORT/SZCHAR);
case DOUBLE:
- return(8);
+ return(SZDOUBLE/SZCHAR);
default:
- return(4);
+ return(SZINT/SZCHAR);
}
}
-anyfloat(p, q)
- NODE *p, *q;
+mixtypes(p, q) NODE *p, *q;
{
register TWORD tp, tq;
tp = p->in.type;
tq = q->in.type;
- return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
+
+ return( (tp==FLOAT || tp==DOUBLE) !=
+ (tq==FLOAT || tq==DOUBLE) );
}
prtype(n) NODE *n;
putchar('f');
return;
+ case LONG:
+ case ULONG:
case INT:
case UNSIGNED:
putchar('l');
cbgen( p->in.op, p->bn.label, c );
return;
- case 'A': /* assignment and load (integer only) */
+ case 'G': /* i *= f; asgops with int lhs and float rhs */
{
- register NODE *l, *r;
+ register NODE *l, *r, *s;
+ int lt, rt;
- if (xdebug) eprint(p, 0, &val, &val);
- r = getlr(p, 'R');
- if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) {
- l = resc;
- l->in.type = INT;
- } else
- l = getlr(p, 'L');
- if(r->in.type==FLOAT || r->in.type==DOUBLE
- || l->in.type==FLOAT || l->in.type==DOUBLE)
- cerror("float in ZA");
- if (r->in.op == ICON)
- if(r->in.name[0] == '\0') {
- if (r->tn.lval == 0) {
- putstr("clr");
- prtype(l);
- putchar('\t');
- adrput(l);
- return;
- }
- if (r->tn.lval < 0 && r->tn.lval >= -63) {
- putstr("mneg");
- prtype(l);
- r->tn.lval = -r->tn.lval;
- goto ops;
- }
-#ifdef MOVAFASTER
- } else {
- putstr("movab\t");
- acon(r);
- putchar(',');
- adrput(l);
- return;
-#endif MOVAFASTER
- }
+ l = p->in.left;
+ r = p->in.right;
+ s = talloc();
+ rt = r->in.type;
+ lt = l->in.type;
+
+ if (lt != INT && lt != UNSIGNED) {
+ s->in.op = SCONV;
+ s->in.left = l;
+ s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
+ zzzcode(s, 'U');
+ putstr("\n\t");
+ }
- if (l->in.op == REG) {
- if( tlen(l) < tlen(r) ) {
- putstr(!ISUNSIGNED(l->in.type)?
- "cvt": "movz");
- prtype(l);
- putchar('l');
- goto ops;
- } else
- l->in.type = INT;
+ if (ISUNSIGNED(lt)) {
+ s->in.op = SCONV;
+ s->in.left = lt == UNSIGNED ? l : resc;
+ s->in.type = rt;
+ unsigned_to_float(s);
+ } else {
+ putstr("cvl");
+ prtype(r);
+ putchar('\t');
+ adrput(lt == INT ? l : resc);
}
- if (tlen(l) == tlen(r)) {
- putstr("mov");
- prtype(l);
- goto ops;
- } else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
- putstr("movz");
- else
- putstr("cvt");
- prtype(r);
- prtype(l);
- ops:
+ putstr("\n\t");
+
+ hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
putchar('\t');
adrput(r);
- putchar(',');
- adrput(l);
+
+ if (ISUNSIGNED(lt)) {
+ putstr("\n\t");
+ s->in.op = SCONV;
+ s->in.left = r; /* we need only the type */
+ s->in.type = UNSIGNED;
+ float_to_unsigned(s);
+ } else {
+ putstr("\n\tcv");
+ prtype(r);
+ putstr("l\t");
+ if (lt == INT)
+ adrput(l);
+ else
+ adrput(resc);
+ }
+ if (lt != INT) {
+ putstr("\n\t");
+ s->in.op = ASSIGN;
+ s->in.left = l;
+ s->in.right = resc;
+ s->in.type = lt;
+ zzzcode(s, 'U');
+ }
+
+ s->in.op = FREE;
+ return;
+ }
+
+ case 'J': /* unsigned DIV/MOD with constant divisors */
+ {
+ register int ck = INAREG;
+ int label1, label2;
+
+ /* case constant <= 1 is handled by optim() in pass 1 */
+ /* case constant < 0x80000000 is handled in table */
+ switch( p->in.op ) {
+ /* case DIV: handled in optim2() */
+ case MOD:
+ if( p->in.left->in.op == REG &&
+ p->in.left->tn.rval == resc->tn.rval )
+ goto asgmod;
+ label1 = getlab();
+ expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
+ printf("\tjlssu\tL%d\n", label1);
+ expand(p, ck, "\tsubl2\tAR,A1\n");
+ printf("L%d:", label1);
+ break;
+ case ASG DIV:
+ label1 = getlab();
+ label2 = getlab();
+ expand(p, ck, "cmpl\tAL,AR\n");
+ printf("\tjgequ\tL%d\n", label1);
+ expand(p, ck, "\tmovl\t$1,AL\n");
+ printf("\tjbr\tL%d\nL%d:\n", label2, label1);
+ expand(p, ck, "\tclrl\tAL\n");
+ printf("L%d:", label2);
+ break;
+ case ASG MOD:
+ asgmod:
+ label1 = getlab();
+ expand(p, ck, "cmpl\tAL,AR\n");
+ printf("\tjlssu\tL%d\n", label1);
+ expand(p, ck, "\tsubl2\tAR,AL\n");
+ printf("L%d:", label1);
+ break;
+ }
return;
}
register NODE *r;
if (xdebug) eprint(p, 0, &val, &val);
r = p->in.right;
- if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
+ if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
putstr("movl");
else {
putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
return;
}
- case 'C': /* num bytes pushed on arg stack */
+ case 'C': /* generate 'call[fs] $bytes' */
{
extern int gc_numbytes;
extern int xdebug;
printf("call%c $%d",
(p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
gc_numbytes+4);
- /* dont change to double (here's the only place to catch it) */
+ /* don't change to double (here's the only place to catch it) */
if(p->in.type == FLOAT)
rtyflg = 1;
return;
}
case 'D': /* INCR and DECR */
- zzzcode(p->in.left, 'A');
+ if (p->in.left->in.type == FLOAT)
+ expand(p, INAREG, "movl\tAL,A1");
+ else if (p->in.left->in.type == DOUBLE)
+ expand(p, INAREG, "ldd\tAL\n\tstd\tA1");
+ else
+ zzzcode(p->in.left, 'U');
putstr("\n ");
case 'E': /* INCR and DECR, FOREFF */
- if (p->in.right->tn.lval == 1)
+ if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
{
putstr(p->in.op == INCR ? "inc" : "dec");
prtype(p->in.left);
adrput(p->in.left);
return;
}
+ else if (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE) {
+ if (c == 'E' || p->in.left->in.type == FLOAT)
+ expand(p, INAREG, "ldZL\tAL\n\t");
+ if (p->in.op == INCR)
+ expand(p, INAREG, "addZL\tAR\n\tstZL\tAL");
+ else /* DECR */
+ expand(p, INAREG, "subZL\tAR\n\tstZL\tAL");
+ return;
+ }
putstr(p->in.op == INCR ? "add" : "sub");
prtype(p->in.left);
putstr("2 ");
printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
return;
+ case 'I': /* produce value of bitfield assignment */
+ /* avoid shifts -- shifts are SLOW on this machine */
+ /* XXX this wouldn't be necessary if we were smarter
+ and masked BEFORE shifting XXX */
+ {
+ register NODE *r = p->in.right;
+ if(r->in.op == ICON && r->tn.name[0] == '\0') {
+ putstr("movl\t");
+ printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
+ }
+ else {
+ putstr("andl3\t");
+ printf(ACONFMT, (1 << fldsz) - 1);
+ putchar(',');
+ adrput(r);
+ }
+ putchar(',');
+ adrput(resc);
+ break;
+ }
+
case 'H': /* opcode for shift */
if(p->in.op == LS || p->in.op == ASG LS)
putstr("shll");
}
case 'M': { /* initiate ediv for mod and unsigned div */
- register char *r;
- m = getlr(p, '1')->tn.rval;
- r = rname(m);
- printf("\tclrl\t%s\n\tmovl\t", r);
+ putstr("clrl\t");
+ adrput(resc);
+ putstr("\n\tmovl\t");
adrput(p->in.left);
- printf(",%s\n", rname(m+1));
- if(!ISUNSIGNED(p->in.type)) { /* should be MOD */
- m = getlab();
- printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
- deflab(m);
- }
+ putchar(',');
+ upput(resc, SZLONG);
+ printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
+ adrput(resc);
+ putchar('\n');
+ deflab(m);
return;
}
stasg(p);
break;
+#ifdef I_don_t_understand_this
case 'X': /* multiplication for short and char */
if (ISUNSIGNED(p->in.left->in.type))
printf("\tmovz");
adrput(&resc[1]);
printf("\n");
return;
+#endif
case 'U': /* SCONV */
case 'V': /* SCONV with FORCC */
sconv(p, c == 'V');
break;
+ case 'W': { /* SCONV or ASSIGN float/double => unsigned */
+ NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
+
+ putstr("ld");
+ prtype(src);
+ putchar('\t');
+ adrput(src);
+ putstr("\n\t");
+ float_to_unsigned(p);
+ break;
+ }
+
+ case 'Y': /* SCONV or ASSIGN unsigned => float/double */
+ unsigned_to_float(p); /* stores into accumulator */
+ putstr("\n\tst");
+ prtype(p);
+ putchar('\t');
+ if (p->in.op == SCONV)
+ adrput(resc);
+ else
+ adrput(p->in.left);
+ rtyflg = 1;
+ break;
+
+#ifdef I_don_t_understand_this
case 'Z':
p = p->in.right;
switch (p->in.type) {
}
printf("$%d", p->tn.lval);
break;
+#endif
default:
cerror( "illegal zzzcode" );
* Can we ever get a register conflict with R1 here?
*/
putstr("\tmovab\t");
- adrput(l);
- putstr(",r1\n\tmovab\t");
- adrput(r);
- printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
+ if(r->in.op == OREG && r->tn.rval == R1)
+ {
+ adrput(r);
+ printf(",r0\n\tmovab\t");
+ adrput(l);
+ putstr(",r1\n");
+ }
+ else
+ {
+ adrput(l);
+ putstr(",r1\n\tmovab\t");
+ adrput(r);
+ printf(",r0\n");
+ }
+ printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
rname(R2);
break;
}
}
/*
- * Output the address of the second item in the
- * pair pointed to by p.
+ * Convert a float or double in the accumulator into an unsigned int.
+ * Unlike the vax, the tahoe stores 0 into the destination
+ * on a conversion of > 2 ** 31, so we compensate.
*/
-upput(p, size)
- register NODE *p;
+float_to_unsigned(p)
+ NODE *p;
{
- CONSZ save;
-
- if (p->in.op == FLD)
- p = p->in.left;
- switch (p->in.op) {
+ register NODE *l = p->in.left;
+ int label1 = getlab();
+ int label2 = getlab();
+ int label3 = getlab();
+ NODE *src, *dst;
+
+ if (p->in.op == SCONV) {
+ src = p->in.left;
+ dst = resc;
+ } else {
+ src = p->in.right;
+ dst = p->in.left;
+ }
- case NAME:
- case OREG:
- save = p->tn.lval;
- p->tn.lval += size/SZCHAR;
- adrput(p);
- p->tn.lval = save;
- break;
+ printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
+ if (src->in.type == DOUBLE)
+ putstr(", 0x00000000 # .double");
+ else
+ putstr(" # .float");
+ putstr(" 2147483648\n\t.text\n\tcmp");
+ prtype(src);
+ printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
+ prtype(src);
+ printf("\tL%d\n\tcv", label1);
+ prtype(src);
+ putstr("l\t");
+ adrput(dst);
+ putstr("\n\taddl2\t$-2147483648,");
+ adrput(dst);
+ printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
+ prtype(src);
+ putstr("l\t");
+ adrput(dst);
+ printf("\nL%d:", label3);
+}
- case REG:
- if (size == SZLONG) {
- putstr(rname(p->tn.rval+1));
- break;
- }
- /* fall thru... */
+/*
+ * Convert an unsigned int into a float or double, leaving the result
+ * in the accumulator.
+ */
+unsigned_to_float(p)
+ register NODE *p;
+{
+ int label1 = getlab();
+ int label2 = getlab();
+ NODE *src, *dst;
- default:
- cerror("illegal upper address op %s size %d",
- opst[p->tn.op], size);
- /*NOTREACHED*/
+ if (p->in.op == SCONV) {
+ src = p->in.left;
+ dst = resc;
+ } else {
+ src = p->in.right;
+ dst = p->in.left;
}
+
+ printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
+ if (p->in.type == DOUBLE)
+ putstr(", 0x00000000 # .double");
+ else
+ putstr(" # .float");
+ putstr(" 4294967296\n\t.text\n\tmovl\t");
+ adrput(src);
+ putchar(',');
+ adrput(dst);
+ putstr("\n\tcvl");
+ prtype(p);
+ putchar('\t');
+ adrput(dst);
+ printf("\n\tjgeq\tL%d\n\tadd", label1);
+ prtype(p);
+ printf("\tL%d\nL%d:", label2, label1);
}
/*
- * Generate code for storage conversions.
+ * Prlen() is a cheap prtype()...
+ */
+static char convtab[SZINT/SZCHAR + 1] = {
+ '?', 'b', 'w', '?', 'l'
+};
+#define prlen(len) putchar(convtab[len])
+
+
+/*
+ * Generate code for integral scalar conversions.
+ * Some of this code is designed to work around a tahoe misfeature
+ * that causes sign- and zero- extension to be defeated in
+ * certain circumstances.
+ * Basically if the source operand of a CVT or MOVZ instruction is
+ * shorter than the destination, and the source is a register
+ * or an immediate constant, sign- and zero- extension are
+ * ignored and the high bits of the source are copied. (Note
+ * that zero-extension is not a problem for immediate
+ * constants.)
+ * Another problem -- condition codes for a conversion with a
+ * register source reflect the source rather than the destination.
*/
sconv(p, forcc)
NODE *p;
+ int forcc;
{
- register NODE *l, *r;
- register wfrom, wto;
- int oltype;
-
- l = getlr(p, '1');
- oltype = l->in.type, l->in.type = r->in.type;
- r = getlr(p, 'L');
- wfrom = tlen(r), wto = tlen(l);
- if (wfrom == wto) /* e.g. int -> unsigned */
- goto done;
- /*
- * Conversion in registers requires care
- * as cvt and movz instruction don't work
- * as expected (they end up as plain mov's).
- */
- if (l->in.op == REG && r->in.op == REG) {
- if ((wfrom < wto && ISUNSIGNED(r->in.type)) ||
- (wto < wfrom && ISUNSIGNED(l->in.type))) {
- /* unsigned, mask */
- if (r->tn.rval != l->tn.rval) {
- printf("\tandl3\t$%d,", (1<<(wto*SZCHAR))-1);
- adrput(r);
- putchar(',');
- } else
- printf("\tandl2\t$%d,", (1<<(wto*SZCHAR))-1);
- adrput(l);
- } else { /* effect sign-extend */
- printf("\tpushl\t"); adrput(r);
- printf("\n\tcvt"); prtype(l);
- printf("l\t%d(sp),", sizeof (int) - wto); adrput(l);
- printf("\n\tmovab\t4(sp),sp");
- }
- /*
- * If condition codes are required then we must generate a
- * test of the appropriate type.
- */
- if (forcc) {
- printf("\n\tcmp");
- prtype(l);
- putchar('\t');
- adrput(l);
- printf(",$0");
- }
+ register NODE *src, *dst;
+ register NODE *tmp;
+ register int srclen, dstlen;
+ int srctype, dsttype;
+ int val;
+ int neg = 0;
+
+ if (p->in.op == ASSIGN) {
+ src = p->in.right;
+ dst = p->in.left;
+ dstlen = tlen(dst);
+ dsttype = dst->in.type;
+ } else if (p->in.op == SCONV) {
+ src = p->in.left;
+ dst = resc;
+ dstlen = tlen(p);
+ dsttype = p->in.type;
+ } else /* if (p->in.op == OPLEAF) */ {
+ src = p;
+ dst = resc;
+ dstlen = SZINT/SZCHAR;
+ dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
+ }
+
+ if (src->in.op == REG) {
+ srclen = SZINT/SZCHAR;
+ srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
} else {
- /*
- * Conversion with at least one parameter in memory.
- */
- if (wfrom < wto) { /* expanding datum */
- if (ISUNSIGNED(r->in.type)) {
- printf("\tmovz");
- prtype(r);
- /*
- * If target is a register, generate
- * movz?l so optimizer can compress
- * argument pushes.
- */
- if (l->in.op == REG)
- putchar('l');
- else
- prtype(l);
- } else {
- printf("\tcvt");
- prtype(r), prtype(l);
- }
- putchar('\t');
- adrput(r);
- } else { /* shrinking dataum */
- int off = wfrom - wto;
- if (l->in.op == REG) {
- printf("\tmovz");
- prtype(l);
- putchar('l');
- } else {
- printf("\tcvt");
- prtype(l), prtype(r);
- }
+ srclen = tlen(src);
+ srctype = src->in.type;
+ }
+
+ if (src->in.op == ICON && src->tn.name[0] == '\0') {
+ if (src->tn.lval == 0) {
+ putstr("clr");
+ prtype(dst);
putchar('\t');
- switch (r->in.op) {
- case NAME: case OREG:
- r->tn.lval += off;
- adrput(r);
- r->tn.lval -= off;
+ adrput(dst);
+ return;
+ }
+ if (dstlen < srclen) {
+ switch (dsttype) {
+ case CHAR:
+ src->tn.lval = (char) src->tn.lval;
+ break;
+ case UCHAR:
+ src->tn.lval = (unsigned char) src->tn.lval;
+ break;
+ case SHORT:
+ src->tn.lval = (short) src->tn.lval;
break;
- case REG: case ICON: case UNARY MUL:
- adrput(r);
+ case USHORT:
+ src->tn.lval = (unsigned short) src->tn.lval;
break;
- default:
- cerror("sconv: bad shrink op");
- /*NOTREACHED*/
}
}
- putchar(',');
- adrput(l);
+ if (dst->in.op == REG) {
+ dsttype = INT;
+ dstlen = SZINT/SZCHAR;
+ }
+ srctype = dsttype;
+ srclen = dstlen;
+ val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
+ if ((unsigned) val < 64) {
+ src->tn.lval = val;
+ ++neg; /* MNEGx may be shorter */
+ }
+ }
+
+ if (srclen < dstlen) {
+ if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
+ /* (unsigned short) c; => sign extend to 16 bits */
+ putstr("cvtbl\t");
+ adrput(src);
+ putstr(",-(sp)\n\tmovzwl\t2(sp),");
+ adrput(dst);
+ putstr("\n\tmovab\t4(sp),sp");
+ if (forcc) {
+ putstr("\n\ttstl\t");
+ adrput(dst);
+ }
+ return;
+ }
+ genconv(ISUNSIGNED(srctype),
+ srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+ src, dst, forcc);
+ return;
}
- putchar('\n');
-done:
- l->in.type = oltype;
+
+ if (srclen > dstlen && dst->in.op == REG) {
+ /* if dst is a register, the result must look like an int */
+ if (src->in.op == REG) {
+ if (ISUNSIGNED(dsttype)) {
+ val = (1 << dstlen * SZCHAR) - 1;
+ if (src->tn.rval == dst->tn.rval)
+ /* conversion in place */
+ printf("andl2\t$%ld,", val);
+ else {
+ printf("andl3\t$%ld,", val);
+ adrput(src);
+ putchar(',');
+ }
+ adrput(dst);
+ return;
+ }
+ /*
+ * Sign extension in register can also be
+ * accomplished by shifts, but unfortunately
+ * shifts are extremely slow, due to the lack
+ * of a barrel shifter.
+ */
+ putstr("pushl\t");
+ adrput(src);
+ putstr("\n\tcvt");
+ prlen(dstlen);
+ printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
+ adrput(dst);
+ putstr("\n\tmovab\t4(sp),sp");
+ if (forcc) {
+ putstr("\n\ttstl\t");
+ adrput(dst);
+ }
+ return;
+ }
+ tmp = talloc();
+ if ((src->in.op == NAME) ||
+ (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
+ (src->in.op == OREG && !R2TEST(src->tn.rval))) {
+ /* we can increment src's address & pun it */
+ *tmp = *src;
+ tmp->tn.lval += srclen - dstlen;
+ } else {
+ /* we must store src's address */
+ *tmp = *dst;
+ putstr("mova");
+ prlen(srclen);
+ putchar('\t');
+ adrput(src);
+ putchar(',');
+ adrput(tmp);
+ putstr("\n\t");
+ tmp->tn.op = OREG;
+ tmp->tn.lval = srclen - dstlen;
+ }
+ genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
+ tmp->in.op = FREE;
+ return;
+ }
+
+ genconv(neg ? -1 : ISUNSIGNED(dsttype),
+ srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+ src, dst, forcc);
}
-rmove( rt, rs, t ) TWORD t;{
+genconv(srcflag, srclen, dstlen, src, dst, forcc)
+ int srcflag;
+ register int srclen, dstlen;
+ NODE *src, *dst;
+ int forcc;
+{
+ if (srclen != dstlen) {
+ if (srcflag > 0 && srclen < dstlen)
+ putstr("movz");
+ else
+ putstr("cvt");
+ prlen(srclen);
+ } else if (srcflag < 0)
+ putstr("mneg");
+ else
+ putstr("mov");
+ prlen(dstlen);
+ putchar('\t');
+ adrput(src);
+ putchar(',');
+ adrput(dst);
+
+ /*
+ * This hack is made necessary by architecture problems
+ * described above
+ */
+ if (forcc && src->in.op == REG && srclen > dstlen) {
+ putstr("\n\ttst");
+ prlen(dstlen);
+ putchar('\t');
+ adrput(dst);
+ }
+}
+
+rmove( rt, rs, t ) TWORD t; {
printf( " movl %s,%s\n", rname(rs), rname(rt) );
if(t==DOUBLE)
printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
}
#endif
+/*ARGSUSED*/
rewfld( p ) NODE *p; {
return(1);
}
+/*ARGSUSED*/
callreg(p) NODE *p; {
return( R0 );
}
base( p ) register NODE *p; {
register int o = p->in.op;
- if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
+ if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
if( o==REG ) return( p->tn.rval );
if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
return( p->in.left->tn.rval );
if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
return( p->tn.rval + 0200*1 );
+ if( o==NAME ) return( 100 + 0200*1 );
return( -1 );
}
offset( p, tyl ) register NODE *p; int tyl; {
- if(tyl > 8) return( -1 );
- if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
- if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
- (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
- && (1<<p->in.right->tn.lval)==tyl))
+ if( tyl==1 &&
+ p->in.op==REG &&
+ (p->in.type==INT || p->in.type==UNSIGNED) )
+ return( p->tn.rval );
+ if( p->in.op==LS &&
+ p->in.left->in.op==REG &&
+ (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
+ p->in.right->in.op==ICON &&
+ p->in.right->in.name[0]=='\0' &&
+ (1<<p->in.right->tn.lval)==tyl)
+ return( p->in.left->tn.rval );
+ if( tyl==2 &&
+ p->in.op==PLUS &&
+ (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
+ p->in.left->in.op==REG &&
+ p->in.right->in.op==REG &&
+ p->in.left->tn.rval==p->in.right->tn.rval )
return( p->in.left->tn.rval );
return( -1 );
}
makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
register NODE *t;
- register int i;
NODE *f;
p->in.op = OREG;
case ICON:
case REG:
case OREG:
+ case NAME:
t = q;
break;
p->tn.lval = t->tn.lval;
#ifndef FLEXNAMES
- for(i=0; i<NCHNAM; ++i)
- p->in.name[i] = t->in.name[i];
+ {
+ register int i;
+ for(i=0; i<NCHNAM; ++i)
+ p->in.name[i] = t->in.name[i];
+ }
#else
p->in.name = t->in.name;
#endif
return(0);
}
+/* INTEMP shapes must not contain any temporary registers */
shtemp( p ) register NODE *p; {
+ int r;
+
if( p->in.op == STARG ) p = p->in.left;
- return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
+
+ switch (p->in.op) {
+ case REG:
+ return( !istreg(p->tn.rval) );
+ case OREG:
+ r = p->tn.rval;
+ if( R2TEST(r) ) {
+ if( istreg(R2UPK1(r)) )
+ return(0);
+ r = R2UPK2(r);
+ }
+ return( !istreg(r) );
+ case UNARY MUL:
+ p = p->in.left;
+ return( p->in.op != UNARY MUL && shtemp(p) );
+ }
+
+ if( optype( p->in.op ) != LTYPE ) return(0);
+ return(1);
}
shumul( p ) register NODE *p; {
}
}
+/*ARGSUSED*/
insput( p ) NODE *p; {
cerror( "insput" );
}
+/*
+ * Output the address of the second item in the
+ * pair pointed to by p.
+ */
+upput(p, size)
+ register NODE *p;
+{
+ CONSZ save;
+
+ if (p->in.op == FLD)
+ p = p->in.left;
+ switch (p->in.op) {
+
+ case NAME:
+ case OREG:
+ save = p->tn.lval;
+ p->tn.lval += size/SZCHAR;
+ adrput(p);
+ p->tn.lval = save;
+ break;
+
+ case REG:
+ if (size == SZLONG) {
+ putstr(rname(p->tn.rval+1));
+ break;
+ }
+ /* fall thru... */
+
+ default:
+ cerror("illegal upper address op %s size %d",
+ opst[p->tn.op], size);
+ /*NOTREACHED*/
+ }
+}
+
adrput( p ) register NODE *p; {
register int r;
/* output an address, with offsets, from p */
acon( p ) register NODE *p; { /* print out a constant */
- if( p->in.name[0] == '\0' ){
+ if( p->in.name[0] == '\0' )
printf( CONFMT, p->tn.lval);
- return;
- } else {
+ else {
#ifndef FLEXNAMES
printf( "%.8s", p->in.name );
#else
- putstr(p->in.name);
+ putstr( p->in.name );
#endif
- if (p->tn.lval != 0) {
- putchar('+');
- printf(CONFMT, p->tn.lval);
+ if( p->tn.lval != 0 ) {
+ putchar( '+' );
+ printf( CONFMT, p->tn.lval );
+ }
}
}
- }
genscall( p, cookie ) register NODE *p; {
/* structure valued call */
int gc_numbytes;
/* tbl */
+/*ARGSUSED*/
gencall( p, cookie ) register NODE *p; {
/* generate the call given by p */
register NODE *p1, *ptemp;
};
/* tbl */
+/*ARGSUSED*/
cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
- if(o != 0 && (o < EQ || o > UGT ))
- cerror( "bad conditional branch: %s", opst[o] );
- printf( " j%s L%d\n",
- o == 0 ? "br" : ccbranches[o-EQ], lab );
+ if( o != 0 && ( o < EQ || o > UGT ) )
+ cerror( "bad conditional branch: %s", opst[o] );
+ printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
}
nextcook( p, cookie ) NODE *p; {
return( FORREW );
}
+/*ARGSUSED*/
lastchance( p, cook ) NODE *p; {
/* forget it! */
return(0);
}
optim2( p ) register NODE *p; {
-# ifdef ONEPASS
/* do local tree transformations and optimizations */
-# define RV(p) p->in.right->tn.lval
-# define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0)
- register int o, i;
+
+ int o;
+ int i, mask;
register NODE *l, *r;
- switch (o = p->in.op) {
+ switch( o = p->in.op ) {
- case DIV: case ASG DIV:
- case MOD: case ASG MOD:
- /*
- * Change unsigned mods and divs to
- * logicals (mul is done in mip & c2)
- */
- if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
- (i = ispow2(RV(p))) >= 0) {
- if (o == DIV || o == ASG DIV) {
- p->in.op = RS;
- RV(p) = i;
- } else {
- p->in.op = AND;
- RV(p)--;
+ case ASG PLUS:
+ case ASG MINUS:
+ case ASG MUL:
+ case ASG OR:
+ /* simple ASG OPSIMP -- reduce range of constant rhs */
+ l = p->in.left;
+ r = p->in.right;
+ if( tlen(l) < SZINT/SZCHAR &&
+ r->in.op==ICON && r->in.name[0]==0 ){
+ mask = (1 << tlen(l) * SZCHAR) - 1;
+ if( r->tn.lval & (mask & ~(mask >> 1)) )
+ r->tn.lval |= ~mask;
+ else
+ r->tn.lval &= mask;
}
- if (asgop(o))
- p->in.op = ASG p->in.op;
- }
- return;
+ break;
+
+ case AND:
+ case ASG AND:
+ r = p->in.right;
+ if( r->in.op==ICON && r->in.name[0]==0 ) {
+ /* check for degenerate operations */
+ l = p->in.left;
+ mask = (1 << tlen(l) * SZCHAR) - 1;
+ if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
+ i = r->tn.lval & mask;
+ if( i == mask ) {
+ /* redundant mask */
+ r->in.op = FREE;
+ ncopy(p, l);
+ l->in.op = FREE;
+ break;
+ }
+ else if( i == 0 )
+ /* all bits masked off */
+ goto zero;
+ r->tn.lval = i;
+ if( tlen(l) < SZINT/SZCHAR ){
+ /* sign extend */
+ if( r->tn.lval & (mask & ~(mask >> 1)) )
+ r->tn.lval |= ~mask;
+ else
+ r->tn.lval &= mask;
+ }
+ }
+ else if( r->tn.lval == mask &&
+ tlen(l) < SZINT/SZCHAR ) {
+ /* use movz instead of and */
+ r->in.op = SCONV;
+ r->in.left = l;
+ r->in.right = 0;
+ r->in.type = ENUNSIGN(l->in.type);
+ r->in.su = l->in.su > 1 ? l->in.su : 1;
+ ncopy(p, r);
+ p->in.left = r;
+ p->in.type = INT;
+ }
+ }
+ break;
case SCONV:
l = p->in.left;
- /* clobber conversions w/o side effects */
- if (!anyfloat(p, l) && l->in.op != PCONV &&
- tlen(p) == tlen(l)) {
- if (l->in.op != FLD)
- l->in.type = p->in.type;
- ncopy(p, l);
- l->in.op = FREE;
- }
- return;
+ if( p->in.type == FLOAT || p->in.type == DOUBLE ||
+ l->in.type == FLOAT || l->in.type == DOUBLE )
+ return;
+ if( l->in.op == PCONV )
+ return;
+ if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
+ l->in.type != INT && l->in.type != UNSIGNED )
+ return;
+
+ /* Only trust it to get it right if the size is the same */
+ if( tlen(p) != tlen(l) )
+ return;
+
+ /* clobber conversion */
+ if( l->in.op != FLD )
+ l->in.type = p->in.type;
+ ncopy( p, l );
+ l->in.op = FREE;
+
+ break;
case ASSIGN:
/*
- * Try to zap storage conversions of non-float items.
+ * Conversions are equivalent to assignments;
+ * when the two operations are combined,
+ * we can sometimes zap the conversion.
*/
r = p->in.right;
- if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
- int wdest, wconv, wsrc;
- wdest = tlen(p->in.left);
- wconv = tlen(r);
- /*
- * If size doesn't change across assignment or
- * conversion expands src before shrinking again
- * due to the assignment, delete conversion so
- * code generator can create optimal code.
- */
- if (wdest == wconv ||
- (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
+ l = p->in.left;
+ if ( r->in.op == SCONV &&
+ !mixtypes(l, r) &&
+ l->in.op != FLD &&
+ tlen(l) == tlen(r) ) {
p->in.right = r->in.left;
r->in.op = FREE;
}
+ break;
+
+ case ULE:
+ case ULT:
+ case UGE:
+ case UGT:
+ p->in.op -= (UGE-GE);
+ if( degenerate(p) )
+ break;
+ p->in.op += (UGE-GE);
+ break;
+
+ case EQ:
+ case NE:
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ if( p->in.left->in.op == SCONV &&
+ p->in.right->in.op == SCONV ) {
+ l = p->in.left;
+ r = p->in.right;
+ if( l->in.type == DOUBLE &&
+ l->in.left->in.type == FLOAT &&
+ r->in.left->in.type == FLOAT ) {
+ /* nuke the conversions */
+ p->in.left = l->in.left;
+ p->in.right = r->in.left;
+ l->in.op = FREE;
+ r->in.op = FREE;
+ }
+ /* more? */
+ }
+ (void) degenerate(p);
+ break;
+
+ case DIV:
+ if( p->in.right->in.op == ICON &&
+ p->in.right->tn.name[0] == '\0' &&
+ ISUNSIGNED(p->in.right->in.type) &&
+ (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
+ /* easy to do here, harder to do in zzzcode() */
+ p->in.op = UGE;
+ break;
+ }
+ case MOD:
+ case ASG DIV:
+ case ASG MOD:
+ /*
+ * optimize DIV and MOD
+ *
+ * basically we spot UCHAR and USHORT and try to do them
+ * as signed ints... this may need tuning for the tahoe.
+ */
+ if( degenerate(p) )
+ break;
+ l = p->in.left;
+ r = p->in.right;
+ if( !ISUNSIGNED(r->in.type) ||
+ tlen(l) >= SZINT/SZCHAR ||
+ !(tlen(r) < SZINT/SZCHAR ||
+ (r->in.op == ICON && r->tn.name[0] == '\0')) )
+ break;
+ if( r->in.op == ICON )
+ r->tn.type = INT;
+ else {
+ NODE *t = talloc();
+ t->in.left = r;
+ r = t;
+ r->in.op = SCONV;
+ r->in.type = INT;
+ r->in.right = 0;
+ p->in.right = r;
+ }
+ if( o == DIV || o == MOD ) {
+ NODE *t = talloc();
+ t->in.left = l;
+ l = t;
+ l->in.op = SCONV;
+ l->in.type = INT;
+ l->in.right = 0;
+ p->in.left = l;
+ }
+ /* handle asgops in table */
+ break;
+
+ case RS:
+ case ASG RS:
+ case LS:
+ case ASG LS:
+ /* pick up degenerate shifts */
+ l = p->in.left;
+ r = p->in.right;
+ if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
+ break;
+ i = r->tn.lval;
+ if( i < 0 )
+ /* front end 'fixes' this? */
+ if( o == LS || o == ASG LS )
+ o += (RS-LS);
+ else
+ o += (LS-RS);
+ if( (o == RS || o == ASG RS) &&
+ !ISUNSIGNED(l->in.type) )
+ /* can't optimize signed right shifts */
+ break;
+ if( o == LS ) {
+ if( i < SZINT )
+ break;
+ }
+ else {
+ if( i < tlen(l) * SZCHAR )
+ break;
+ }
+ zero:
+ if( !asgop( o ) )
+ if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
+ /* no side effects */
+ tfree(l);
+ ncopy(p, r);
+ r->in.op = FREE;
+ p->tn.lval = 0;
+ }
+ else {
+ p->in.op = COMOP;
+ r->tn.lval = 0;
+ }
+ else {
+ p->in.op = ASSIGN;
+ r->tn.lval = 0;
+ }
+ break;
}
- return;
}
-# endif
-}
+
+degenerate(p) register NODE *p; {
+ int o;
+ int result, i;
+ int lower, upper;
+ register NODE *l, *r;
+
+ /*
+ * try to keep degenerate comparisons with constants
+ * out of the table.
+ */
+ r = p->in.right;
+ l = p->in.left;
+ if( r->in.op != ICON ||
+ r->tn.name[0] != '\0' ||
+ tlen(l) >= tlen(r) )
+ return (0);
+ switch( l->in.type ) {
+ case CHAR:
+ lower = -(1 << SZCHAR - 1);
+ upper = (1 << SZCHAR - 1) - 1;
+ break;
+ case UCHAR:
+ lower = 0;
+ upper = (1 << SZCHAR) - 1;
+ break;
+ case SHORT:
+ lower = -(1 << SZSHORT - 1);
+ upper = (1 << SZSHORT - 1) - 1;
+ break;
+ case USHORT:
+ lower = 0;
+ upper = (1 << SZSHORT) - 1;
+ break;
+ default:
+ cerror("unsupported type in degenerate()");
+ }
+ i = r->tn.lval;
+ switch( o = p->in.op ) {
+ case DIV:
+ case ASG DIV:
+ case MOD:
+ case ASG MOD:
+ /* DIV and MOD work like EQ */
+ case EQ:
+ case NE:
+ if( lower == 0 && (unsigned) i > upper )
+ result = o == NE;
+ else if( i < lower || i > upper )
+ result = o == NE;
+ else
+ return (0);
+ break;
+ case LT:
+ case GE:
+ if( lower == 0 && (unsigned) i > upper )
+ result = o == LT;
+ else if( i <= lower )
+ result = o != LT;
+ else if( i > upper )
+ result = o == LT;
+ else
+ return (0);
+ break;
+ case LE:
+ case GT:
+ if( lower == 0 && (unsigned) i >= upper )
+ result = o == LE;
+ else if( i < lower )
+ result = o != LE;
+ else if( i >= upper )
+ result = o == LE;
+ else
+ return (0);
+ break;
+ default:
+ cerror("unknown op in degenerate()");
+ }
+
+ if( o == MOD || o == ASG MOD ) {
+ r->in.op = FREE;
+ ncopy(p, l);
+ l->in.op = FREE;
+ }
+ else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
+ /* no side effects */
+ tfree(l);
+ ncopy(p, r);
+ r->in.op = FREE;
+ p->tn.lval = result;
+ }
+ else {
+ if( o == ASG DIV )
+ p->in.op = ASSIGN;
+ else {
+ p->in.op = COMOP;
+ r->tn.type = INT;
+ }
+ r->tn.lval = result;
+ }
+ if( logop(o) )
+ p->in.type = INT;
+
+ return (1);
+ }
struct functbl {
int fop;
+ TWORD ftype;
char *func;
-} opfunc[] = {
- DIV, "udiv",
- ASG DIV, "udiv",
- 0
-};
+ } opfunc[] = {
+ DIV, TANY, "udiv",
+ MOD, TANY, "urem",
+ ASG DIV, TANY, "audiv",
+ ASG MOD, TANY, "aurem",
+ 0, 0, 0 };
hardops(p) register NODE *p; {
/* change hard to do operators into function calls. */
register NODE *q;
register struct functbl *f;
- register int o;
- register TWORD t, t1, t2;
+ register o;
+ NODE *old,*temp;
o = p->in.op;
+ if( ! (optype(o)==BITYPE &&
+ (ISUNSIGNED(p->in.left->in.type) ||
+ ISUNSIGNED(p->in.right->in.type))) )
+ return;
for( f=opfunc; f->fop; f++ ) {
if( o==f->fop ) goto convert;
- }
+ }
return;
convert:
- t = p->in.type;
- t1 = p->in.left->in.type;
- t2 = p->in.right->in.type;
-
- if (!((ISUNSIGNED(t1) && !(ISUNSIGNED(t2))) ||
- ( t2 == UNSIGNED))) return;
-
- /* need to rewrite tree for ASG OP */
- /* must change ASG OP to a simple OP */
+ if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
+ /* 'J' in zzzcode() -- assumes DIV or MOD operations */
+ /* save a subroutine call -- use at most 5 instructions */
+ return;
+ if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
+ /* optim2() will modify the op into an ordinary int op */
+ return;
if( asgop( o ) ) {
- q = talloc();
- q->in.op = NOASG ( o );
- q->in.rall = NOPREF;
- q->in.type = p->in.type;
- q->in.left = tcopy(p->in.left);
- q->in.right = p->in.right;
- p->in.op = ASSIGN;
- p->in.right = q;
- zappost(q->in.left); /* remove post-INCR(DECR) from new node */
- fixpre(q->in.left); /* change pre-INCR(DECR) to +/- */
- p = q;
+ old = NIL;
+ switch( p->in.left->in.op ){
+ case FLD:
+ q = p->in.left->in.left;
+ /*
+ * rewrite (lval.fld /= rval); as
+ * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
+ * else the compiler will evaluate lval twice.
+ */
+ if( q->in.op == UNARY MUL ){
+ /* first allocate a temp storage */
+ temp = talloc();
+ temp->in.op = OREG;
+ temp->tn.rval = TMPREG;
+ temp->tn.lval = BITOOR(freetemp(1));
+ temp->in.type = INCREF(p->in.type);
+#ifdef FLEXNAMES
+ temp->in.name = "";
+#else
+ temp->in.name[0] = '\0';
+#endif
+ old = q->in.left;
+ q->in.left = temp;
+ }
+ /* fall thru ... */
- }
- /* turn logicals to compare 0 */
- else if( logop( o ) ) {
- ncopy(q = talloc(), p);
- p->in.left = q;
- p->in.right = q = talloc();
- q->in.op = ICON;
- q->in.type = INT;
-#ifndef FLEXNAMES
- q->in.name[0] = '\0';
+ case REG:
+ case NAME:
+ case OREG:
+ /* change ASG OP to a simple OP */
+ q = talloc();
+ q->in.op = NOASG p->in.op;
+ q->in.rall = NOPREF;
+ q->in.type = p->in.type;
+ q->in.left = tcopy(p->in.left);
+ q->in.right = p->in.right;
+ p->in.op = ASSIGN;
+ p->in.right = q;
+ p = q;
+ f -= 2; /* Note: this depends on the table order */
+ /* on the right side only - replace *temp with
+ *(temp = &lval), build the assignment node */
+ if( old ){
+ temp = q->in.left->in.left; /* the "*" node */
+ q = talloc();
+ q->in.op = ASSIGN;
+ q->in.left = temp->in.left;
+ q->in.right = old;
+ q->in.type = old->in.type;
+#ifdef FLEXNAMES
+ q->in.name = "";
#else
- q->in.name = "";
+ q->in.name[0] = '\0';
#endif
- q->tn.lval = 0;
- q->tn.rval = 0;
- p = p->in.left;
- }
+ temp->in.left = q;
+ }
+ break;
- /* build comma op for args to function */
- t1 = p->in.left->in.type;
- t2 = 0;
- if ( optype(p->in.op) == BITYPE) {
- q = talloc();
- q->in.op = CM;
- q->in.rall = NOPREF;
- q->in.type = INT;
- q->in.left = p->in.left;
- q->in.right = p->in.right;
- t2 = p->in.right->in.type;
- } else
- q = p->in.left;
+ case UNARY MUL:
+ /* avoid doing side effects twice */
+ q = p->in.left;
+ p->in.left = q->in.left;
+ q->in.op = FREE;
+ break;
+ default:
+ cerror( "hardops: can't compute & LHS" );
+ }
+ }
+
+ /* build comma op for args to function */
+ q = talloc();
+ q->in.op = CM;
+ q->in.rall = NOPREF;
+ q->in.type = INT;
+ q->in.left = p->in.left;
+ q->in.right = p->in.right;
p->in.op = CALL;
p->in.right = q;
q->in.rall = NOPREF;
q->in.type = INCREF( FTN + p->in.type );
#ifndef FLEXNAMES
- strcpy( q->in.name, f->func );
+ strcpy( q->in.name, f->func );
#else
- q->in.name = f->func;
+ q->in.name = f->func;
#endif
q->tn.lval = 0;
q->tn.rval = 0;
if( ty != LTYPE ) fixpre( p->in.left );
}
+/*ARGSUSED*/
NODE * addroreg(l) NODE *l;
/* OREG was built in clocal()
* for an auto or formal parameter
*/
{
cerror("address of OREG taken");
+ /*NOTREACHED*/
}
# ifndef ONEPASS
myreader(p) register NODE *p; {
strip( p ); /* strip off operations with no side effects */
+ canon( p ); /* expands r-vals for fields */
walkf( p, hardops ); /* convert ops to function calls */
- canon( p ); /* expands r-vals for fileds */
walkf( p, optim2 );
}