utah rcsid 1.25 87/07/07 20:30:32: Permit the ZE code for INCR/DECR in
[unix-history] / usr / src / old / pcc / ccom.vax / local2.c
index d9b7afb..96dc187 100644 (file)
@@ -1,13 +1,19 @@
-static char *sccsid ="@(#)local2.c     1.6 (Berkeley) %G%";
-# include "mfile2"
+# ifndef lint
+static char *sccsid ="@(#)local2.c     1.28 (Berkeley) %G%";
+# endif
+
+# include "pass2.h"
 # include "ctype.h"
 # ifdef FORT
 int ftlab1, ftlab2;
 # endif
 /* a lot of the machine dependent parts of the second pass */
 
 # include "ctype.h"
 # ifdef FORT
 int ftlab1, ftlab2;
 # endif
 /* a lot of the machine dependent parts of the second pass */
 
+# define putstr(s)     fputs((s), stdout)
+
 # define BITMASK(n) ((1L<<n)-1)
 
 # define BITMASK(n) ((1L<<n)-1)
 
+/*ARGSUSED*/
 where(c){
        fprintf( stderr, "%s, line %d: ", filename, lineno );
        }
 where(c){
        fprintf( stderr, "%s, line %d: ", filename, lineno );
        }
@@ -74,10 +80,10 @@ hopcode( f, o ){
 
        for( q = ioptab;  q->opmask>=0; ++q ){
                if( q->opmask == o ){
 
        for( q = ioptab;  q->opmask>=0; ++q ){
                if( q->opmask == o ){
-                       printf( "%s", q->opstring );
+                       putstr( q->opstring );
 /* tbl
 /* tbl
-                       if( f == 'F' ) printf( "e" );
-                       else if( f == 'D' ) printf( "d" );
+                       if( f == 'F' ) putchar( 'e' );
+                       else if( f == 'D' ) putchar( 'd' );
    tbl */
 /* tbl */
                        switch( f ) {
    tbl */
 /* tbl */
                        switch( f ) {
@@ -86,7 +92,7 @@ hopcode( f, o ){
                                case 'B':
                                case 'D':
                                case 'F':
                                case 'B':
                                case 'D':
                                case 'F':
-                                       printf("%c", tolower(f));
+                                       putchar(tolower(f));
                                        break;
 
                                }
                                        break;
 
                                }
@@ -150,34 +156,34 @@ prtype(n) NODE *n;
        switch (n->in.type)
                {
                case DOUBLE:
        switch (n->in.type)
                {
                case DOUBLE:
-                       printf("d");
+                       putchar('d');
                        return;
 
                case FLOAT:
                        return;
 
                case FLOAT:
-                       printf("f");
+                       putchar('f');
                        return;
 
                case LONG:
                case ULONG:
                case INT:
                case UNSIGNED:
                        return;
 
                case LONG:
                case ULONG:
                case INT:
                case UNSIGNED:
-                       printf("l");
+                       putchar('l');
                        return;
 
                case SHORT:
                case USHORT:
                        return;
 
                case SHORT:
                case USHORT:
-                       printf("w");
+                       putchar('w');
                        return;
 
                case CHAR:
                case UCHAR:
                        return;
 
                case CHAR:
                case UCHAR:
-                       printf("b");
+                       putchar('b');
                        return;
 
                default:
                        if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
                        else {
                        return;
 
                default:
                        if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
                        else {
-                               printf("l");
+                               putchar('l');
                                return;
                                }
                }
                                return;
                                }
                }
@@ -185,7 +191,7 @@ prtype(n) NODE *n;
 
 zzzcode( p, c ) register NODE *p; {
        register m;
 
 zzzcode( p, c ) register NODE *p; {
        register m;
-       CONSZ val;
+       int val;
        switch( c ){
 
        case 'N':  /* logical ops, turned into 0-1 */
        switch( c ){
 
        case 'N':  /* logical ops, turned into 0-1 */
@@ -211,7 +217,7 @@ zzzcode( p, c ) register NODE *p; {
                        l = getlr(p, 'L');
                else if (p->in.op == SCONV) {
                        l = resc;
                        l = getlr(p, 'L');
                else if (p->in.op == SCONV) {
                        l = resc;
-#ifdef FORT
+#if defined(FORT) || defined(SPRECC)
                        l->in.type = r->in.type;
 #else
                        l->in.type = r->in.type==FLOAT ? DOUBLE : r->in.type;
                        l->in.type = r->in.type;
 #else
                        l->in.type = r->in.type==FLOAT ? DOUBLE : r->in.type;
@@ -220,7 +226,7 @@ zzzcode( p, c ) register NODE *p; {
                        }
                else {          /* OPLTYPE */
                        l = resc;
                        }
                else {          /* OPLTYPE */
                        l = resc;
-#ifdef FORT
+#if defined(FORT) || defined(SPRECC)
                        l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT);
 #else
                        l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT);
                        l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT);
 #else
                        l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT);
@@ -229,14 +235,14 @@ zzzcode( p, c ) register NODE *p; {
                if (r->in.op == ICON)
                        if (r->in.name[0] == '\0') {
                                if (r->tn.lval == 0) {
                if (r->in.op == ICON)
                        if (r->in.name[0] == '\0') {
                                if (r->tn.lval == 0) {
-                                       printf("clr");
+                                       putstr("clr");
                                        prtype(l);
                                        prtype(l);
-                                       printf("        ");
+                                       putchar('\t');
                                        adrput(l);
                                        return;
                                        }
                                if (r->tn.lval < 0 && r->tn.lval >= -63) {
                                        adrput(l);
                                        return;
                                        }
                                if (r->tn.lval < 0 && r->tn.lval >= -63) {
-                                       printf("mneg");
+                                       putstr("mneg");
                                        prtype(l);
                                        r->tn.lval = -r->tn.lval;
                                        goto ops;
                                        prtype(l);
                                        r->tn.lval = -r->tn.lval;
                                        goto ops;
@@ -260,61 +266,206 @@ zzzcode( p, c ) register NODE *p; {
                                                : INT))));
                                }
                        else {
                                                : INT))));
                                }
                        else {
-                               printf("moval");
-                               printf("        ");
+                               putstr("moval");
+                               putchar('\t');
                                acon(r);
                                acon(r);
-                               printf(",");
+                               putchar(',');
                                adrput(l);
                                return;
                                }
 
                                adrput(l);
                                return;
                                }
 
-               if (l->in.op == REG && l->in.type != FLOAT && l->in.type != DOUBLE) {
-                       if (tlen(l) < tlen(r) && !mixtypes(l,r)) {
-                               if (ISUNSIGNED(l->in.type))
-                                       printf("movz");
+               if (p->in.op == SCONV &&
+                   !(l->in.type == FLOAT || l->in.type == DOUBLE) &&
+                   !mixtypes(l, r)) {
+                       /*
+                        * Because registers must always contain objects
+                        * of the same width as INTs, we may have to
+                        * perform two conversions to get an INT.  Can
+                        * the conversions be collapsed into one?
+                        */
+                       if (m = collapsible(l, r))
+                               r->in.type = m;
+                       else {
+                               /*
+                                * Two steps are required.
+                                */
+                               NODE *x = &resc[1];
+
+                               *x = *l;
+                               if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type))
+                                       putstr("movz");
                                else
                                else
-                                       printf("cvt");
-                               prtype(l);
-                               printf("l");
-                               goto ops;
+                                       putstr("cvt");
+                               prtype(r);
+                               prtype(x);
+                               putchar('\t');
+                               adrput(r);
+                               putchar(',');
+                               adrput(x);
+                               putchar('\n');
+                               putchar('\t');
+                               r = x;
                                }
                                }
-                       else
-                               l->in.type = INT;
+                       l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT);
+                       }
+
+               if ((r->in.type == UNSIGNED || r->in.type == ULONG) &&
+                   mixtypes(l, r)) {
+                       int label1, label2;
+
+                       label1 = getlab();
+                       label2 = getlab();
+
+                       putstr("movl\t");
+                       adrput(r);
+                       putchar(',');
+                       adrput(l);
+                       putstr("\n\tjbsc\t$31,");
+                       adrput(l);
+                       printf(",L%d\n\tcvtl", label1);
+                       prtype(l);
+                       putchar('\t');
+                       adrput(l);
+                       putchar(',');
+                       adrput(l);
+                       printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1);
+                       prtype(l);
+                       putchar('\t');
+                       adrput(l);
+                       putchar(',');
+                       adrput(l);
+                       putstr("\n\tadd");
+                       prtype(l);
+                       putstr("2\t$0");
+                       prtype(l);
+                       putstr("2.147483648e9,");
+                       adrput(l);
+                       printf("\nL%d:", label2);
+
+                       return;
                        }
                        }
+
                if (!mixtypes(l,r)) {
                        if (tlen(l) == tlen(r)) {
                if (!mixtypes(l,r)) {
                        if (tlen(l) == tlen(r)) {
-                               printf("mov");
+                               putstr("mov");
+#ifdef FORT
+                               if (Oflag)
+                                       prtype(l);
+                               else {
+                                       if (l->in.type == DOUBLE)
+                                               putchar('q');
+                                       else if(l->in.type == FLOAT)
+                                               putchar('l');
+                                       else
+                                               prtype(l);
+                                       }
+#else
                                prtype(l);
                                prtype(l);
+#endif FORT
                                goto ops;
                                }
                        else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
                                goto ops;
                                }
                        else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
-                               printf("movz");
+                               putstr("movz");
                        else
                        else
-                               printf("cvt");
+                               putstr("cvt");
                        }
                else
                        }
                else
-                       printf("cvt");
+                       putstr("cvt");
                prtype(r);
                prtype(l);
        ops:
                prtype(r);
                prtype(l);
        ops:
-               printf("        ");
+               putchar('\t');
                adrput(r);
                adrput(r);
-               printf(",");
+               putchar(',');
                adrput(l);
                return;
                }
 
                adrput(l);
                return;
                }
 
