BSD 4_4 release
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
index 20e5bee..158d04e 100644 (file)
@@ -1,9 +1,13 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)local2.c   1.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)local2.c   1.32 (Berkeley) 2/29/88";
 #endif
 
 #endif
 
-# include "mfile2"
-# include "ctype.h"
+# 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;
 # endif
 # ifdef FORT
 int ftlab1, ftlab2;
 # endif
@@ -12,6 +16,7 @@ int ftlab1, ftlab2;
 # define BITMASK(n) ((1L<<n)-1)
 
 # ifndef ONEPASS
 # define BITMASK(n) ((1L<<n)-1)
 
 # ifndef ONEPASS
+/*ARGSUSED*/
 where(c){
        fprintf( stderr, "%s, line %d: ", filename, lineno );
        }
 where(c){
        fprintf( stderr, "%s, line %d: ", filename, lineno );
        }
@@ -35,17 +40,17 @@ eobl2(){
        SETOFF(spoff,4);
 #ifdef FORT
 #ifndef FLEXNAMES
        SETOFF(spoff,4);
 #ifdef FORT
 #ifndef FLEXNAMES
-       printf( "       .set    .F%d,%d\n", ftnno, spoff );
+       printf( "       .set    .F%d,%ld\n", ftnno, spoff );
 #else
        /* SHOULD BE L%d ... ftnno but must change pc/f77 */
 #else
        /* SHOULD BE L%d ... ftnno but must change pc/f77 */
-       printf( "       .set    LF%d,%d\n", ftnno, spoff );
+       printf( "       .set    LF%d,%ld\n", ftnno, spoff );
 #endif
        printf( "       .set    LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
 #else
        printf( "       .set    L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
        printf( "L%d:\n", ftlab1);
        if( maxoff > AUTOINIT )
 #endif
        printf( "       .set    LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
 #else
        printf( "       .set    L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
        printf( "L%d:\n", ftlab1);
        if( maxoff > AUTOINIT )
-               printf( "       subl3   $%d,fp,sp\n", spoff);
+               printf( "       subl3   $%ld,fp,sp\n", spoff);
        printf( "       jbr     L%d\n", ftlab2);
 #endif
        ent_mask = 0;
        printf( "       jbr     L%d\n", ftlab2);
 #endif
        ent_mask = 0;
@@ -98,7 +103,8 @@ rname(r)
        register int r;
 {
 
        register int r;
 {
 
-       ent_mask |= 1<<r;
+       if (!istreg(r))
+               ent_mask |= 1<<r;
        return(rnames[r]);
 }
 
        return(rnames[r]);
 }
 
@@ -118,48 +124,61 @@ tlen(p) NODE *p;
 
                case SHORT:
                case USHORT:
 
                case SHORT:
                case USHORT:
-                       return(2);
+                       return(SZSHORT/SZCHAR);
 
                case DOUBLE:
 
                case DOUBLE:
-                       return(8);
+                       return(SZDOUBLE/SZCHAR);
 
                default:
 
                default:
-                       return(4);
+                       return(SZINT/SZCHAR);
                }
 }
 
                }
 }
 
+mixtypes(p, q) NODE *p, *q;
+{
+       register TWORD tp, tq;
+
+       tp = p->in.type;
+       tq = q->in.type;
+
+       return( (tp==FLOAT || tp==DOUBLE) !=
+               (tq==FLOAT || tq==DOUBLE) );
+}
+
 prtype(n) NODE *n;
 {
        switch (n->in.type)
                {
 
                case DOUBLE:
 prtype(n) NODE *n;
 {
        switch (n->in.type)
                {
 
                case DOUBLE:
-                       printf("d");
+                       putchar('d');
                        return;
 
                case FLOAT:
                        return;
 
                case FLOAT:
-                       printf("f");
+                       putchar('f');
                        return;
 
                        return;
 
+               case LONG:
+               case ULONG:
                case INT:
                case UNSIGNED:
                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;
                                }
                }
@@ -182,72 +201,108 @@ 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) {
-                                       printf("clr");
-                                       prtype(l);
-                                       printf("        ");
-                                       adrput(l);
-                                       return;
-                               }
-                               if (r->tn.lval < 0 && r->tn.lval >= -63) {
-                                       printf("mneg");
-                                       prtype(l);
-                                       r->tn.lval = -r->tn.lval;
-                                       goto ops;
-                               }
-#ifdef MOVAFASTER
-                       } else {
-                               printf("movab");
-                               printf("        ");
-                               acon(r);
-                               printf(",");
-                               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) ) {
-                               !ISUNSIGNED(l->in.type)?
-                                       printf("cvt"):
-                                       printf("movz");
-                               prtype(l);
-                               printf("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)) {
-                       printf("mov");
-                       prtype(l);
-                       goto ops;
-               } else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
-                       printf("movz");
-               else
-                       printf("cvt");
-               prtype(r);
-               prtype(l);
-       ops:
-               printf("        ");
+               putstr("\n\t");
+
+               hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
+               putchar('\t');
                adrput(r);
                adrput(r);
-               printf(",");
-               adrput(l);
+
+               if (ISUNSIGNED(lt)) {
+                       putstr("\n\t");
+                       s->in.op = SCONV;
+                       s->in.left = r;         /* we need only the type */
+                       s->in.type = UNSIGNED;
+                       float_to_unsigned(s);
+               } else {
+                       putstr("\n\tcv");
+                       prtype(r);
+                       putstr("l\t");
+                       if (lt == INT)
+                               adrput(l);
+                       else
+                               adrput(resc);
+               }
+               if (lt != INT) {
+                       putstr("\n\t");
+                       s->in.op = ASSIGN;
+                       s->in.left = l;
+                       s->in.right = resc;
+                       s->in.type = lt;
+                       zzzcode(s, 'U');
+               }
+
+               s->in.op = FREE;
+               return;
+               }
+
+       case 'J':       /* unsigned DIV/MOD with constant divisors */
+               {
+               register int ck = INAREG;
+               int label1, label2;
+
+               /* case constant <= 1 is handled by optim() in pass 1 */
+               /* case constant < 0x80000000 is handled in table */
+               switch( p->in.op ) {
+               /* case DIV: handled in optim2() */
+               case MOD:
+                       if( p->in.left->in.op == REG &&
+                           p->in.left->tn.rval == resc->tn.rval )
+                               goto asgmod;
+                       label1 = getlab();
+                       expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
+                       printf("\tjlssu\tL%d\n", label1);
+                       expand(p, ck, "\tsubl2\tAR,A1\n");
+                       printf("L%d:", label1);
+                       break;
+               case ASG DIV:
+                       label1 = getlab();
+                       label2 = getlab();
+                       expand(p, ck, "cmpl\tAL,AR\n");
+                       printf("\tjgequ\tL%d\n", label1);
+                       expand(p, ck, "\tmovl\t$1,AL\n");
+                       printf("\tjbr\tL%d\nL%d:\n", label2, label1);
+                       expand(p, ck, "\tclrl\tAL\n");
+                       printf("L%d:", label2);
+                       break;
+               case ASG MOD:
+               asgmod:
+                       label1 = getlab();
+                       expand(p, ck, "cmpl\tAL,AR\n");
+                       printf("\tjlssu\tL%d\n", label1);
+                       expand(p, ck, "\tsubl2\tAR,AL\n");
+                       printf("L%d:", label1);
+                       break;
+                       }
                return;
                }
 
                return;
                }
 
