utah rcsid 1.8 87/04/18 01:42:25: Extensive hacking to weed out bugs in
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
index 8abc83d..ad40cb0 100644 (file)
@@ -1,11 +1,12 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)local2.c   1.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)local2.c   1.17 (Berkeley) %G%";
 #endif
 
 # include "pass2.h"
 # include <ctype.h>
 
 # define putstr(s)     fputs((s), stdout)
 #endif
 
 # include "pass2.h"
 # include <ctype.h>
 
 # define putstr(s)     fputs((s), stdout)
+# define ISCHAR(p)     (p->in.type == UCHAR || p->in.type == CHAR)
 
 # ifdef FORT
 int ftlab1, ftlab2;
 
 # ifdef FORT
 int ftlab1, ftlab2;
@@ -131,6 +132,16 @@ tlen(p) NODE *p;
                }
 }
 
                }
 }
 
+anyfloat(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);
+}
+
 prtype(n) NODE *n;
 {
        switch (n->in.type)
 prtype(n) NODE *n;
 {
        switch (n->in.type)
@@ -185,70 +196,67 @@ zzzcode( p, c ) register NODE *p; {
                cbgen( p->in.op, p->bn.label, c );
                return;
 
                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('\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;
                }
 
                return;
                }
 
@@ -284,7 +292,7 @@ zzzcode( p, c ) register NODE *p; {
                }
 
        case 'D':       /* INCR and DECR */
                }
 
        case 'D':       /* INCR and DECR */
-               zzzcode(p->in.left, 'A');
+               zzzcode(p->in.left, 'U');
                putstr("\n      ");
 
        case 'E':       /* INCR and DECR, FOREFF */
                putstr("\n      ");
 
        case 'E':       /* INCR and DECR, FOREFF */
@@ -330,8 +338,7 @@ zzzcode( p, c ) register NODE *p; {
                return;
                }
 
                return;
                }
 
-       case 'M':  /* initiate ediv for mod and unsigned div */
-               {
+       case 'M': {  /* initiate ediv for mod and unsigned div */
                register char *r;
                m = getlr(p, '1')->tn.rval;
                r = rname(m);
                register char *r;
                m = getlr(p, '1')->tn.rval;
                r = rname(m);
@@ -343,51 +350,93 @@ zzzcode( p, c ) register NODE *p; {
                        printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
                        deflab(m);
                }
                        printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
                        deflab(m);
                }
-               }
                return;
                return;
+       }
 
 
-       case 'U':
-               /* Truncate int for type conversions:
-                   LONG|ULONG -> CHAR|UCHAR|SHORT|USHORT
-                   SHORT|USHORT -> CHAR|UCHAR
-                  increment offset to correct byte */
-               {
-               register NODE *p1;
-               int dif;
-
-               p1 = p->in.left;
-               switch( p1->in.op ){
-               case NAME:
-               case OREG:
-                       dif = tlen(p1)-tlen(p);
-                       p1->tn.lval += dif;
-                       adrput(p1);
-                       p1->tn.lval -= dif;
-                       return;
-               default:
-                       cerror( "Illegal ZU type conversion" );
-                       return;
-                       }
-               }
-
-       case 'T':       /* rounded structure length for arguments */
-               {
-               int size;
-
-               size = p->stn.stsize;
+       case 'T': {     /* rounded structure length for arguments */
+               int size = p->stn.stsize;
                SETOFF( size, 4);
                printf("movab   -%d(sp),sp", size);
                return;
                SETOFF( size, 4);
                printf("movab   -%d(sp),sp", size);
                return;
-               }
+       }
 
        case 'S':  /* structure assignment */
                stasg(p);
                break;
 
 
        case 'S':  /* structure assignment */
                stasg(p);
                break;
 
+       case 'X':       /* multiplication for short and char */
+               if (ISUNSIGNED(p->in.left->in.type)) 
+                       printf("\tmovz");
+               else
+                       printf("\tcvt");
+               zzzcode(p, 'L');
+               printf("l\t");
+               adrput(p->in.left);
+               printf(",");
+               adrput(&resc[0]);
+               printf("\n");
+               if (ISUNSIGNED(p->in.right->in.type)) 
+                       printf("\tmovz");
+               else
+                       printf("\tcvt");
+               zzzcode(p, 'R');
+               printf("l\t");
+               adrput(p->in.right);
+               printf(",");
+               adrput(&resc[1]);
+               printf("\n");
+               return;
+
+       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;
+
+       case 'Z':
+               p = p->in.right;
+               switch (p->in.type) {
+               case SHORT: {
+                       short w = p->tn.lval;
+                       p->tn.lval = w;
+                       break;
+               }
+               case CHAR: {
+                       char c = p->tn.lval;
+                       p->tn.lval = c;
+                       break;
+               }
+               }
+               printf("$%d", p->tn.lval);
+               break;
+
        default:
                cerror( "illegal zzzcode" );
        default:
                cerror( "illegal zzzcode" );