+       case 'G':       /* i *= f; asgops with int lhs and float rhs */
+               {
+               register NODE *l, *r, *s;
+               int rt;
+
+               l = p->in.left;
+               r = p->in.right;
+               s = talloc();
+               rt = r->in.type;
+
+               s->in.op = SCONV;
+               s->in.left = l;
+               s->in.type = rt;
+               zzzcode(s, 'A');
+               putstr("\n\t");
+
+               hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
+               putstr("2\t");
+               adrput(r);
+               putchar(',');
+               adrput(resc);
+               putstr("\n\t");
+
+               s->in.op = ASSIGN;
+               s->in.left = l;
+               s->in.right = resc;
+               s->in.type = l->in.type;
+               zzzcode(s, 'A');
+
+               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 hardops() */
+               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;
+               }
+
        case 'B':       /* get oreg value in temp register for left shift */
                {
                register NODE *r;
                if (xdebug) eprint(p, 0, &val, &val);
                r = p->in.right;
                if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
        case 'B':       /* get oreg value in temp register for left shift */
                {
                register NODE *r;
                if (xdebug) eprint(p, 0, &val, &val);
                r = p->in.right;
                if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
-                       printf("movl");
+                       putstr("movl");
                else {
                else {
-                       printf("cvt");
+                       putstr("cvt");
                        prtype(r);
                        prtype(r);
-                       printf("l");
+                       putchar('l');
                        }
                return;
                }
                        }
                return;
                }