@@ -256,17 +311,17 @@ zzzcode( p, c ) register NODE *p; {
                register NODE *r;
                if (xdebug) eprint(p, 0, &val, &val);
                r = p->in.right;
                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");
+               if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
+                       putstr("movl");
                else {
                else {
-                       printf(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
+                       putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
                        prtype(r);
                        prtype(r);
-                       printf("l");
+                       putchar('l');
                        }
                return;
                }
 
                        }
                return;
                }
 
-       case 'C':       /* num bytes pushed on arg stack */
+       case 'C':       /* generate 'call[fs] $bytes' */
                {
                extern int gc_numbytes;
                extern int xdebug;
                {
                extern int gc_numbytes;
                extern int xdebug;
@@ -276,30 +331,44 @@ zzzcode( p, c ) register NODE *p; {
                printf("call%c  $%d",
                 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
                 gc_numbytes+4);
                printf("call%c  $%d",
                 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
                 gc_numbytes+4);
-               /* dont change to double (here's the only place to catch it) */
+               /* don't change to double (here's the only place to catch it) */
                if(p->in.type == FLOAT)
                        rtyflg = 1;
                return;
                }
 
        case 'D':       /* INCR and DECR */
                if(p->in.type == FLOAT)
                        rtyflg = 1;
                return;
                }
 
        case 'D':       /* INCR and DECR */
-               zzzcode(p->in.left, 'A');
-               printf("\n      ");
+               if (p->in.left->in.type == FLOAT)
+                       expand(p, INAREG, "movl\tAL,A1");
+               else if (p->in.left->in.type == DOUBLE)
+                       expand(p, INAREG, "ldd\tAL\n\tstd\tA1");
+               else
+                       zzzcode(p->in.left, 'U');
+               putstr("\n      ");
 
        case 'E':       /* INCR and DECR, FOREFF */
 
        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") );
+               else if (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE) {
+                       if (c == 'E' || p->in.left->in.type == FLOAT)
+                               expand(p, INAREG, "ldZL\tAL\n\t");
+                       if (p->in.op == INCR)
+                               expand(p, INAREG, "addZL\tAR\n\tstZL\tAL");
+                       else /* DECR */
+                               expand(p, INAREG, "subZL\tAR\n\tstZL\tAL");
+                       return;
+                       }
+               putstr(p->in.op == INCR ? "add" : "sub");
                prtype(p->in.left);
                prtype(p->in.left);
-               printf("2       ");
+               putstr("2       ");
                adrput(p->in.right);
                adrput(p->in.right);
-               printf(",");
+               putchar(',');
                adrput(p->in.left);
                return;
 
                adrput(p->in.left);
                return;
 
@@ -307,13 +376,34 @@ zzzcode( p, c ) register NODE *p; {
                printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
                return;
 
                printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
                return;
 
+       case 'I':       /* produce value of bitfield assignment */
+                       /* avoid shifts -- shifts are SLOW on this machine */
+                       /* XXX this wouldn't be necessary if we were smarter
+                              and masked BEFORE shifting XXX */
+               {
+               register NODE *r = p->in.right;
+               if(r->in.op == ICON && r->tn.name[0] == '\0') {
+                       putstr("movl\t");
+                       printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
+                       }
+               else {
+                       putstr("andl3\t");
+                       printf(ACONFMT, (1 << fldsz) - 1);
+                       putchar(',');
+                       adrput(r);
+                       }
+               putchar(',');
+               adrput(resc);
+               break;
+               }
+
        case 'H':       /* opcode for shift */
                if(p->in.op == LS || p->in.op == ASG LS)
        case 'H':       /* opcode for shift */
                if(p->in.op == LS || p->in.op == ASG LS)
-                       printf("shll");
+                       putstr("shll");
                else if(ISUNSIGNED(p->in.left->in.type))
                else if(ISUNSIGNED(p->in.left->in.type))
-                       printf("shrl");
+                       putstr("shrl");
                else
                else
-                       printf("shar");
+                       putstr("shar");
                return;
 
        case 'L':       /* type of left operand */
                return;
 
        case 'L':       /* type of left operand */
@@ -329,113 +419,544 @@ zzzcode( p, c ) register NODE *p; {
                return;
                }
 
                return;
                }
 
-       case 'M':  /* initiate ediv for mod and unsigned div */
-               {
-               register char *r;
-               m = getlr(p, '1')->tn.rval;
-               r = rname(m);
-               printf("\tclrl\t%s\n\tmovl\t", r);
+       case 'M': {  /* initiate ediv for mod and unsigned div */
+               putstr("clrl\t");
+               adrput(resc);
+               putstr("\n\tmovl\t");
                adrput(p->in.left);
                adrput(p->in.left);
-               printf(",%s\n", rname(m+1));
-               if(!ISUNSIGNED(p->in.type)) {   /* should be MOD */
-                       m = getlab();
-                       printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
-                       deflab(m);
+               putchar(',');
+               upput(resc, SZLONG);
+               printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
+               adrput(resc);
+               putchar('\n');
+               deflab(m);
+               return;
+       }
+
+       case 'T': {     /* rounded structure length for arguments */
+               int size = p->stn.stsize;
+               SETOFF( size, 4);
+               printf("movab   -%d(sp),sp", size);
+               return;
+       }
+
+       case 'S':  /* structure assignment */
+               stasg(p);
+               break;
+
+#ifdef I_don_t_understand_this
+       case 'X':       /* multiplication for short and char */
+               if (ISUNSIGNED(p->in.left->in.type)) 
+                       printf("\tmovz");
+               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;
+#endif
+
+       case 'U':               /* SCONV */
+       case 'V':               /* SCONV with FORCC */
+               sconv(p, c == 'V');
+               break;
+
+       case 'W': {             /* SCONV or ASSIGN float/double => unsigned */
+               NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
+
+               putstr("ld");
+               prtype(src);
+               putchar('\t');
+               adrput(src);
+               putstr("\n\t");
+               float_to_unsigned(p);
+               break;
+       }
+
+       case 'Y':               /* SCONV or ASSIGN unsigned => float/double */
+               unsigned_to_float(p);   /* stores into accumulator */
+               putstr("\n\tst");
+               prtype(p);
+               putchar('\t');
+               if (p->in.op == SCONV)
+                       adrput(resc);
+               else
+                       adrput(p->in.left);
+               rtyflg = 1;
+               break;
+
+#ifdef I_don_t_understand_this
+       case 'Z':
+               p = p->in.right;
+               switch (p->in.type) {
+               case SHORT: {
+                       short w = p->tn.lval;
+                       p->tn.lval = w;
+                       break;
                }
                }
+               case CHAR: {
+                       char c = p->tn.lval;
+                       p->tn.lval = c;
+                       break;
                }
                }
-               return;
+               }
+               printf("$%d", p->tn.lval);
+               break;
+#endif
 
 
-       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;
+       default:
+               cerror( "illegal zzzcode" );
+       }
+}
 
 
-               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;
+#define        MOVB(dst, src, off) { \
+       putstr("\tmovb\t"); upput(src, off); putchar(','); \
+       upput(dst, off); putchar('\n'); \
+}
+#define        MOVW(dst, src, off) { \
+       putstr("\tmovw\t"); upput(src, off); putchar(','); \
+       upput(dst, off); putchar('\n'); \
+}
+#define        MOVL(dst, src, off) { \
+       putstr("\tmovl\t"); upput(src, off); putchar(','); \
+       upput(dst, off); putchar('\n'); \
+}
+/*
+ * Generate code for a structure assignment.
+ */
+stasg(p)
+       register NODE *p;
+{
+       register NODE *l, *r;
+       register int size;
+
+       switch (p->in.op) {
+       case STASG:                     /* regular assignment */
+               l = p->in.left;
+               r = p->in.right;
+               break;
+       case STARG:                     /* place arg on the stack */
+               l = getlr(p, '3');
+               r = p->in.left;
+               break;
+       default:
+               cerror("STASG bad");
+               /*NOTREACHED*/
+       }
+       /*
+        * Pun source for use in code generation.
+        */
+       switch (r->in.op) {
+       case ICON:
+               r->in.op = NAME;
+               break;
+       case REG:
+               r->in.op = OREG;
+               break;
+       default:
+               cerror( "STASG-r" );
+               /*NOTREACHED*/
+       }
+       size = p->stn.stsize;
+       if (size <= 0 || size > 65535)
+               cerror("structure size out of range");
+       /*
+        * Generate optimized code based on structure size
+        * and alignment properties....
+        */
+       switch (size) {
+
+       case 1:
+               putstr("\tmovb\t");
+       optimized:
+               adrput(r);
+               putchar(',');
+               adrput(l);
+               putchar('\n');
+               break;
+
+       case 2:
+               if (p->stn.stalign != 2) {
+                       MOVB(l, r, SZCHAR);
+                       putstr("\tmovb\t");
+               } else
+                       putstr("\tmovw\t");
+               goto optimized;
+
+       case 4:
+               if (p->stn.stalign != 4) {
+                       if (p->stn.stalign != 2) {
+                               MOVB(l, r, 3*SZCHAR);
+                               MOVB(l, r, 2*SZCHAR);
+                               MOVB(l, r, 1*SZCHAR);
+                               putstr("\tmovb\t");
+                       } else {
+                               MOVW(l, r, SZSHORT);
+                               putstr("\tmovw\t");
                        }
                        }
+               } else
+                       putstr("\tmovl\t");
+               goto optimized;
+
+       case 6:
+               if (p->stn.stalign != 2)
+                       goto movblk;
+               MOVW(l, r, 2*SZSHORT);
+               MOVW(l, r, 1*SZSHORT);
+               putstr("\tmovw\t");
+               goto optimized;
+
+       case 8:
+               if (p->stn.stalign == 4) {
+                       MOVL(l, r, SZLONG);
+                       putstr("\tmovl\t");
+                       goto optimized;
                }
                }
