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 7b5a8d9..96dc187 100644 (file)
@@ -1,5 +1,5 @@
 # ifndef lint
 # ifndef lint
-static char *sccsid ="@(#)local2.c     1.17 (Berkeley) %G%";
+static char *sccsid ="@(#)local2.c     1.28 (Berkeley) %G%";
 # endif
 
 # include "pass2.h"
 # endif
 
 # include "pass2.h"
@@ -13,6 +13,7 @@ int ftlab1, ftlab2;
 
 # 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 );
        }
@@ -190,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 */
@@ -413,6 +414,47 @@ zzzcode( p, c ) register NODE *p; {
                return;
                }
 
                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;
        case 'B':       /* get oreg value in temp register for left shift */
                {
                register NODE *r;
@@ -445,7 +487,7 @@ zzzcode( p, c ) register NODE *p; {
                putchar('\t');
 
        case 'E':       /* INCR and DECR, FOREFF */
                putchar('\t');
 
        case 'E':       /* INCR and DECR, FOREFF */
-               if (p->in.right->tn.lval == 1)
+               if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
                        {
                        putstr( p->in.op == INCR ? "inc" : "dec" );
                        prtype(p->in.left);
                        {
                        putstr( p->in.op == INCR ? "inc" : "dec" );
                        prtype(p->in.left);
@@ -638,10 +680,12 @@ setregs(){ /* set up temporary registers */
        ;
        }
 
        ;
        }
 
+/*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 );
        }
@@ -688,7 +732,6 @@ offset( p, tyl ) register NODE *p; int tyl; {
 
 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
        register NODE *t;
 
 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;
@@ -723,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
@@ -748,9 +794,30 @@ flshape( p ) register NODE *p; {
                (p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
        }
 
                (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; {
@@ -758,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 );
 
@@ -830,12 +897,15 @@ conput( p ) register NODE *p; {
        }
 
 /*ARGSUSED*/
        }
 
 /*ARGSUSED*/
-insput( p ) register NODE *p; {
+insput( p ) NODE *p; {
        cerror( "insput" );
        }
 
        cerror( "insput" );
        }
 
-/*ARGSUSED*/
-upput( p, off ) register NODE *p; int off; {
+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" );
        }
 
@@ -877,7 +947,7 @@ adrput( p ) register NODE *p; {
                        return;
                        }
                if( r == AP ){  /* in the argument region */
                        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 );
                        putstr( "(ap)" );
                        return;
                        printf( CONFMT, p->tn.lval );
                        putstr( "(ap)" );
                        return;
@@ -994,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;
@@ -1080,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 */
@@ -1099,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);
@@ -1107,10 +1180,11 @@ 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:
                /* commute L and R to eliminate complements and constants */
 
        case AND:
                /* commute L and R to eliminate complements and constants */
@@ -1122,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 ) { /* complement 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 */
@@ -1148,7 +1251,7 @@ optim2( p ) register NODE *p; {
 #else
                if( mixtypes(p, l) ) return;
 #endif
 #else
                if( mixtypes(p, l) ) return;
 #endif
-               if( l->in.op == PCONV )
+               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 */
                        return;
 
                /* Only trust it to get it right if the size is the same */
@@ -1180,9 +1283,233 @@ optim2( p ) register NODE *p; {
                        }
                break;
 
                        }
                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;
+               }
+       }
+
+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
 NODE * addroreg(l) NODE *l;
                                /* OREG was built in clocal()
                                 * for an auto or formal parameter
@@ -1236,6 +1563,13 @@ hardops(p)  register NODE *p; {
        return;
 
        convert:
        return;
 
        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 ) ) {
                old = NIL;
                switch( p->in.left->in.op ){
        if( asgop( o ) ) {
                old = NIL;
                switch( p->in.left->in.op ){