#ifndef lint static char *sccsid ="@(#)optim.c 4.7 (Berkeley) 1/8/86"; #endif lint # include "pass1.h" # define SWAP(p,q) {sp=p; p=q; q=sp;} # define RCON(p) (p->in.right->in.op==ICON) # define RO(p) p->in.right->in.op # define RV(p) p->in.right->tn.lval # define LCON(p) (p->in.left->in.op==ICON) # define LO(p) p->in.left->in.op # define LV(p) p->in.left->tn.lval /* is p a constant without a name */ # define nncon(p) ((p)->in.op == ICON && (p)->tn.rval == NONAME) int oflag = 0; NODE * fortarg( p ) NODE *p; { /* fortran function arguments */ if( p->in.op == CM ){ p->in.left = fortarg( p->in.left ); p->in.right = fortarg( p->in.right ); return(p); } while( ISPTR(p->in.type) ){ p = buildtree( UNARY MUL, p, NIL ); } return( optim(p) ); } /* mapping relationals when the sides are reversed */ short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; NODE * optim(p) register NODE *p; { /* local optimizations, most of which are probably machine independent */ register o, ty; NODE *sp; int i; TWORD t; if( (t=BTYPE(p->in.type))==ENUMTY || t==MOETY ) econvert(p); if( oflag ) return(p); ty = optype( o=p->in.op); if( ty == LTYPE ) return(p); if( ty == BITYPE ) p->in.right = optim(p->in.right); p->in.left = optim(p->in.left); /* collect constants */ switch(o){ case SCONV: case PCONV: return( clocal(p) ); case FORTCALL: p->in.right = fortarg( p->in.right ); break; case UNARY AND: if( LO(p) != NAME || !andable(p->in.left) ) return(p); LO(p) = ICON; setuleft: /* paint over the type of the left hand side with the type of the top */ p->in.left->in.type = p->in.type; p->in.left->fn.cdim = p->fn.cdim; p->in.left->fn.csiz = p->fn.csiz; p->in.op = FREE; return( p->in.left ); case UNARY MUL: if( LO(p) != ICON ) break; LO(p) = NAME; goto setuleft; case MINUS: if( !nncon(p->in.right) ) break; RV(p) = -RV(p); o = p->in.op = PLUS; case MUL: case PLUS: case AND: case OR: case ER: /* commutative ops; for now, just collect constants */ /* someday, do it right */ if( nncon(p->in.left) || ( LCON(p) && !RCON(p) ) ) SWAP( p->in.left, p->in.right ); /* make ops tower to the left, not the right */ if( RO(p) == o ){ NODE *t1, *t2, *t3; t1 = p->in.left; sp = p->in.right; t2 = sp->in.left; t3 = sp->in.right; /* now, put together again */ p->in.left = sp; sp->in.left = t1; sp->in.right = t2; p->in.right = t3; } if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->in.left) && conval(p->in.right, MINUS, p->in.left->in.right)){ zapleft: RO(p->in.left) = FREE; LO(p) = FREE; p->in.left = p->in.left->in.left; } if( RCON(p) && LO(p)==o && RCON(p->in.left) && conval( p->in.right, o, p->in.left->in.right ) ){ goto zapleft; } else if( LCON(p) && RCON(p) && conval( p->in.left, o, p->in.right ) ){ zapright: RO(p) = FREE; p->in.left = makety( p->in.left, p->in.type, p->fn.cdim, p->fn.csiz ); p->in.op = FREE; return( clocal( p->in.left ) ); } /* FALL THROUGH */ case ASG MUL: /* change muls to adds or shifts */ if( (o == MUL || o == ASG MUL) && nncon(p->in.right) && (i=ispow2(RV(p)))>=0){ if( i == 0 ) /* multiplication by 1 */ goto zapright; /* c2 will turn 'i << 1' into 'i + i' for us */ else { p->in.op = (asgop(o) ? ASG LS : LS); o = p->in.op; p->in.right->in.type = p->in.right->fn.csiz = INT; RV(p) = i; } } /* change +'s of negative consts back to - */ if( o==PLUS && nncon(p->in.right) && RV(p)<0 ){ RV(p) = -RV(p); o = p->in.op = MINUS; } /* FALL THROUGH */ case ASG AND: case ASG PLUS: case ASG MINUS: case RS: case LS: /* Operations with zero */ if( nncon(p->in.right) && RV(p) == 0 ) { if( o == MUL || o == ASG MUL || o == AND || o == ASG AND ) { if( asgop(o) ) p->in.op = ASSIGN; else if( optype(LO(p)) == LTYPE ) { p->in.op = FREE; LO(p) = FREE; p = p->in.right; } else p->in.op = COMOP; /* side effects */ } else if( o == PLUS || o == MINUS || o == ASG PLUS || o == ASG MINUS || o == OR || o == ER || o == LS || o == RS ) goto zapright; } if( o != LS && o != RS ) break; /* FALL THROUGH */ case ASG RS: case ASG LS: if( !ISUNSIGNED(p->in.left->in.type) ) break; if( p->in.right->in.op == ICON && p->in.right->tn.lval < 0 ) { /* * Technically negative shifts are illegal * but we can support them, at least with * constants; you take potluck with variables. */ p->in.right->tn.lval = -p->in.right->tn.lval; switch( o ){ case LS: p->in.op = RS; break; case ASG LS: p->in.op = ASG RS; break; case RS: p->in.op = LS; break; case ASG RS: p->in.op = ASG LS; break; } } break; case ASG DIV: case DIV: if( nncon( p->in.right ) ){ if( RV(p) == 0 ) uerror("division by zero"); else if( RV(p) == 1 ) goto zapright; /* Unsigned division by a power of two */ else if( (i=ispow2(RV(p)))>=0 && (ISUNSIGNED(p->in.left->in.type) || ISUNSIGNED(p->in.right->in.type)) ){ p->in.op = (asgop(o) ? ASG RS : RS); p->in.right->in.type = p->in.right->fn.csiz = INT; RV(p) = i; } } break; case ASG MOD: case MOD: if( nncon(p->in.right) ){ if( RV(p) == 0 ) uerror("modulus of zero"); else if( RV(p) == 1 ){ /* mod by one gives zero */ RV(p) = 0; if( asgop(o) ) p->in.op = ASSIGN; else if( optype(LO(p)) == LTYPE ) { p->in.op = FREE; LO(p) = FREE; p = p->in.right; } else p->in.op = COMOP; /* side effects */ } else if ((i=ispow2(RV(p)))>=0 && (ISUNSIGNED(p->in.left->in.type) || ISUNSIGNED(p->in.right->in.type)) ){ /* Unsigned mod by a power of two */ p->in.op = (asgop(o) ? ASG AND : AND); RV(p)--; } } break; case EQ: case NE: case LT: case LE: case GT: case GE: case ULT: case ULE: case UGT: case UGE: if( !LCON(p) ) break; /* exchange operands */ sp = p->in.left; p->in.left = p->in.right; p->in.right = sp; p->in.op = revrel[p->in.op - EQ ]; break; } return(p); } ispow2( c ) CONSZ c; { register i; if( c <= 0 || (c&(c-1)) ) return(-1); for( i=0; c>1; ++i) c >>= 1; return(i); }