@@ -332,22 +483,24 @@ zzzcode( p, c ) register NODE *p; {
 
        case 'D':       /* INCR and DECR */
                zzzcode(p->in.left, 'A');
 
        case 'D':       /* INCR and DECR */
                zzzcode(p->in.left, 'A');
-               printf("\n      ");
+               putchar('\n');
+               putchar('\t');
 
        case 'E':       /* INCR and DECR, FOREFF */
 
        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)
                        {
                        {
-                       printf("%s", (p->in.op == INCR ? "inc" : "dec") );
+                       putstr( p->in.op == INCR ? "inc" : "dec" );
                        prtype(p->in.left);
                        prtype(p->in.left);
-                       printf("        ");
+                       putchar('\t');
                        adrput(p->in.left);
                        return;
                        }
                        adrput(p->in.left);
                        return;
                        }
-               printf("%s", (p->in.op == INCR ? "add" : "sub") );
+               putstr( p->in.op == INCR ? "add" : "sub" );
                prtype(p->in.left);
                prtype(p->in.left);
-               printf("2       ");
+               putchar('2');
+               putchar('\t');
                adrput(p->in.right);
                adrput(p->in.right);
-               printf(",");
+               putchar(',');
                adrput(p->in.left);
                return;
 
                adrput(p->in.left);
                return;
 