+               /* fall thru...*/
 
 
-       case 'T':       /* rounded structure length for arguments */
+       default:
+       movblk:
+               /*
+                * Can we ever get a register conflict with R1 here?
+                */
+               putstr("\tmovab\t");
+               if(r->in.op == OREG && r->tn.rval == R1)
                {
                {
-               int size;
-
-               size = p->stn.stsize;
-               SETOFF( size, 4);
-               printf("movab   -%d(sp),sp", size);
-               return;
+                       adrput(r);
+                       printf(",r0\n\tmovab\t");
+                       adrput(l);
+                       putstr(",r1\n");
                }
                }
-
-       case 'S':  /* structure assignment */
+               else
                {
                {
-                       register NODE *l, *r;
-                       register int size;
+                       adrput(l);
+                       putstr(",r1\n\tmovab\t");
+                       adrput(r);
+                       printf(",r0\n");
+               }
+               printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
+               rname(R2);
+               break;
+       }
+       /*
+        * Reverse above pun for reclaim.
+        */
+       if (r->in.op == NAME)
+               r->in.op = ICON;
+       else if (r->in.op == OREG)
+               r->in.op = REG;
+}
 
 
-                       if( p->in.op == STASG ){
-                               l = p->in.left;
-                               r = p->in.right;
+/*
+ * 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;
+       }
 
 
-                               }
-                       else if( p->in.op == STARG ){  /* store an arg into a temporary */
-                               l = getlr( p, '3' );
-                               r = p->in.left;
-                               }
-                       else cerror( "STASG bad" );
+       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);
+}
 
 
-                       if( r->in.op == ICON ) r->in.op = NAME;
-                       else if( r->in.op == REG ) r->in.op = OREG;
-                       else if( r->in.op != OREG ) cerror( "STASG-r" );
+/*
+ * 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;
+       }
 
 
-                       size = p->stn.stsize;
+       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);
+}
 
 
-                       if( size <= 0 || size > 65535 )
-                               cerror("structure size <0=0 or >65535");
-                       /*
-                        * Can't optimize with movw's or movl's here as
-                        * we don't know the alignment properties of
-                        * either source or destination (governed, potentially
-                        * by alignment of enclosing structure/union).
-                        * (PERHAPS WE COULD SIMULATE dclstruct?)
-                        */
-                       if (size != 1) {
-                               printf("\tmovab\t");
-                               adrput(l);
-                               printf(",r1\n\tmovab\t");
-                               adrput(r);
-                               printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
-                               rname(2);
-                       } else {
-                               printf("\tmovb\t");
-                               adrput(r);
-                               printf(",");
-                               adrput(l);
-                               printf("\n");
+/*
+ * Prlen() is a cheap prtype()...
+ */
+static char convtab[SZINT/SZCHAR + 1] = {
+       '?', 'b', 'w', '?', 'l'
+};
+#define        prlen(len)      putchar(convtab[len])
+
+
+/*
+ * Generate code for integral scalar conversions.
+ * Some of this code is designed to work around a tahoe misfeature
+ *     that causes sign- and zero- extension to be defeated in
+ *     certain circumstances.
+ * Basically if the source operand of a CVT or MOVZ instruction is
+ *     shorter than the destination, and the source is a register
+ *     or an immediate constant, sign- and zero- extension are
+ *     ignored and the high bits of the source are copied.  (Note
+ *     that zero-extension is not a problem for immediate
+ *     constants.)
+ * Another problem -- condition codes for a conversion with a
+ *     register source reflect the source rather than the destination.
+ */
+sconv(p, forcc)
+       NODE *p;
+       int forcc;
+{
+       register NODE *src, *dst;
+       register NODE *tmp;
+       register int srclen, dstlen;
+       int srctype, dsttype;
+       int val;
+       int neg = 0;
+
+       if (p->in.op == ASSIGN) {
+               src = p->in.right;
+               dst = p->in.left;
+               dstlen = tlen(dst);
+               dsttype = dst->in.type;
+       } else if (p->in.op == SCONV) {
+               src = p->in.left;
+               dst = resc;
+               dstlen = tlen(p);
+               dsttype = p->in.type;
+       } else /* if (p->in.op == OPLEAF) */ {
+               src = p;
+               dst = resc;
+               dstlen = SZINT/SZCHAR;
+               dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
+       }
+
+       if (src->in.op == REG) {
+               srclen = SZINT/SZCHAR;
+               srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
+       } else {
+               srclen = tlen(src);
+               srctype = src->in.type;
+       }
+
+       if (src->in.op == ICON && src->tn.name[0] == '\0') {
+               if (src->tn.lval == 0) {
+                       putstr("clr");
+                       prtype(dst);
+                       putchar('\t');
+                       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( r->in.op == NAME ) r->in.op = ICON;
-                       else if( r->in.op == OREG ) r->in.op = REG;
+               }
+               if (dst->in.op == REG) {
+                       dsttype = INT;
+                       dstlen = SZINT/SZCHAR;
+               }
+               srctype = dsttype;
+               srclen = dstlen;
+               val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
+               if ((unsigned) val < 64) {
+                       src->tn.lval = val;
+                       ++neg;          /* MNEGx may be shorter */
+               }
+       }
 
 
+       if (srclen < dstlen) {
+               if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
+                       /* (unsigned short) c; => sign extend to 16 bits */
+                       putstr("cvtbl\t");
+                       adrput(src);
+                       putstr(",-(sp)\n\tmovzwl\t2(sp),");
+                       adrput(dst);
+                       putstr("\n\tmovab\t4(sp),sp");
+                       if (forcc) {
+                               putstr("\n\ttstl\t");
+                               adrput(dst);
                        }
                        }
-               break;
+                       return;
+               }
+               genconv(ISUNSIGNED(srctype),
+                       srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+                       src, dst, forcc);
+               return;
+       }
 
 
-       default:
-               cerror( "illegal zzzcode" );
+       if (srclen > dstlen && dst->in.op == REG) {
+               /* if dst is a register, the result must look like an int */
+               if (src->in.op == REG) {
+                       if (ISUNSIGNED(dsttype)) {
+                               val = (1 << dstlen * SZCHAR) - 1;
+                               if (src->tn.rval == dst->tn.rval)
+                                       /* conversion in place */
+                                       printf("andl2\t$%ld,", val);
+                               else {
+                                       printf("andl3\t$%ld,", val);
+                                       adrput(src);
+                                       putchar(',');
+                               }
+                               adrput(dst);
+                               return;
+                       }
+                       /*
+                        * Sign extension in register can also be
+                        * accomplished by shifts, but unfortunately
+                        * shifts are extremely slow, due to the lack
+                        * of a barrel shifter.
+                        */
+                       putstr("pushl\t");
+                       adrput(src);
+                       putstr("\n\tcvt");
+                       prlen(dstlen);
+                       printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
+                       adrput(dst);
+                       putstr("\n\tmovab\t4(sp),sp");
+                       if (forcc) {
+                               putstr("\n\ttstl\t");
+                               adrput(dst);
+                       }
+                       return;
+               }
+               tmp = talloc();
+               if ((src->in.op == NAME) ||
+                   (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
+                   (src->in.op == OREG && !R2TEST(src->tn.rval))) {
+                       /* we can increment src's address & pun it */
+                       *tmp = *src;
+                       tmp->tn.lval += srclen - dstlen;
+               } else {
+                       /* we must store src's address */
+                       *tmp = *dst;
+                       putstr("mova");
+                       prlen(srclen);
+                       putchar('\t');
+                       adrput(src);
+                       putchar(',');
+                       adrput(tmp);
+                       putstr("\n\t");
+                       tmp->tn.op = OREG;
+                       tmp->tn.lval = srclen - dstlen;
                }
                }
+               genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
+               tmp->in.op = FREE;
+               return;
        }
 
        }
 