-               }
        }
        }
+}
 
 #define        MOVB(dst, src, off) { \
        putstr("\tmovb\t"); upput(src, off); putchar(','); \
 
 #define        MOVB(dst, src, off) { \
        putstr("\tmovb\t"); upput(src, off); putchar(','); \
@@ -551,6 +600,283 @@ upput(p, size)
        }
 }
 
        }
 }
 
+/*
+ * 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.
+ */
+float_to_unsigned(p)
+       NODE *p;
+{
+       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;
+       }
+
+       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);
+}
+
+/*
+ * 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;
+
+       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);
+}
+
+/*
+ * 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.)
+ */
+sconv(p, forcc)
+       NODE *p;
+       int forcc;
+{
+       register NODE *src, *dst;
+       register NODE *tmp;
+       register int srclen, dstlen;
+       int srctype, dsttype;
+       int val;
+
+       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 {
+               srclen = tlen(src);
+               srctype = src->in.type;
+       }
+
+       if (src->in.op == ICON) {
+               if (src->tn.lval == 0) {
+                       putstr("clr");
+                       prtype(dst);
+                       putchar('\t');
+                       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 USHORT:
+                               src->tn.lval = (unsigned short) src->tn.lval;
+                               break;
+                       }
+               }
+               if (dst->in.op == REG) {
+                       dsttype = INT;
+                       dstlen = SZINT/SZCHAR;
+               }
+               srctype = dsttype;
+               srclen = dstlen;
+       }
+
+       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) {
+                               /* inverted test */
+                               putstr("\n\tcmpl\t$0,");
+                               adrput(dst);
+                       }
+                       return;
+               }
+               genconv(ISUNSIGNED(srctype),
+                       srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+                       src, dst);
+               return;
+       }
+
+       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$%#x,", val);
+                               else {
+                                       printf("andl3\t$%#x,", 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) {
+                               /* inverted test */
+                               putstr("\n\tcmpl\t$0,");
+                               adrput(dst);
+                       }
+                       return;
+               }
+               tmp = talloc();
+               if ((src->in.op == UNARY MUL &&
+                   ((src->in.left->in.op == NAME ||
+                    (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);
+               tmp->in.op = FREE;
+               return;
+       }
+
+       genconv(ISUNSIGNED(dsttype),
+               srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+               src, dst);
+}
+
+genconv(usrc, srclen, dstlen, src, dst)
+       int usrc;
+       register int srclen, dstlen;
+       NODE *src, *dst;
+{
+       if (srclen != dstlen) {
+               if (usrc && srclen < dstlen)
+                       putstr("movz");
+               else
+                       putstr("cvt");
+               prlen(srclen);
+       } else
+               putstr("mov");
+       prlen(dstlen);
+       putchar('\t');
+       adrput(src);
+       putchar(',');
+       adrput(dst);
+}
+
 rmove( rt, rs, t ) TWORD t;{
        printf( "       movl    %s,%s\n", rname(rs), rname(rt) );
        if(t==DOUBLE)
 rmove( rt, rs, t ) TWORD t;{
        printf( "       movl    %s,%s\n", rname(rs), rname(rt) );
        if(t==DOUBLE)
@@ -943,108 +1269,203 @@ optim2( p ) register NODE *p; {
        /* 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)
        /* 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 = p->in.op;
-       register int i;
+       register int o, i;
+       register NODE *l, *r;
 
 
-       /* change unsigned mods and divs to logicals (mul is done in mip & c2) */
-       if(optype(o) == BITYPE && ISUNSIGNED(p->in.left->in.type)
-        && nncon(p->in.right) && (i=ispow2(RV(p)))>=0){
-               switch(o) {
-               case DIV:
-               case ASG DIV:
-                       p->in.op = RS;
-                       RV(p) = i;
-                       break;
-               case MOD:
-               case ASG MOD:
-                       p->in.op = AND;
-                       RV(p)--;
-                       break;
-               default:
-                       return;
+       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)--;
+                       }
+                       if (asgop(o))
+                               p->in.op = ASG p->in.op;
                }
                }
-               if(asgop(o))
-                       p->in.op = ASG p->in.op;
+               return;
+
+       case SCONV:
+               l = p->in.left;
+               if (anyfloat(p, l)) {
+                       /* save some labor later */
+                       NODE *t = talloc();
+
+                       if (p->in.type == UCHAR || p->in.type == USHORT) {
+                               *t = *p;
+                               t->in.type = UNSIGNED;
+                               p->in.left = t;
+                       } else if (l->in.type == UCHAR || l->in.type == USHORT) {
+                               *t = *p;
+                               t->in.type = INT;
+                               p->in.left = t;
+                       }
+               } else if (l->in.op != PCONV &&
+                   l->in.op != CALL && l->in.op != UNARY CALL &&
+                   tlen(p) == tlen(l)) {
+                       /* clobber conversions w/o side effects */
+                       if (l->in.op != FLD)
+                               l->in.type = p->in.type;
+                       ncopy(p, l);
+                       l->in.op = FREE;
+               }
+               return;
+
+       case ASSIGN:
+               /*
+                * Try to zap storage conversions of non-float items.
+                */
+               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)) {
+                               p->in.right = r->in.left;
+                               r->in.op = FREE;
+                       }
+               } else if (p->in.left->in.type == UNSIGNED && 
+                          r->in.type == UNSIGNED) {
+                       /* let the code table handle it */
+                       p->in.right = r->in.left;
+                       r->in.op = FREE;
+               } else if ((p->in.left->in.type == FLOAT ||
+                           p->in.left->in.type == DOUBLE) &&
+                          p->in.left->in.type == r->in.type &&
+                          r->in.left->in.type == UNSIGNED) {
+                       /* let the code table handle it */
+                       p->in.right = r->in.left;
+                       r->in.op = FREE;
+               }
+               return;
        }
 # endif
 }
 
 struct functbl {
        int fop;
        }
 # endif
 }
 
 struct functbl {
        int fop;
+       TWORD ftype;
        char *func;
        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;
 
 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;
 
        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;
 
        for( f=opfunc; f->fop; f++ ) {
                if( o==f->fop ) goto convert;
-       }
+               }
        return;
 
        convert:
        return;
 
        convert:
-       t = p->in.type;
-       t1 = p->in.left->in.type;
-       t2 = p->in.right->in.type;
-       if ( t1 != UNSIGNED && (t2 != UNSIGNED)) return;
-
-       /* need to rewrite tree for ASG OP */
-       /* must change ASG OP to a simple OP */
        if( asgop( o ) ) {
        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
 #else
-               q->in.name = "";
+                               q->in.name[0] = '\0';
 #endif
 #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;
 
        p->in.op = CALL;
        p->in.right = q;
 
@@ -1054,9 +1475,9 @@ hardops(p)  register NODE *p; {
        q->in.rall = NOPREF;
        q->in.type = INCREF( FTN + p->in.type );
 #ifndef FLEXNAMES
        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
 #else
-               q->in.name = f->func;
+       q->in.name = f->func;
 #endif
        q->tn.lval = 0;
        q->tn.rval = 0;
 #endif
        q->tn.lval = 0;
        q->tn.rval = 0;
@@ -1125,7 +1546,26 @@ main( argc, argv ) char *argv[]; {
        }
 # endif
 
        }
 # endif
 
+strip(p) register NODE *p; {
+       NODE *q;
+
+       /* strip nodes off the top when no side effects occur */
+       for( ; ; ) {
+               switch( p->in.op ) {
+               case SCONV:                     /* remove lint tidbits */
+                       q = p->in.left;
+                       ncopy( p, q );
+                       q->in.op = FREE;
+                       break;
+               /* could probably add a few more here */
+               default:
+                       return;
+                       }
+               }
+       }
+
 myreader(p) register NODE *p; {
 myreader(p) register NODE *p; {
+       strip( p );             /* strip off operations with no side effects */
        walkf( p, hardops );    /* convert ops to function calls */
        canon( p );             /* expands r-vals for fileds */
        walkf( p, optim2 );
        walkf( p, hardops );    /* convert ops to function calls */
        canon( p );             /* expands r-vals for fileds */
        walkf( p, optim2 );