@@ -362,9 +515,9 @@ zzzcode( p, c ) register NODE *p; {
 
                if (xdebug) printf("->%d<-", ty);
 
 
                if (xdebug) printf("->%d<-", ty);
 
-               if ( ty==DOUBLE) printf("d");
-               else if ( ty==FLOAT ) printf("f");
-               else printf("l");
+               if ( ty==DOUBLE) putchar('d');
+               else if ( ty==FLOAT ) putchar('f');
+               else putchar('l');
                return;
                }
 
                return;
                }
 
@@ -425,16 +578,16 @@ zzzcode( p, c ) register NODE *p; {
 
                        switch(size) {
                                case 1:
 
                        switch(size) {
                                case 1:
-                                       printf("        movb    ");
+                                       putstr("        movb    ");
                                        break;
                                case 2:
                                        break;
                                case 2:
-                                       printf("        movw    ");
+                                       putstr("        movw    ");
                                        break;
                                case 4:
                                        break;
                                case 4:
-                                       printf("        movl    ");
+                                       putstr("        movl    ");
                                        break;
                                case 8:
                                        break;
                                case 8:
-                                       printf("        movq    ");
+                                       putstr("        movq    ");
                                        break;
                                default:
                                        printf("        movc3   $%d,", size);
                                        break;
                                default:
                                        printf("        movc3   $%d,", size);
@@ -442,12 +595,12 @@ zzzcode( p, c ) register NODE *p; {
                        }
                        adrput(r);
                        if( p->in.op == STASG ){
                        }
                        adrput(r);
                        if( p->in.op == STASG ){
-                               printf(",");
+                               putchar(',');
                                adrput(l);
                                adrput(l);
-                               printf("\n");
+                               putchar('\n');
                                }
                        else
                                }
                        else
-                               printf(",(sp)\n");
+                               putstr(",(sp)\n");
 
                        if( r->in.op == NAME ) r->in.op = ICON;
                        else if( r->in.op == OREG ) r->in.op = REG;
 
                        if( r->in.op == NAME ) r->in.op = ICON;
                        else if( r->in.op == OREG ) r->in.op = REG;
@@ -460,8 +613,55 @@ zzzcode( p, c ) register NODE *p; {
                }
        }
 
                }
        }
 
-rmove( rt, rs, t ){
+/*
+ * collapsible(dest, src) -- if a conversion with a register destination
+ *     can be accomplished in one instruction, return the type of src
+ *     that will do the job correctly; otherwise return 0.  Note that
+ *     a register must always end up having type INT or UNSIGNED.
+ */
+int
+collapsible(dest, src)
+NODE *dest, *src;
+{
+       int st = src->in.type;
+       int dt = dest->in.type;
+       int newt = 0;
+
+       /*
+        * Are there side effects of evaluating src?
+        * If the derived type will not be the same size as src,
+        * we may have to use two steps.
+        */
+       if (tlen(src) > tlen(dest)) {
+               if (tshape(src, STARREG))
+                       return (0);
+               if (src->in.op == OREG && R2TEST(src->tn.rval))
+                       return (0);
+               }
+
+       /*
+        * Can we get an object of dest's type by punning src?
+        * Praises be to great Cthulhu for little-endian machines...
+        */
+       if (st == CHAR && dt == USHORT)
+               /*
+                * Special case -- we must sign-extend to 16 bits.
+                */
+               return (0);
+
+       if (tlen(src) < tlen(dest))
+               newt = st;
+       else
+               newt = dt;
+
+       return (newt);
+       }
+
+rmove( rt, rs, t ) TWORD t; {
        printf( "       %s      %s,%s\n",
        printf( "       %s      %s,%s\n",
+#ifdef FORT
+               !Oflag ? (t==DOUBLE ? "movq" : "movl") :
+#endif
                (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
                rnames[rs], rnames[rt] );
        }
                (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
                rnames[rs], rnames[rt] );
        }
@@ -480,18 +680,12 @@ setregs(){ /* set up temporary registers */
        ;
        }
 
        ;
        }
 
-szty(t){ /* size, in registers, needed to hold thing of type t */
-#ifdef FORT
-       return( (t==DOUBLE) ? 2 : 1 );
-#else
-       return( (t==DOUBLE||t==FLOAT) ? 2 : 1 );
-#endif
-       }
-
+/*ARGSUSED*/
 rewfld( p ) NODE *p; {
        return(1);
        }
 
 rewfld( p ) NODE *p; {
        return(1);
        }
 
+/*ARGSUSED*/
 callreg(p) NODE *p; {
        return( R0 );
        }
 callreg(p) NODE *p; {
        return( R0 );
        }
@@ -515,17 +709,29 @@ base( p ) register NODE *p; {
 
 offset( p, tyl ) register NODE *p; int tyl; {
 
 
 offset( p, tyl ) register NODE *p; int 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))
+       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;
                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;
        NODE *f;
 
        p->in.op = OREG;
@@ -560,8 +766,11 @@ makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
 
        p->tn.lval = t->tn.lval;
 #ifndef FLEXNAMES
 
        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
 #else
        p->in.name = t->in.name;
 #endif
@@ -580,18 +789,35 @@ canaddr( p ) NODE *p; {
        return(0);
        }
 
        return(0);
        }
 