-rmove( rt, rs, t ) TWORD t;{
+       genconv(neg ? -1 : ISUNSIGNED(dsttype),
+               srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
+               src, dst, forcc);
+}
+
+genconv(srcflag, srclen, dstlen, src, dst, forcc)
+       int srcflag;
+       register int srclen, dstlen;
+       NODE *src, *dst;
+       int forcc;
+{
+       if (srclen != dstlen) {
+               if (srcflag > 0 && srclen < dstlen)
+                       putstr("movz");
+               else
+                       putstr("cvt");
+               prlen(srclen);
+       } else if (srcflag < 0)
+               putstr("mneg");
+       else
+               putstr("mov");
+       prlen(dstlen);
+       putchar('\t');
+       adrput(src);
+       putchar(',');
+       adrput(dst);
+
+       /*
+        * This hack is made necessary by architecture problems
+        *      described above
+        */
+       if (forcc && src->in.op == REG && srclen > dstlen) {
+               putstr("\n\ttst");
+               prlen(dstlen);
+               putchar('\t');
+               adrput(dst);
+       }
+}
+
+rmove( rt, rs, t ) TWORD t; {
        printf( "       movl    %s,%s\n", rname(rs), rname(rt) );
        if(t==DOUBLE)
                printf( "       movl    %s,%s\n", rname(rs+1), rname(rt+1) );
        printf( "       movl    %s,%s\n", rname(rs), rname(rt) );
        if(t==DOUBLE)
                printf( "       movl    %s,%s\n", rname(rs+1), rname(rt+1) );
@@ -454,14 +975,18 @@ setregs(){ /* set up temporary registers */
        fregs = 6;      /* tbl- 6 free regs on Tahoe (0-5) */
        }
 
        fregs = 6;      /* tbl- 6 free regs on Tahoe (0-5) */
        }
 
