X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/344c124651b2c38250cb87e9aee82ca1dbd0b7a3..ad7871609881e73855d0b04da49b486cd93efca7:/usr/src/old/pcc/ccom.tahoe/local2.c diff --git a/usr/src/old/pcc/ccom.tahoe/local2.c b/usr/src/old/pcc/ccom.tahoe/local2.c index e5e57ed399..158d04e4e6 100644 --- a/usr/src/old/pcc/ccom.tahoe/local2.c +++ b/usr/src/old/pcc/ccom.tahoe/local2.c @@ -1,5 +1,5 @@ #ifndef lint -static char sccsid[] = "@(#)local2.c 1.9 (Berkeley) %G%"; +static char sccsid[] = "@(#)local2.c 1.32 (Berkeley) 2/29/88"; #endif # include "pass2.h" @@ -16,6 +16,7 @@ int ftlab1, ftlab2; # define BITMASK(n) ((1L< 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; @@ -102,7 +103,8 @@ rname(r) register int r; { - ent_mask |= 1<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; @@ -155,6 +158,8 @@ prtype(n) NODE *n; putchar('f'); return; + case LONG: + case ULONG: case INT: case UNSIGNED: putchar('l'); @@ -196,70 +201,108 @@ zzzcode( p, c ) register NODE *p; { 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; } @@ -268,7 +311,7 @@ zzzcode( p, c ) register NODE *p; { 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"); @@ -278,7 +321,7 @@ zzzcode( p, c ) register NODE *p; { return; } - case 'C': /* num bytes pushed on arg stack */ + case 'C': /* generate 'call[fs] $bytes' */ { extern int gc_numbytes; extern int xdebug; @@ -288,18 +331,23 @@ zzzcode( p, c ) register NODE *p; { 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); @@ -307,6 +355,15 @@ zzzcode( p, c ) register NODE *p; { 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 "); @@ -319,6 +376,27 @@ zzzcode( p, c ) register NODE *p; { printf(ACONFMT, (p->in.right->tn.lval&((1<in.right; + if(r->in.op == ICON && r->tn.name[0] == '\0') { + putstr("movl\t"); + printf(ACONFMT, r->tn.lval & ((1<in.op == LS || p->in.op == ASG LS) putstr("shll"); @@ -342,17 +420,16 @@ zzzcode( p, c ) register NODE *p; { } 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; } @@ -367,6 +444,7 @@ zzzcode( p, c ) register NODE *p; { 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"); @@ -389,12 +467,38 @@ zzzcode( p, c ) register NODE *p; { 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) { @@ -411,6 +515,7 @@ zzzcode( p, c ) register NODE *p; { } printf("$%d", p->tn.lval); break; +#endif default: cerror( "illegal zzzcode" ); @@ -528,10 +633,21 @@ stasg(p) * 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; } @@ -545,146 +661,302 @@ stasg(p) } /* - * 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'); - printf("$0,"); - adrput(l); - } + 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) ); @@ -709,10 +981,12 @@ szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ } #endif +/*ARGSUSED*/ rewfld( p ) NODE *p; { return(1); } +/*ARGSUSED*/ callreg(p) NODE *p; { return( R0 ); } @@ -720,29 +994,41 @@ callreg(p) NODE *p; { 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<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<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; @@ -753,6 +1039,7 @@ makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { case ICON: case REG: case OREG: + case NAME: t = q; break; @@ -772,8 +1059,11 @@ makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { p->tn.lval = t->tn.lval; #ifndef FLEXNAMES - for(i=0; iin.name[i] = t->in.name[i]; + { + register int i; + for(i=0; iin.name[i] = t->in.name[i]; + } #else p->in.name = t->in.name; #endif @@ -805,9 +1095,30 @@ flshape( p ) NODE *p; { 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; { @@ -852,10 +1163,46 @@ conput( 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 */ @@ -921,21 +1268,20 @@ adrput( p ) register NODE *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 */ @@ -977,6 +1323,7 @@ genfcall( p, cookie ) register NODE *p; { int gc_numbytes; /* tbl */ +/*ARGSUSED*/ gencall( p, cookie ) register NODE *p; { /* generate the call given by p */ register NODE *p1, *ptemp; @@ -1050,12 +1397,12 @@ ccbranches[] = { }; /* 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; { @@ -1066,157 +1413,474 @@ 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; @@ -1226,9 +1890,9 @@ hardops(p) register NODE *p; { 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; @@ -1279,6 +1943,7 @@ fixpre(p) NODE *p; { if( ty != LTYPE ) fixpre( p->in.left ); } +/*ARGSUSED*/ NODE * addroreg(l) NODE *l; /* OREG was built in clocal() * for an auto or formal parameter @@ -1289,6 +1954,7 @@ NODE * addroreg(l) NODE *l; */ { cerror("address of OREG taken"); + /*NOTREACHED*/ } # ifndef ONEPASS @@ -1317,7 +1983,7 @@ strip(p) register NODE *p; { 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 ); }