Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1039 lines
25 KiB
Groff

/*
Copyright 1982, 1983
Alcyon Corporation
8716 Production Ave.
San Diego, Ca. 92121
@(#)canon.c 1.15 12/30/83
*/
#include "cgen.h"
#include "cskel.h"
/*
* canon - expression canonicalization
* Top level tree canonicalization. This fixes any bit field
* accesses, then loops on commute and optim until no more
* optimizations are done.
*/
char *canon(tp) /* returns pointer to tree*/
struct tnode *tp; /* pointer to tree to canonicalize*/
{
tp = fixbfield(tp);
do {
sucomp(tp,0,1); /*need Sethy-Ullman's for commute*/
tp = commute(tp); /*commute the tree*/
} while( optim(&tp) ); /*keep trying for optimizations*/
PUTEXPR((cflag>1),"canon return",tp);
return(tp);
}
/* fixbfield - fix bit field operators*/
/* Fixes bit field assignment and normal usage*/
char *fixbfield(tp) /* returns pointer to fixed tree*/
struct tnode *tp; /* pointer to tree*/
{
register struct tnode *btp, *stp;
struct tnode *rhstp, *asgtp;
register short foff, fmask, op, flen;
if( LEAFOP(op=tp->t_op) )
return(tp);
if( ISASGOP(op) && tp->t_left->t_op == BFIELD ) {
tp->t_right = fixbfield(tp->t_right); /* [vlh] 4.0 */
btp = tp->t_left; /*pointer to BFIELD node*/
stp = btp->t_left; /*pointer to son of BFIELD node*/
foff = (btp->t_su>>8) & 0377;
flen = btp->t_su & 0377;
fmask = (1<<flen)-1;
if( tp->t_right->t_op == CINT && (op == ASSIGN || op == EQXOR) ) {
if( op == EQXOR ) {
tp->t_left = stp;
tp->t_right->t_value <<= foff;
return(tp);
}
if( !tp->t_right->t_value ) {
tp->t_op = EQAND;
tp->t_left = stp;
tp->t_right->t_value = ~ (fmask << foff);
return(tp);
}
if( (tp->t_right->t_value & fmask) == fmask ) {
tp->t_op = EQOR;
tp->t_left = stp;
tp->t_right->t_value = fmask << foff;
return(tp);
}
}
if( fmask == -1 )
tp->t_left = stp;
else {
asgtp = tcopy(stp,A_DOPOST); /*for lhs of assign*/
op = tp->t_op;
tp = tp->t_right; /*pointer to expression*/
if( op != ASSIGN ) { /*=op operator?*/
rhstp = tcopy(stp,0);
btp = fixbfield(btp);
tp = tnalloc(op-(EQADD-ADD),INT,0,0,tcopy(btp,A_DOPRE),tp);
}
else
rhstp = tcopy(stp,A_DOPRE); /*for rhs of assign*/
tp = tnalloc(AND,INT,0,0,tp,cnalloc(INT,fmask));
tp = tnalloc(LSH,INT,0,0,tp,cnalloc(INT,foff));
btp = tnalloc(AND,INT,0,0,rhstp,cnalloc(INT,~(fmask<<foff)));
tp = tnalloc(OR,INT,0,0,btp,tp);
tp = tnalloc(ASSIGN,INT,0,0,asgtp,tp);
}
}
else if( op == BFIELD ) {
foff = (tp->t_su>>8) & 0377;
fmask = (1<<(tp->t_su&0377))-1;
tp = tnalloc(RSH,INT,0,0,tp->t_left,cnalloc(INT,foff));
tp = tnalloc(AND,INT,0,0,tp,cnalloc(INT,fmask));
}
else {
tp->t_left = fixbfield(tp->t_left);
if( BINOP(op) )
tp->t_right = fixbfield(tp->t_right);
}
return(tp);
}
/*
* optim - optimize expression tree
* This takes expression tree and performs the following
* translations: folds auto names to accesses off the local
* environment pointer, performs mostly "machine-independent"
* optimizations, such as multiply by zero and one, etc.,
* turns field accesses into and's and or's, etc.
* [vlh] 4.0 added checks for divide/modulos long zero...
* [vlh] 4.0 optimize multiply/divide 1L, add/sub 0L...
* [vlh] 4.1 optimize all long constant expressions which
* previously had integer constant equivilents.
*/
optim(tpp) /* returns pointer to new tree*/
struct tnode **tpp;
{
register struct tnode *ltp, *rtp, *tp;
register char *p;
register short i, changes, op, tmp;
short lconst, tlc;
long cval; /* [vlh] 4.1 handle all integer constants as longs */
tp = *tpp;
if (tp->t_op != STASSIGN && (tp->t_type & ~TYPE)) { /*[vlh]4.2 STASSIGN*/
tp->t_type &= TYPE;
tp->t_type |= POINTER;
}
if( LEAFOP(op=tp->t_op) )
return(0);
lconst = changes = 0;
if( BINOP(op) )
changes += optim(&tp->t_right);
changes += optim(&tp->t_left);
for( ; NOTLEAFOP(op=tp->t_op); changes++ ) {
#ifdef DEBUG
if (oflag>1) printf("optim: op = %d, changes %d\n",op,changes);
#endif
PUTEXPR(oflag,"optim",tp);
*tpp = tp;
ltp = tp->t_left;
if( BINOP(op) ) {
rtp = tp->t_right;
if( tp->t_type == CHAR )
tp->t_type = INT;
p = constant(rtp,&lconst);
}
else
p = constant(ltp,&lconst);
if( p )
cval = (lconst) ? p->t_lvalue : p->t_value; /* [vlh] 4.1 */
switch( op ) {
case ADD:
if( p ) {
if( !cval ) {
tp = ltp;
continue;
}
if( ltp->t_op == ADDR ) {
ltp->t_left->t_offset += cval;
tp = ltp;
continue;
}
}
break;
case ASSIGN:
if( rtp->t_op == ADD && indexreg(rtp->t_left) &&
rtp->t_right->t_op == CINT ) {
ltp = rtp->t_left;
ltp->t_sc = REGOFF;
ltp->t_offset += rtp->t_right->t_value;
tp->t_right = ltp;
tp->t_op = EQADDR;
continue;
}
if (rtp->t_op==LONG2I &&
(rtp->t_left->t_op==LDIV || rtp->t_left->t_op==LMOD)) {
rtp = rtp->t_left;
if(rtp->t_right->t_op == DCLONG) {
if(rtp->t_right->t_lvalue < 0) break;
if(rtp->t_right->t_lvalue > 0xffff) break;
rtp->t_right->t_op = CINT;
rtp->t_right->t_type = INT;
}
else if(rtp->t_right->t_op == INT2L)
rtp->t_right = rtp->t_right->t_left;
rtp->t_op -= (LDIV - DIV);
tp->t_right = rtp;
continue;
}
case EQSUB: /* [vlh] 4.2 */
case EQADD: /* [vlh] 4.2 */
case EQAND: /* [vlh] 4.2 */
case EQOR: /* [vlh] 4.2 */
if(p && ltp->t_type==CHAR) { /* [vlh] 4.2 */
ctrunc:
if (lconst) {
tmp = rtp->t_lvalue;
rtp->t_op = CINT;
}
else
tmp = rtp->t_value;
if (tmp > 255) {
warning("value assigned to char truncated");
rtp->t_value = tmp & 0xff;
}
else if ( tmp < -128) {
warning("value assigned to char truncated");
rtp->t_value = ((char)(tmp & 0xff));
}
break;
}
break;
case SUB:
if( p ) {
if( !cval ) {
tp = ltp;
continue;
}
tp->t_op = ADD;
SETVAL(lconst,p,-cval);
continue;
}
if( (p=constant(ltp,&tlc)) && CONSTZERO(tlc,p)) {
tp->t_op = UMINUS;
tp->t_left = ltp = rtp;
continue;
} /*0-x = -x*/
break;
case DIV:
case EQDIV:
if( p ) {
if( !cval ) { /*X/0->error*/
error("divide by zero");
tp = rtp;
continue;
}
if( cval == 1 ) {
tp = ltp;
continue;
}
if( cval == -1 ) {
tp->t_op = (tp->t_op == DIV ? UMINUS : EQNEG );
continue;
}
}
if( (p=constant(ltp,&tlc)) && CONSTZERO(lconst,p)) {
tp = ltp;
continue;
}
if( multop(tpp) ) {
tp = *tpp;
continue;
}
break;
case EQMOD:
case MOD:
if( p ) {
if( !cval ) { /*X%0->error*/
error("modulus by zero");
tp = rtp;
continue;
}
if( cval == 1 ) { /*X%1->0*/
SETVAL(lconst,p,0);
if (op == EQMOD) /*[vlh] 4.0*/
tp->t_op = ASSIGN;
else
tp = rtp;
continue;
}
}
if( (p=constant(ltp,&tlc)) && CONSTZERO(lconst,p)) {
tp = ltp;
continue;
}
if( multop(tpp) ) {
tp = *tpp;
continue;
}
break;
case MULT:
case EQMULT:
if( p ) {
/* Don't do this optimization !!! case: 0 * f()
if( !cval ) {
if (op == EQMULT)
tp->t_op = ASSIGN;
else
tp = rtp;
continue;
} Problem: side effects of object multiplied with !!!
*/
if( cval == 1L ) {
tp = ltp;
continue;
}
if( cval == -1L ) {
tp->t_op = (tp->t_op == MULT ? UMINUS : EQNEG);
continue;
}
}
if( multop(tpp) ) {
tp = *tpp;
continue;
}
break;
case EQUALS:
case NEQUALS:
if( p && ((i=onebit(cval)) >= 0) && ltp->t_op == AND &&
(rtp=constant(ltp->t_right,&tlc)))
if ((!tlc && i == onebit((long)rtp->t_value)) ||
(tlc && i == onebit(rtp->t_lvalue))) {
tp->t_op = invrel[tp->t_op-EQUALS];
p->t_value = 0;
p->t_op = CINT; /* assure const short on bit value... */
continue;
}
break;
case GREATEQ:
if( p && !cval && UNSIGN(ltp->t_type) ) {
SETVAL(lconst,p,1);
tp = p;
continue;
}
break;
case LESS:
if( p && !cval && UNSIGN(ltp->t_type) ) {
tp = p;
continue;
}
break;
case AND:
if( p ) {
/* Don't do this optimization !!! case: 0 & f()
if( !cval ) {
tp = rtp;
continue;
} Problem: side effects of object anded with !!!
*/
if( cval == -1L ) {
tp = ltp;
continue;
}
}
break;
case OR:
if( p ) {
if( !cval ) {
tp = ltp;
continue;
}
if( cval == -1 ) {
tp = rtp;
continue;
}
}
break;
case EQXOR:
case XOR:
if( p ) {
if( !cval ) {
tp = ltp;
continue;
}
if( cval == -1 ) {
tp->t_op = (tp->t_op == XOR ? COMPL : EQNOT);
continue;
}
if(ltp->t_type==CHAR) /* [vlh] 4.2 */
goto ctrunc;
}
break;
case LSH:
case EQLSH:
if(tp->t_type==LONG && rtp->t_op==INT2L &&
UNSIGN(rtp->t_left->t_type)) {
tp->t_right = rtp->t_left;
continue;
}
case RSH:
case EQRSH:
if( p ) {
if( !cval ) {
tp = ltp;
continue;
}
if( p != rtp ) {
tp->t_right = p;
continue;
}
}
break;
case ADDR:
if( ltp->t_op == INDR ) {
tp = ltp->t_left;
continue;
}
if( ltp->t_op == SYMBOL && ltp->t_sc == REGOFF ) {
tp->t_op = ADD;
tp->t_right = cnalloc(INT,(short)ltp->t_offset);
ltp->t_type = tp->t_type;
ltp->t_sc = REGISTER;
ltp->t_offset = 0;
continue;
}
break;
case INDR:
p = ltp->t_left;
switch( ltp->t_op ) {
case ADDR:
tp = p;
continue;
case CINT:
tp = snalloc(tp->t_type,CINDR,(long)ltp->t_value,0,0);
continue;
case CLONG:
tp = snalloc(tp->t_type,CLINDR,ltp->t_lvalue,0,
ltp->t_lvalue.loword);
continue;
case CFLOAT: /* [vlh] 3.4 */
tp = snalloc(tp->t_type,CFINDR,ltp->t_lvalue,0,
ltp->t_lvalue.loword);
continue;
case SYMBOL:
if( indexreg(ltp) ) {
ltp->t_sc = REGOFF;
ltp->t_type = tp->t_type;
ltp->t_offset = 0;
tp = ltp;
continue;
}
break;
case ADD:
if (p->t_op==SYMBOL && p->t_sc==REGOFF &&
(rtp=constant(ltp->t_right,&tlc)) &&
!tlc && NOTPOINTER(p->t_type) ) {
p->t_offset += rtp->t_value;
tp = p;
continue;
} /* [vlh] 4.2 long constant not valid offset !!!! */
if( indexreg(p) ) {
if((rtp=constant(ltp->t_right,&tlc)) && !tlc){
/*
* This combines an address register and a constant into a register
* offset. This relies on 68000 Addressing scheme somewhat.
*/
p->t_sc = REGOFF;
p->t_type = tp->t_type;
p->t_offset += rtp->t_value;
tp = p;
continue;
}
if( !lflag && ltp->t_right->t_op == ADDR ) {
/*
* We can fold *(An+&expr) into *(&expr(An)), but note that &expr
* must be 16 bits for 68000, hence we can only do this if short
* addresses are enabled. Note that the storage classes are mapped:
* EXTERNAL->EXTOFF, STATIC->STATOFF, REGISTER->REGOFF
*/
ltp = ltp->t_right->t_left;
ltp->t_sc += (EXTOFF-EXTERNAL);
ltp->t_type = tp->t_type;
tp = ltp;
continue;
}
}
break;
/*
* --X and X++ can be folded into -(An) and (An)+ 68000 instructions
*/
case PREDEC:
case POSTINC:
if( indexreg(p) && ltp->t_type == p->t_type ) {
p->t_op = (ltp->t_op == PREDEC ? AUTODEC : AUTOINC);
p->t_type = tp->t_type;
tp = p;
continue;
}
} /* INDR switch... */
break;
case NOT:
if( RELOP(ltp->t_op) ) { /*!(X>Y)->X<=Y*/
tp = ltp;
tp->t_op = invrel[tp->t_op-EQUALS];
continue;
}
break;
case UMINUS:
case COMPL:
if( tp->t_type == CHAR )
tp->t_type = INT;
if( tp->t_op == ltp->t_op ) {
tp = ltp->t_left;
continue;
}
if( ltp->t_op == INT2L ) { /*~(INT2L X)->INT2L (~X)*/
ltp->t_op = tp->t_op;
tp->t_op = INT2L;
ltp->t_type = INT;
continue;
}
if(ltp->t_op==LONG2I) { /*[vlh] 4.2 ~(LONG2I X)->LONG2I (~X)*/
ltp->t_op = tp->t_op;
tp->t_op = LONG2I;
ltp->t_type = LONG;
continue;
}
break;
case INT2L:
if( ltp->t_op == MULT ) { /*INT2L (X*Y)->X*Y*/
ltp->t_type = (ltp->t_type&(~TYPE))|LONG;
tp = ltp;
continue;
}
break;
} /* end of switch */
if(!ccexpr(tpp))
break;
tp = *tpp;
}
PUTEXPR(oflag,"optim exit",tp);
*tpp = tp;
return(changes);
}
/*
* commute - commutes expression tree to canonical form
* This sorts commutable expression trees so that the most
* difficult expression is the left-most operand. Note that
* canon assumes that commute has placed constant operands in
* the right sub-tree. This also swaps relationals so that the
* most difficult expression is on the left.
*/
char *commute(tp) /* returns commuted expression tree*/
struct tnode *tp;
{
struct tnode *clist[20], *plist[19];
register struct tnode **p, **q, *s;
struct tnode **plp, **clp;
register short op;
if( RELOP(op=tp->t_op) ) {
s = tp->t_left;
if( harder(tp->t_right,s) ) {
PUTEXPR(oflag,"swaprel",tp);
tp->t_op = swaprel[op-EQUALS];
tp->t_left = tp->t_right;
tp->t_right = s;
}
}
if( COMMOP(op) ) {
PUTEXPR(oflag,"commute",tp);
clp = clist;
plp = plist;
addtree(tp,&clp,&plp); /*collect comm. expressions*/
/*
* see if any sub-trees can also be commuted (with different operator)
*/
clp--;
plp--;
for( p = clist; p <= clp; p++ )
*p = commute(*p);
/*
* this sorts the expressions in decreasing order of Sethy-Ullman
* values.
*/
for( p = clist; p <= clp; p++ ) {
for( q = p; q <= clp; q++ ) {
if( harder(*q,*p) ) {
s = *q;
*q = *p;
*p = s;
}
}
}
/*
* Now, we start at the end of the list and collect any constants
* if possible.
*/
for( q = clp, p = plp; p > plist; p-- ) {
s = *p;
s->t_right = *q;
s->t_left = *--q;
if( ccexpr(p) ) {
clp--;
plp--;
*q = *p; /*[vlh]*/
}
}
/*
* this takes the sorted sub-expression pointers and the pointers
* to the commutable operator nodes (plist) and structures the
* tree so that the left sub-expression is the most complex. The
* code generation scheme is very sensitive to this...
*/
q = clist;
p = plist;
s = *q++;
while( p <= plp ) {
(*p)->t_left = s;
s = *p++;
s->t_right = *q++;
if(!LONGORPTR(s->t_type)) {
if( LONGORPTR(s->t_right->t_type) )
s->t_type = s->t_right->t_type;
else if( LONGORPTR(s->t_left->t_type) )
s->t_type = s->t_left->t_type;
}
}
tp = s;
PUTEXPR(oflag,"after commute",tp);
}
else if( BINOP(op) ) {
tp->t_left = commute(tp->t_left);
tp->t_right = commute(tp->t_right);
}
else if( UNARYOP(op) )
tp->t_left = commute(tp->t_left);
return(tp);
}
/*
* harder - test one sub-expression for being "harder" than another
* This requires some special finagling for registers. The reason
* for this is that the code skeletons produce better code if the
* register is on the left. Also note that allowing an address
* register on the right can have disastrous effects for AND and OR.
* The basic poshort is: don't mess with this routine unless you're
* 100% sure you understand the ramifications...
*/
harder(tp,ntp) /* returns 1 if tp > ntp, else 0*/
struct tnode *tp;
struct tnode *ntp;
{
short lconst;
if( ntp->t_su == SU_VHARD )
return(0);
if( tp->t_su == SU_VHARD )
return(1);
if( ISREG(ntp) )
return(0);
if( ISREG(tp) )
return(1);
if( constant(ntp,&lconst) ) /* [vlh] */
return(1);
if( constant(tp,&lconst) ) /* [vlh] */
return(0);
return( tp->t_su > ntp->t_su );
}
/*
* addtree - collect commutable sub-trees for commute
* This recurses down the sub-trees looking for groups of
* commutable operators. It collects the sub-trees and their
* parent nodes for commute.
*/
addtree(tp,clist,plist) /* returns pointer to clist*/
struct tnode *tp; /* pointer to tree*/
struct tnode ***clist; /* commutable sub-trees*/
struct tnode ***plist; /* parent nodes of sub-trees*/
{
register struct tnode ***p, ***c;
c = clist;
p = plist;
if( tp->t_op == tp->t_left->t_op )
addtree(tp->t_left,c,p);
else
*(*c)++ = tp->t_left;
if( tp->t_op == tp->t_right->t_op )
addtree(tp->t_right,c,p);
else
*(*c)++ = tp->t_right;
*(*p)++ = tp;
}
/* constant - test for tree being a constant node*/
char *
constant(tp,lconst) /* returns 0 or ptr to const node*/
struct tnode *tp; /* pointer to tree*/
short *lconst;
{
if (tp->t_op == CLONG) { /* [vlh] */
*lconst = 1;
return(tp);
}
else
*lconst = 0;
if( tp->t_op == CINT )
return(tp);
if(tp->t_op==INT2L && (tp->t_left->t_op==CINT||tp->t_left->t_op==CLONG)) {
tp->t_op = CLONG;
tp->t_type = LONG;
if (tp->t_left->t_op == CLONG)
tp->t_lvalue = tp->t_left->t_lvalue;
else
tp->t_lvalue = tp->t_left->t_value;
*lconst = 1;
return(tp);
}
if (tp->t_op==LONG2I && (tp->t_left->t_op==CINT||tp->t_left->t_op==CLONG)) {
tp->t_op = CINT;
tp->t_type = INT;
if (tp->t_left->t_op == CLONG)
tp->t_value = tp->t_left->t_lvalue;
else
tp->t_value = tp->t_left->t_value;
return(tp);
}
return(0);
}
/* indexreg - returns whether node is an address register*/
/* For 68000, must be an A register*/
indexreg(tp) /* returns whether node is A reg*/
struct tnode *tp; /* pointer to tree*/
{
if( tp->t_op == SYMBOL && tp->t_sc == REGISTER &&
!(ISDREG(tp->t_reg)) )
return(1);
return(0);
}
/* ccexpr - compute constant expression*/
/* Evaluates constant expressions, including ?: and relationals*/
ccexpr(tpp) /* returns 1 if changes, 0 otherwise*/
struct tnode **tpp; /* pointer to tree*/
{
register struct tnode *ltp, *rtp, *tp;
register short op, anyfloat; /*[vlh] 3.4 anyfloat*/
register long rval, lval;
short anylong, lconst;
tp = *tpp;
op = tp->t_op;
if( LEAFOP(op) )
return(0);
anylong = anyfloat = 0;
ltp = tp->t_left;
if ( ltp->t_op == CFLOAT) { /* [vlh] 3.4 */
lval = ltp->t_lvalue;
anyfloat++;
}
else if( ltp = constant(ltp,&anylong) ) /* [vlh] 4.1 */
lval = (anylong) ? ltp->t_lvalue : ltp->t_value;
else
return(0);
if( BINOP(op) ) {
rtp = tp->t_right;
if( op == QMARK ) {
ltp = rtp->t_left;
rtp = rtp->t_right;
if( lconst && (ltp->t_op != CLONG || rtp->t_op != CLONG))
return(0); /* [vlh] 4.1 */
if( !lconst && (ltp->t_op != CINT || rtp->t_op != CINT ))
return(0);
if (lconst) /* [vlh] 4.1 */
ltp->t_lvalue = (lval) ? ltp->t_lvalue : rtp->t_lvalue;
else
ltp->t_value = (lval) ? ltp->t_value : rtp->t_value;
*tpp = ltp;
return(1);
}
if (rtp->t_op == CFLOAT) { /* [vlh] 3.4 */
anyfloat++;
rval = rtp->t_lvalue;
switch (op) {
case MULT:
case DIV:
case MOD:
case LSH:
case RSH:
case XOR:
return(0);
}
}
else if( rtp = constant(rtp,&lconst) ) {
rval = (lconst) ? rtp->t_lvalue : rtp->t_value;
anylong += lconst;
}
else
return(0);
}
switch( op ) {
case ADD:
lval += rval;
break;
case SUB:
lval -= rval;
break;
case MULT:
lval *= rval;
break;
case DIV:
lval /= rval;
break;
case MOD:
lval %= rval;
break;
case RSH:
lval >>= rval;
break;
case LSH:
lval <<= rval;
break;
case XOR:
lval ^= rval;
break;
case GREAT:
lval = (lval>rval);
break;
case GREATEQ:
lval = (lval>=rval);
break;
case LESS:
lval = (lval<rval);
break;
case LESSEQ:
lval = (lval<=rval);
break;
case UMINUS:
lval = -lval;
break;
case COMPL:
lval = ~lval;
break;
case NOT:
lval = !lval;
break;
case OR:
lval |= rval;
break;
case AND:
lval &= rval;
break;
default:
return(0);
} /* end of switch */
if( anylong )
ltp = lcnalloc(LONG,lval);
else if ( anyfloat )
ltp = fpcnalloc(FLOAT,lval);
else
ltp->t_value = lval;
*tpp = ltp;
return(1);
}
/**
* power2 - do multiply and divide by powers of two
* This changes multiplies and divides by constant powers of two
* to shifts.
**/
power2(tpp) /* returns 0 if not power of two*/
struct tnode **tpp; /* pointer to expression tree*/
{
register char *p;
register short op;
register struct tnode *tp;
short lconst;
short value;
tp = *tpp;
if( p = constant(tp->t_right,&lconst) ) {
if(!lconst && ((value=onebit((long)p->t_value)) < 0) )
return(0);
if(lconst && ((value=onebit(p->t_lvalue)) < 0) )
return(0);
op = tp->t_op;
/* THIS FIX MUST WAIT FOR UNSIGNED LONG IMPLEMENTATION...........*/
if (op!=MULT && op!=EQMULT && !UNSIGN(tp->t_left->t_type))
return(0);
switch( op ) {
case MULT:
op = LSH;
break;
case EQMULT:
op = EQLSH;
break;
case DIV:
op = RSH;
break;
case EQDIV:
op = EQRSH;
break;
case MOD:
op = AND;
if (!lconst)
value = p->t_value - 1;
else
value = p->t_lvalue - 1;
break;
case EQMOD:
op = EQAND;
if (!lconst)
value = p->t_value - 1;
else
value = p->t_lvalue - 1;
break;
default:
return(0);
} /* end of case */
tp->t_op = op;
if (lconst)
p->t_op = CINT; /* [vlh] 4.1 assure constant int.... */
p->t_value = value;
#ifdef DEBUG
if (oflag>1) printf("lconst %d op = %d value = %d\n",lconst,op,value);
#endif
return(1);
}
return(0);
}
/* chklong - check for tree being a long*/
chklong(tp) /* returns 1 if long, 0 otherwise*/
struct tnode *tp; /* pointer to expression tree*/
{
if( tp->t_op == CLONG )
return(1);
return( LONGORPTR(tp->t_type) );
}
/**
* multop - handle multiplicative operators
* This checks for powers of two optimizations, then for a hard
* long operation.
**/
multop(tpp) /* returns ptr to expression tree*/
struct tnode **tpp; /* pointer to expression tree*/
{
register struct tnode *tp, *rtp;
register short change;
tp = *tpp;
PUTEXPR(oflag,"multop",*tpp);
if (change = power2(tpp))
tp = *tpp;
if( chklong(rtp=tp->t_right) || chklong(tp->t_left) )
switch( tp->t_op ) {
case MULT:
tp->t_op = LMULT;
break;
case DIV:
case MOD:
if( chklong(tp->t_left) ) { /*only hard if divisor is long*/
if(rtp->t_type == INT) /*only occurs if changed !!*/
break;
tp->t_op += (LDIV-DIV);
if( rtp->t_op == CLONG )
rtp->t_op = DCLONG;
}
break;
case EQDIV:
case EQMOD:
if( !chklong(rtp) )
break;
if( rtp->t_op == CLONG )
rtp->t_op = DCLONG;
case EQMULT:
tp->t_op += (LMULT-EQMULT);
*tpp = tnalloc(ASSIGN,tp->t_type,0,0,tcopy(tp->t_left,A_DOPOST),
tcopy(tp,A_DOPRE));
change++;
break;
} /* end of case... */
PUTEXPR(oflag,"after multop ",tp);
return(change);
}
/* onebit - returns whether constant is power of two (one bit on)*/
onebit(val) /* returns bit number or -1*/
long val; /* [vlh] int->long, constant value to check*/
{
register short i;
for( i = 31; val != 0; val <<= 1, i-- )
if( val & 0x80000000 )
break;
if (val != 0x80000000)
return(-1);
return(i);
}