+#ifndef szty
 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
        return(t==DOUBLE ? 2 : 1 );
        }
 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
        return(t==DOUBLE ? 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 );
        }
@@ -469,29 +994,41 @@ callreg(p) NODE *p; {
 base( p ) register NODE *p; {
        register int o = p->in.op;
 
 base( p ) register NODE *p; {
        register int o = p->in.op;
 
-       if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
+       if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
        if( o==REG ) return( p->tn.rval );
     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
                return( p->in.left->tn.rval );
     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
                return( p->tn.rval + 0200*1 );
        if( o==REG ) return( p->tn.rval );
     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
                return( p->in.left->tn.rval );
     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
                return( p->tn.rval + 0200*1 );
+       if( o==NAME ) return( 100 + 0200*1 );
        return( -1 );
        }
 
 offset( p, tyl ) register NODE *p; int tyl; {
 
        return( -1 );
        }
 
 offset( p, tyl ) register NODE *p; int tyl; {
 
-       if(tyl > 8) return( -1 );
-       if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
-       if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
-             (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
-             && (1<<p->in.right->tn.lval)==tyl))
+       if( tyl==1 &&
+           p->in.op==REG &&
+           (p->in.type==INT || p->in.type==UNSIGNED) )
+               return( p->tn.rval );
+       if( p->in.op==LS &&
+           p->in.left->in.op==REG &&
+           (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
+           p->in.right->in.op==ICON &&
+           p->in.right->in.name[0]=='\0' &&
+           (1<<p->in.right->tn.lval)==tyl)
+               return( p->in.left->tn.rval );
+       if( tyl==2 &&
+           p->in.op==PLUS &&
+           (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
+           p->in.left->in.op==REG &&
+           p->in.right->in.op==REG &&
+           p->in.left->tn.rval==p->in.right->tn.rval )
                return( p->in.left->tn.rval );
        return( -1 );
        }
 
 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
        register NODE *t;
                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;
@@ -502,6 +1039,7 @@ makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
                case ICON:
                case REG:
                case OREG:
                case ICON:
                case REG:
                case OREG:
+               case NAME:
                        t = q;
                        break;
 
                        t = q;
                        break;
 
@@ -521,8 +1059,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
@@ -541,9 +1082,11 @@ canaddr( p ) NODE *p; {
        return(0);
        }
 
        return(0);
        }
 
+#ifndef shltype
 shltype( o, p ) register NODE *p; {
        return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
        }
 shltype( o, p ) register NODE *p; {
        return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
        }
+#endif
 
 flshape( p ) NODE *p; {
        register int o = p->in.op;
 
 flshape( p ) NODE *p; {
        register int o = p->in.op;
@@ -552,9 +1095,30 @@ flshape( p ) NODE *p; {
        return(0);
        }
 
        return(0);
        }
 
+/* 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; {
@@ -591,7 +1155,7 @@ conput( p ) register NODE *p; {
                return;
 
        case REG:
                return;
 
        case REG:
-               printf( "%s", rname(p->tn.rval) );
+               putstr(rname(p->tn.rval));
                return;
 
        default:
                return;
 
        default:
@@ -599,36 +1163,45 @@ conput( p ) register NODE *p; {
                }
        }
 
                }
        }
 
+/*ARGSUSED*/
 insput( p ) NODE *p; {
        cerror( "insput" );
        }
 
 insput( p ) NODE *p; {
        cerror( "insput" );
        }
 
-upput( p ) register NODE *p; {
-       /* output the address of the second long in the
-          pair pointed to by p (for DOUBLEs)*/
+/*
+ * Output the address of the second item in the
+ * pair pointed to by p.
+ */
+upput(p, size)
+       register NODE *p;
+{
        CONSZ save;
 
        CONSZ save;
 
-       if( p->in.op == FLD ){
+       if (p->in.op == FLD)
                p = p->in.left;
                p = p->in.left;
-               }
-       switch( p->in.op ){
+       switch (p->in.op) {
 
        case NAME:
        case OREG:
                save = p->tn.lval;
 
        case NAME:
        case OREG:
                save = p->tn.lval;
-               p->tn.lval += SZLONG/SZCHAR;
+               p->tn.lval += size/SZCHAR;
                adrput(p);
                p->tn.lval = save;
                adrput(p);
                p->tn.lval = save;
-               return;
+               break;
 
        case REG:
 
        case REG:
-               printf( "%s", rname(p->tn.rval+1) );
-               return;
+               if (size == SZLONG) {
+                       putstr(rname(p->tn.rval+1));
+                       break;
+               }
+               /* fall thru... */
 
        default:
 
        default:
-               cerror( "illegal upper address" );
-               }
+               cerror("illegal upper address op %s size %d",
+                   opst[p->tn.op], size);
+               /*NOTREACHED*/
        }
        }
+}
 
 adrput( p ) register NODE *p; {
        register int r;
 
 adrput( p ) register NODE *p; {
        register int r;
@@ -645,12 +1218,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", rname(p->tn.rval) );
+               putstr(rname(p->tn.rval));
                if(p->in.type == DOUBLE)        /* for entry mask */
                        (void) rname(p->tn.rval+1);
                return;
                if(p->in.type == DOUBLE)        /* for entry mask */
                        (void) rname(p->tn.rval+1);
                return;
@@ -661,7 +1234,7 @@ adrput( p ) register NODE *p; {
                        register int flags;
 
                        flags = R2UPK3(r);
                        register int flags;
 
                        flags = R2UPK3(r);
-                       if( flags & 1 ) printf("*");
+                       if( flags & 1 ) putchar('*');
                        if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
                        if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
                        printf( "[%s]", rname(R2UPK2(r)) );
                        if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
                        if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
                        printf( "[%s]", rname(R2UPK2(r)) );
@@ -670,7 +1243,7 @@ adrput( p ) register NODE *p; {
                if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
                        if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
                        printf( CONFMT, p->tn.lval );
                if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
                        if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
                        printf( CONFMT, p->tn.lval );
-                       printf( "(fp)" );
+                       putstr( "(fp)" );
                        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 );
@@ -680,7 +1253,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);
                        }
                return;
                        adrput( p->in.left);
                        }
                return;
@@ -695,23 +1268,18 @@ adrput( p ) register NODE *p; {
 
 acon( p ) register NODE *p; { /* print out a constant */
 
 
 acon( p ) register NODE *p; { /* print out a constant */
 
-       if( p->in.name[0] == '\0' ){
+       if( p->in.name[0] == '\0' )
                printf( CONFMT, p->tn.lval);
                printf( CONFMT, p->tn.lval);
-               }
-       else if( p->tn.lval == 0 ) {
-#ifndef FLEXNAMES
-               printf( "%.8s", p->in.name );
-#else
-               printf( "%s", p->in.name );
-#endif
-               }
        else {
 #ifndef FLEXNAMES
        else {
 #ifndef FLEXNAMES
-               printf( "%.8s+", p->in.name );
+               printf( "%.8s", p->in.name );
 #else
 #else
-               printf( "%s+", p->in.name );
+               putstr( p->in.name );
 #endif
 #endif
-               printf( CONFMT, p->tn.lval );
+               if( p->tn.lval != 0 ) {
+                       putchar( '+' );
+                       printf( CONFMT, p->tn.lval );
+                       }
                }
        }
 
                }
        }
 
@@ -755,6 +1323,7 @@ genfcall( 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, *ptemp;
 gencall( p, cookie ) register NODE *p; {
        /* generate the call given by p */
        register NODE *p1, *ptemp;
@@ -828,12 +1397,12 @@ ccbranches[] = {
        };
 /* tbl */
 
        };
 /* tbl */
 
+/*ARGSUSED*/
 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
 
 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
 
-               if(o != 0 && (o < EQ || o > UGT ))
-                       cerror( "bad conditional branch: %s", opst[o] );
-               printf( "       j%s     L%d\n",
-                o == 0 ? "br" : ccbranches[o-EQ], lab );
+       if( o != 0 && ( o < EQ || o > UGT ) )
+               cerror( "bad conditional branch: %s", opst[o] );
+       printf( "       j%s     L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
        }
 
 nextcook( p, cookie ) NODE *p; {
        }
 
 nextcook( p, cookie ) NODE *p; {
@@ -844,117 +1413,474 @@ nextcook( p, cookie ) NODE *p; {
        return( FORREW );
        }
 
        return( FORREW );
        }
 
+/*ARGSUSED*/
 lastchance( p, cook ) NODE *p; {
        /* forget it! */
        return(0);
        }
 
 optim2( p ) register NODE *p; {
 lastchance( p, cook ) NODE *p; {
        /* forget it! */
        return(0);
        }
 
 optim2( p ) register NODE *p; {
-# ifdef ONEPASS
        /* do local tree transformations and optimizations */
        /* do local tree transformations and optimizations */
-# define RV(p) p->in.right->tn.lval
-       register int o = p->in.op;
-       register int i;
 
 
-       /* 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;
+       int o;
+       int i, mask;
+       register NODE *l, *r;
+
+       switch( o = p->in.op ) {
+
+       case ASG PLUS:
+       case ASG MINUS:
+       case ASG MUL:
+       case ASG OR:
+               /* simple ASG OPSIMP -- reduce range of constant rhs */
+               l = p->in.left;
+               r = p->in.right;
+               if( tlen(l) < SZINT/SZCHAR &&
+                   r->in.op==ICON && r->in.name[0]==0 ){
+                       mask = (1 << tlen(l) * SZCHAR) - 1;
+                       if( r->tn.lval & (mask & ~(mask >> 1)) )
+                               r->tn.lval |= ~mask;
+                       else
+                               r->tn.lval &= mask;
+                       }
+               break;
+
+       case AND:
+       case ASG AND:
+               r = p->in.right;
+               if( r->in.op==ICON && r->in.name[0]==0 ) {
+                       /* check for degenerate operations */
+                       l = p->in.left;
+                       mask = (1 << tlen(l) * SZCHAR) - 1;
+                       if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
+                               i = r->tn.lval & mask;
+                               if( i == mask ) {
+                                       /* redundant mask */
+                                       r->in.op = FREE;
+                                       ncopy(p, l);
+                                       l->in.op = FREE;
+                                       break;
+                                       }
+                               else if( i == 0 )
+                                       /* all bits masked off */
+                                       goto zero;
+                               r->tn.lval = i;
+                               if( tlen(l) < SZINT/SZCHAR ){
+                                       /* sign extend */
+                                       if( r->tn.lval & (mask & ~(mask >> 1)) )
+                                               r->tn.lval |= ~mask;
+                                       else
+                                               r->tn.lval &= mask;
+                                       }
+                               }
+                       else if( r->tn.lval == mask &&
+                                tlen(l) < SZINT/SZCHAR ) {
+                               /* use movz instead of and */
+                               r->in.op = SCONV;
+                               r->in.left = l;
+                               r->in.right = 0;
+                               r->in.type = ENUNSIGN(l->in.type);
+                               r->in.su = l->in.su > 1 ? l->in.su : 1;
+                               ncopy(p, r);
+                               p->in.left = r;
+                               p->in.type = INT;
+                               }
+                       }
+               break;
+
+       case SCONV:
+               l = p->in.left;
+               if( p->in.type == FLOAT || p->in.type == DOUBLE ||
+                   l->in.type == FLOAT || l->in.type == DOUBLE )
+                       return;
+               if( l->in.op == PCONV )
+                       return;
+               if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
+                   l->in.type != INT && l->in.type != UNSIGNED )
+                       return;
+
+               /* Only trust it to get it right if the size is the same */
+               if( tlen(p) != tlen(l) )
+                       return;
+
+               /* clobber conversion */
+               if( l->in.op != FLD )
+                       l->in.type = p->in.type;
+               ncopy( p, l );
+               l->in.op = FREE;
+
+               break;
+
+       case ASSIGN:
+               /*
+                * 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;
                        break;
-               case MOD:
-               case ASG MOD:
-                       p->in.op = AND;
-                       RV(p)--;
+               p->in.op += (UGE-GE);
+               break;
+
+       case EQ:
+       case NE:
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+               if( p->in.left->in.op == SCONV &&
+                   p->in.right->in.op == SCONV ) {
+                       l = p->in.left;
+                       r = p->in.right;
+                       if( l->in.type == DOUBLE &&
+                           l->in.left->in.type == FLOAT &&
+                           r->in.left->in.type == FLOAT ) {
+                               /* nuke the conversions */
+                               p->in.left = l->in.left;
+                               p->in.right = r->in.left;
+                               l->in.op = FREE;
+                               r->in.op = FREE;
+                               }
+                       /* more? */
+                       }
+               (void) degenerate(p);
+               break;
+
+       case DIV:
+               if( p->in.right->in.op == ICON &&
+                   p->in.right->tn.name[0] == '\0' &&
+                   ISUNSIGNED(p->in.right->in.type) &&
+                   (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
+                       /* easy to do here, harder to do in zzzcode() */
+                       p->in.op = UGE;
                        break;
                        break;
-               default:
-                       return;
+                       }
+       case MOD:
+       case ASG DIV:
+       case ASG MOD:
+               /*
+                * optimize DIV and MOD
+                *
+                * basically we spot UCHAR and USHORT and try to do them
+                * as signed ints...  this may need tuning for the tahoe.
+                */
+               if( degenerate(p) )
+                       break;
+               l = p->in.left;
+               r = p->in.right;
+               if( !ISUNSIGNED(r->in.type) ||
+                   tlen(l) >= SZINT/SZCHAR ||
+                   !(tlen(r) < SZINT/SZCHAR ||
+                     (r->in.op == ICON && r->tn.name[0] == '\0')) )
+                       break;
+               if( r->in.op == ICON )
+                       r->tn.type = INT;
+               else {
+                       NODE *t = talloc();
+                       t->in.left = r;
+                       r = t;
+                       r->in.op = SCONV;
+                       r->in.type = INT;
+                       r->in.right = 0;
+                       p->in.right = r;
+                       }
+               if( o == DIV || o == MOD ) {
+                       NODE *t = talloc();
+                       t->in.left = l;
+                       l = t;
+                       l->in.op = SCONV;
+                       l->in.type = INT;
+                       l->in.right = 0;
+                       p->in.left = l;
+                       }
+               /* handle asgops in table */
+               break;
+
+       case RS:
+       case ASG RS:
+       case LS:
+       case ASG LS:
+               /* pick up degenerate shifts */
+               l = p->in.left;
+               r = p->in.right;
+               if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
+                       break;
+               i = r->tn.lval;
+               if( i < 0 )
+                       /* front end 'fixes' this? */
+                       if( o == LS || o == ASG LS )
+                               o += (RS-LS);
+                       else
+                               o += (LS-RS);
+               if( (o == RS || o == ASG RS) &&
+                   !ISUNSIGNED(l->in.type) )
+                       /* can't optimize signed right shifts */
+                       break;
+               if( o == LS ) {
+                       if( i < SZINT )
+                               break;
+                       }
+               else {
+                       if( i < tlen(l) * SZCHAR )
+                               break;
+                       }
+       zero:
+               if( !asgop( o ) )
+                       if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
+                               /* no side effects */
+                               tfree(l);
+                               ncopy(p, r);
+                               r->in.op = FREE;
+                               p->tn.lval = 0;
+                               }
+                       else {
+                               p->in.op = COMOP;
+                               r->tn.lval = 0;
+                               }
+               else {
+                       p->in.op = ASSIGN;
+                       r->tn.lval = 0;
+                       }
+               break;
                }
                }
-               if(asgop(o))
-                       p->in.op = ASG p->in.op;
        }
        }