-shltype( o, p ) register NODE *p; {
-       return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
-       }
-
 flshape( p ) register NODE *p; {
        return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON ||
                (p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
        }
 
 flshape( p ) register NODE *p; {
        return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON ||
                (p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
        }
 
+/* INTEMP shapes must not contain any temporary registers */
 shtemp( p ) register NODE *p; {
 shtemp( p ) register NODE *p; {
+       int r;
+
        if( p->in.op == STARG ) p = p->in.left;
        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; {
        }
 
 shumul( p ) register NODE *p; {
@@ -599,11 +825,11 @@ shumul( p ) register NODE *p; {
        extern int xdebug;
 
        if (xdebug) {
        extern int xdebug;
 
        if (xdebug) {
-                printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
-               printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
+               int val;
+               printf("shumul:\n");
+               eprint(p, 0, &val, &val);
                }
 
                }
 
-
        o = p->in.op;
        if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
 
        o = p->in.op;
        if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
 
@@ -636,7 +862,8 @@ shumul( p ) register NODE *p; {
                                break;
 
                        default:
                                break;
 
                        default:
-                               if ( ISPTR(p->in.type) ) {
+                               if ( ISPTR(p->in.type) &&
+                                    ISPTR(DECREF(p->in.type)) ) {
                                        o = 4;
                                        break;
                                        }
                                        o = 4;
                                        break;
                                        }
@@ -649,7 +876,7 @@ shumul( p ) register NODE *p; {
        }
 
 adrcon( val ) CONSZ val; {
        }
 
 adrcon( val ) CONSZ val; {
-       printf( "$" );
+       putchar( '$' );
        printf( CONFMT, val );
        }
 
        printf( CONFMT, val );
        }
 
@@ -661,7 +888,7 @@ conput( p ) register NODE *p; {
                return;
 
        case REG:
                return;
 
        case REG:
-               printf( "%s", rnames[p->tn.rval] );
+               putstr( rnames[p->tn.rval] );
                return;
 
        default:
                return;
 
        default:
@@ -669,11 +896,16 @@ conput( p ) register NODE *p; {
                }
        }
 
                }
        }
 
-insput( p ) register NODE *p; {
+/*ARGSUSED*/
+insput( p ) NODE *p; {
        cerror( "insput" );
        }
 
        cerror( "insput" );
        }
 
-upput( p ) register NODE *p; {
+upput( p, size ) NODE *p; int size; {
+       if( size == SZLONG && p->in.op == REG ) {
+               putstr( rnames[p->tn.rval + 1] );
+               return;
+               }
        cerror( "upput" );
        }
 
        cerror( "upput" );
        }
 
@@ -692,12 +924,12 @@ adrput( p ) register NODE *p; {
 
        case ICON:
                /* addressable value of the constant */
 
        case ICON:
                /* addressable value of the constant */
-               printf( "$" );
+               putchar( '$' );
                acon( p );
                return;
 
        case REG:
                acon( p );
                return;
 
        case REG:
-               printf( "%s", rnames[p->tn.rval] );
+               putstr( rnames[p->tn.rval] );
                return;
 
        case OREG:
                return;
 
        case OREG:
@@ -706,18 +938,18 @@ adrput( p ) register NODE *p; {
                        register int flags;
 
                        flags = R2UPK3(r);
                        register int flags;
 
                        flags = R2UPK3(r);
-                       if( flags & 1 ) printf("*");
-                       if( flags & 4 ) printf("-");
+                       if( flags & 1 ) putchar('*');
+                       if( flags & 4 ) putchar('-');
                        if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
                        if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
                        if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
                        if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
-                       if( flags & 2 ) printf("+");
+                       if( flags & 2 ) putchar('+');
                        printf( "[%s]", rnames[R2UPK2(r)] );
                        return;
                        }
                if( r == AP ){  /* in the argument region */
                        printf( "[%s]", rnames[R2UPK2(r)] );
                        return;
                        }
                if( r == AP ){  /* in the argument region */
-                       if( p->tn.lval <= 0 || p->in.name[0] != '\0' ) werror( "bad arg temp" );
+                       if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
                        printf( CONFMT, p->tn.lval );
                        printf( CONFMT, p->tn.lval );
-                       printf( "(ap)" );
+                       putstr( "(ap)" );
                        return;
                        }
                if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
                        return;
                        }
                if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
@@ -727,7 +959,7 @@ adrput( p ) register NODE *p; {
        case UNARY MUL:
                /* STARNM or STARREG found */
                if( tshape(p, STARNM) ) {
        case UNARY MUL:
                /* STARNM or STARREG found */
                if( tshape(p, STARNM) ) {
-                       printf( "*" );
+                       putchar( '*' );
                        adrput( p->in.left);
                        }
                else {  /* STARREG - really auto inc or dec */
                        adrput( p->in.left);
                        }
                else {  /* STARREG - really auto inc or dec */
@@ -738,14 +970,16 @@ adrput( p ) register NODE *p; {
                        p->in.left->in.op = OREG;
                        if( p->in.op == INCR ) {
                                adrput( p->in.left );
                        p->in.left->in.op = OREG;
                        if( p->in.op == INCR ) {
                                adrput( p->in.left );
-                               printf( "+" );
+                               putchar( '+' );
                                }
                        else {
                                }
                        else {
-                               printf( "-" );
+                               putchar( '-' );
                                adrput( p->in.left );
                                }
    tbl */
                        q = p->in.left;
                                adrput( p->in.left );
                                }
    tbl */
                        q = p->in.left;
+                       if( q->in.right->tn.lval != tlen(p) )
+                               cerror("adrput: bad auto-increment/decrement");
                        printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
                                rnames[q->in.left->tn.rval], 
                                (q->in.op==INCR ? "+" : "") );
                        printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
                                rnames[q->in.left->tn.rval], 
                                (q->in.op==INCR ? "+" : "") );
@@ -778,7 +1012,7 @@ acon( p ) register NODE *p; { /* print out a constant */
 #ifndef FLEXNAMES
                printf( "%.8s", p->in.name );
 #else
 #ifndef FLEXNAMES
                printf( "%.8s", p->in.name );
 #else
-               printf( "%s", p->in.name );
+               putstr( p->in.name );
 #endif
                }
        else {
 #endif
                }
        else {
@@ -830,6 +1064,7 @@ genscall( p, cookie ) register NODE *p; {
 int gc_numbytes;
 /* tbl */
 
 int gc_numbytes;
 /* tbl */
 
+/*ARGSUSED*/
 gencall( p, cookie ) register NODE *p; {
        /* generate the call given by p */
        register NODE *p1;
 gencall( p, cookie ) register NODE *p; {
        /* generate the call given by p */
        register NODE *p1;
@@ -916,6 +1151,7 @@ ccbranches[] = {
        };
 /* tbl */
 
        };
 /* tbl */
 
+/*ARGSUSED*/
 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
 
 /* tbl */
 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
 
 /* tbl */
@@ -935,6 +1171,7 @@ nextcook( p, cookie ) NODE *p; {
        return( FORREW );
        }
 
        return( FORREW );
        }
 
+/*ARGSUSED*/
 lastchance( p, cook ) NODE *p; {
        /* forget it! */
        return(0);
 lastchance( p, cook ) NODE *p; {
        /* forget it! */
        return(0);
@@ -943,13 +1180,14 @@ lastchance( p, cook ) NODE *p; {
 optim2( p ) register NODE *p; {
        /* do local tree transformations and optimizations */
 
 optim2( p ) register NODE *p; {
        /* do local tree transformations and optimizations */
 
+       int o;
+       int i, mask;
        register NODE *l, *r;
        register NODE *l, *r;
-       int m, ml;
 
 
-       switch( p->in.op ) {
+       switch( o = p->in.op ) {
 
        case AND:
 
        case AND:
-               /* commute L and R to eliminate compliments and constants */
+               /* commute L and R to eliminate complements and constants */
                if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
                    l->in.op == COMPL ) {
                        p->in.left = p->in.right;
                if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
                    l->in.op == COMPL ) {
                        p->in.left = p->in.right;
@@ -958,7 +1196,36 @@ optim2( p ) register NODE *p; {
        case ASG AND:
                /* change meaning of AND to ~R&L - bic on pdp11 */
                r = p->in.right;
        case ASG AND:
                /* change meaning of AND to ~R&L - bic on pdp11 */
                r = p->in.right;
-               if( r->in.op==ICON && r->in.name[0]==0 ) { /* compliment constant */
+               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( ISUNSIGNED(r->in.type) ) {
+                               i = (r->tn.lval & mask);
+                               if( i == mask ) {
+                                       r->in.op = FREE;
+                                       ncopy(p, l);
+                                       l->in.op = FREE;
+                                       break;
+                                       }
+                               else if( i == 0 )
+                                       goto zero;
+                               else
+                                       r->tn.lval = i;
+                               }
+                       else if( r->tn.lval == mask &&
+                                tlen(l) < SZINT/SZCHAR ) {
+                               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;
+                               }
+                       /* complement constant */
                        r->tn.lval = ~r->tn.lval;
                        }
                else if( r->in.op==COMPL ) { /* ~~A => A */
                        r->tn.lval = ~r->tn.lval;
                        }
                else if( r->in.op==COMPL ) { /* ~~A => A */
@@ -976,39 +1243,274 @@ optim2( p ) register NODE *p; {
                break;
 
        case SCONV:
                break;
 
        case SCONV:
-#ifdef FORT
+               l = p->in.left;
+#if defined(FORT) || defined(SPRECC)
                if( p->in.type == FLOAT || p->in.type == DOUBLE ||
                if( p->in.type == FLOAT || p->in.type == DOUBLE ||
-                   (l = p->in.left)->in.type == FLOAT || l->in.type == DOUBLE )
-                       break;
+                   l->in.type == FLOAT || l->in.type == DOUBLE )
+                       return;
 #else
 #else
-               m = (p->in.type == FLOAT || p->in.type == DOUBLE);
-               ml = ((l = p->in.left)->in.type == FLOAT || l->in.type == DOUBLE);
-               if( m != ml ) break;
+               if( mixtypes(p, l) ) return;
 #endif
 #endif
-               m = p->in.type;
-               ml = l->in.type;
-               /* meaningful ones are conversion of int to char, int to short,
-                  and short to char, and unsigned version of them */
-               if( m==CHAR || m==UCHAR ){
-                       if( ml!=CHAR && ml!= UCHAR )
-                               break;
-                       }
-               else if( m==SHORT || m==USHORT ){
-                       if( ml!=CHAR && ml!=UCHAR && ml!=SHORT && ml!=USHORT )
-                               break;
-                       }
+               if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
+                       return;
+
+               /* Only trust it to get it right if the size is the same */
+               if( tlen(p) != tlen(l) )
+                       return;
 
                /* clobber conversion */
 
                /* clobber conversion */
-               if( tlen( p ) == tlen( l ) && l->in.op != FLD )
+               if( l->in.op != FLD )
                        l->in.type = p->in.type;
                ncopy( p, l );
                l->in.op = FREE;
                        l->in.type = p->in.type;
                ncopy( p, l );
                l->in.op = FREE;
+
                break;
 
                break;
 
+       case ASSIGN:
+               /*
+                * Conversions are equivalent to assignments;
+                * when the two operations are combined,
+                * we can sometimes zap the conversion.
+                */
+               r = p->in.right;
+               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:
+               (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...  apparently div+mul+sub is always
+                * faster than ediv for finding MOD on the VAX, when
+                * full unsigned MOD isn't needed.
+                *
+                * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub
+                * are faster for unsigned dividend and a constant divisor
+                * in the right range (.5 to 1 of dividend's range for the
+                * first, .333+ to .5 for the second).  full unsigned is
+                * already done cmp+sub in the appropriate case; the
+                * other cases are less common and require more ambition.
+                */
+               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( 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;
                }
        }
 
                }
        }
 
-NODE * addroreg(l)
+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);
+       }
+
+/*ARGSUSED*/
+NODE * addroreg(l) NODE *l;
                                /* OREG was built in clocal()
                                 * for an auto or formal parameter
                                 * now its address is being taken
                                /* OREG was built in clocal()
                                 * for an auto or formal parameter
                                 * now its address is being taken
@@ -1018,6 +1520,7 @@ NODE * addroreg(l)
                                 */
 {
        cerror("address of OREG taken");
                                 */
 {
        cerror("address of OREG taken");
+       /*NOTREACHED*/
 }
 
 
 }
 
 
@@ -1037,8 +1540,8 @@ struct functbl {
        } opfunc[] = {
        DIV,            TANY,   "udiv",
        MOD,            TANY,   "urem",
        } opfunc[] = {
        DIV,            TANY,   "udiv",
        MOD,            TANY,   "urem",
-       ASG DIV,        TANY,   "udiv",
-       ASG MOD,        TANY,   "urem",
+       ASG DIV,        TANY,   "audiv",
+       ASG MOD,        TANY,   "aurem",
        0,      0,      0 };
 
 hardops(p)  register NODE *p; {
        0,      0,      0 };
 
 hardops(p)  register NODE *p; {
@@ -1046,41 +1549,97 @@ hardops(p)  register NODE *p; {
        register NODE *q;
        register struct functbl *f;
        register o;
        register NODE *q;
        register struct functbl *f;
        register o;
-       register TWORD t;
+       NODE *old,*temp;
 
        o = p->in.op;
 
        o = p->in.op;
-       t = p->in.type;
-       if( t!=UNSIGNED && t!=ULONG ) return;
+       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;
 
 
        for( f=opfunc; f->fop; f++ ) {
                if( o==f->fop ) goto convert;
                }
        return;
 
-       /* need to rewrite tree for ASG OP */
-       /* must change ASG OP to a simple OP */
        convert:
        convert:
+       if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
+               /* 'J', 'K' 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 ) ) {
        if( asgop( o ) ) {
-               q = talloc();
-               switch( p->in.op ) {
-                       case ASG DIV:
-                               q->in.op = DIV;
-                               break;
-                       case ASG MOD:
-                               q->in.op = MOD;
-                               break;
-               }
-               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 ... */
 
 
-       }
+               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[0] = '\0';
+#endif
+                               temp->in.left = q;
+                       }
+                       break;
+
+               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();
 
        /* build comma op for args to function */
        q = talloc();
@@ -1105,8 +1664,6 @@ hardops(p)  register NODE *p; {
        q->tn.lval = 0;
        q->tn.rval = 0;
 
        q->tn.lval = 0;
        q->tn.rval = 0;
 
-       return;
-
        }
 
 zappost(p) NODE *p; {
        }
 
 zappost(p) NODE *p; {
@@ -1153,11 +1710,28 @@ fixpre(p) NODE *p; {
        if( ty != LTYPE ) fixpre( p->in.left );
 }
 
        if( ty != LTYPE ) fixpre( p->in.left );
 }
 
+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 */
+       canon( p );             /* expands r-vals for fields */
        walkf( p, hardops );    /* convert ops to function calls */
        walkf( p, hardops );    /* convert ops to function calls */
-       canon( p );             /* expands r-vals for fileds */
        walkf( p, optim2 );
        /* jwf toff = 0;  /* stack offset swindle */
        }
        walkf( p, optim2 );
        /* jwf toff = 0;  /* stack offset swindle */
        }
-
-