-# endif
-}
+
+degenerate(p) register NODE *p; {
+       int o;
+       int result, i;
+       int lower, upper;
+       register NODE *l, *r;
+
+       /*
+        * try to keep degenerate comparisons with constants
+        * out of the table.
+        */
+       r = p->in.right;
+       l = p->in.left;
+       if( r->in.op != ICON ||
+           r->tn.name[0] != '\0' ||
+           tlen(l) >= tlen(r) )
+               return (0);
+       switch( l->in.type ) {
+       case CHAR:
+               lower = -(1 << SZCHAR - 1);
+               upper = (1 << SZCHAR - 1) - 1;
+               break;
+       case UCHAR:
+               lower = 0;
+               upper = (1 << SZCHAR) - 1;
+               break;
+       case SHORT:
+               lower = -(1 << SZSHORT - 1);
+               upper = (1 << SZSHORT - 1) - 1;
+               break;
+       case USHORT:
+               lower = 0;
+               upper = (1 << SZSHORT) - 1;
+               break;
+       default:
+               cerror("unsupported type in degenerate()");
+               }
+       i = r->tn.lval;
+       switch( o = p->in.op ) {
+       case DIV:
+       case ASG DIV:
+       case MOD:
+       case ASG MOD:
+               /* DIV and MOD work like EQ */
+       case EQ:
+       case NE:
+               if( lower == 0 && (unsigned) i > upper )
+                       result = o == NE;
+               else if( i < lower || i > upper )
+                       result = o == NE;
+               else
+                       return (0);
+               break;
+       case LT:
+       case GE:
+               if( lower == 0 && (unsigned) i > upper )
+                       result = o == LT;
+               else if( i <= lower )
+                       result = o != LT;
+               else if( i > upper )
+                       result = o == LT;
+               else
+                       return (0);
+               break;
+       case LE:
+       case GT:
+               if( lower == 0 && (unsigned) i >= upper )
+                       result = o == LE;
+               else if( i < lower )
+                       result = o != LE;
+               else if( i >= upper )
+                       result = o == LE;
+               else
+                       return (0);
+               break;
+       default:
+               cerror("unknown op in degenerate()");
+               }
+               
+       if( o == MOD || o == ASG MOD ) {
+               r->in.op = FREE;
+               ncopy(p, l);
+               l->in.op = FREE;
+               }
+       else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
+               /* no side effects */
+               tfree(l);
+               ncopy(p, r);
+               r->in.op = FREE;
+               p->tn.lval = result;
+               }
+       else {
+               if( o == ASG DIV )
+                       p->in.op = ASSIGN;
+               else {
+                       p->in.op = COMOP;
+                       r->tn.type = INT;
+                       }
+               r->tn.lval = result;
+               }
+       if( logop(o) )
+               p->in.type = INT;
+
+       return (1);
+       }
 
 struct functbl {
        int fop;
 
 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( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
+               /* 'J' in zzzcode() -- assumes DIV or MOD operations */
+               /* save a subroutine call -- use at most 5 instructions */
+               return;
+       if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
+               /* optim2() will modify the op into an ordinary int op */
+               return;
        if( asgop( o ) ) {
        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;
 
@@ -964,9 +1890,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;
@@ -1017,6 +1943,7 @@ fixpre(p) NODE *p; {
        if( ty != LTYPE ) fixpre( p->in.left );
 }
 
        if( ty != LTYPE ) fixpre( p->in.left );
 }
 
+/*ARGSUSED*/
 NODE * addroreg(l) NODE *l;
                                /* OREG was built in clocal()
                                 * for an auto or formal parameter
 NODE * addroreg(l) NODE *l;
                                /* OREG was built in clocal()
                                 * for an auto or formal parameter
@@ -1027,6 +1954,7 @@ NODE * addroreg(l) NODE *l;
                                 */
 {
        cerror("address of OREG taken");
                                 */
 {
        cerror("address of OREG taken");
+       /*NOTREACHED*/
 }
 
 # ifndef ONEPASS
 }
 
 # ifndef ONEPASS
@@ -1035,8 +1963,27 @@ 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 */
+       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 );
        }
        walkf( p, optim2 );
        }