P8000/WEGA/contrib/lcc/cmd/comp/common/optim.c

989 lines
21 KiB
C

# include "mfile1.h"
#ifndef CCC
#define CCC 0xb
#endif
# define ISCON(p) (p->in.op==ICON)
int opdebug = 0;
NODE *doptim();
NODE *
aadjust( p, aaaadj )
register NODE *p;
OFFSZ aaaadj;
{
/* try to adjust p by adj bits */
register NODE *q;
register adj;
adj = BITOOR(aaaadj);
switch( p->tn.op )
{
case ICON:
p->tn.lval += adj;
return( p );
default:
/* construct a + node */
mkplus:
return( block( PLUS, p, bcon(adj), p->fn.type,
p->fn.cdim, p->fn.csiz ) );
case PLUS:
q = p->in.right;
if( q->tn.op != ICON ) goto mkplus;
q->tn.lval += adj;
return( p );
case MINUS:
q = p->in.right;
if( q->tn.op != ICON ) goto mkplus;
q->tn.lval -= adj;
return( p );
}
}
adjust( p, adj )
register NODE *p;
register adj;
{
/* handle adjustment of scalars by adj bits */
switch( p->tn.op )
{
case NAME:
case VAUTO:
case VPARAM:
p->tn.lval += BITOOR(adj);
return( 1 );
case STAR:
p->in.left = aadjust( p->in.left, (OFFSZ)adj );
return( 1 );
default:
return( 0 );
}
}
# ifdef NOSIMPSTR
# ifndef MYSIMPSTR
simpstr( d, s )
{
return( STRTY );
}
# endif
# else
TWORD
simpstr( d, s )
{
/* return STRTY if not, and CHAR, INT, SHORT, or LONG if simple */
register sz, al;
sz = tsize( STRTY, d, s );
al = talign( STRTY, s );
if( sz == SZINT && !( al % ALINT) ) return( INT );
else if( sz == SZCHAR && !( al % ALCHAR) ) return( CHAR );
else if( sz == SZLONG && !( al % ALLONG) ) return( LONG );
else if( sz == SZSHORT && !( al % ALSHORT) ) return( SHORT );
return( STRTY );
}
# endif
tydown( p )
NODE *p;
{
/* reflect the type of p downwards, as appropriate */
/* the type is typically getting smaller */
/* returns 1 if it makes a real change */
TWORD t;
NODE *l, *r;
int flag;
if( opdebug )
{
printf( "tydown(%d) called with:\n", p-node );
eprint( p );
}
t = p->tn.type;
if( ISPTR(t) || ISARY(t) ) return(0);
/* work these types down into the tree */
flag = 0;
switch( p->tn.op )
{
case AND:
case OR:
case PLUS:
case MINUS:
case ER:
case COMOP:
if( opdebug )
{
printf( "tydown:\n" );
eprint( p );
}
r = p->in.right;
if( bigsize(r->tn.type) > bigsize(p->tn.type ) )
{
r = makety( r, t, 0, (int) t );
tydown( r );
p->in.right = doptim( r );
if( opdebug )
{
printf( "tydown(%d), after doptim(R):\n",
p-node );
eprint(p);
}
flag = 1;
}
if( p->tn.op == COMOP ) return( flag );
/* FALLTHRU */
case UNARY MINUS:
case COMPL:
l = p->in.left;
if( bigsize(l->tn.type) > bigsize(p->tn.type ) )
{
l = makety( l, t, 0, (int) t );
tydown( l );
p->in.left = doptim( l );
if( opdebug )
{
printf( "tydown(%d), after doptim(L):\n",
p-node );
eprint(p);
}
flag = 1;
}
return(flag);
}
return( 0 ); /* no change */
}
# ifndef MYCONVERT
NODE *
sconvert( p )
register NODE *p;
{
register TWORD t, lt;
register NODE *l;
register o;
/* optimize CONV nodes */
/* the unsigned-ness is ignored */
/* if the CONV involves floats or doubles, retain unless null */
/* if the CONV makes things bigger, retain */
/* if the CONV keeps things the same size, just paint the type */
/* if the CONV makes things smaller, adjust the addressing with
** memory references, and paint the new type
*/
/* if a pointer is being converted, convert as if it were PTRTYPE */
/* finally, if CONV converts a constant, do it in place */
again:
if( opdebug )
{
printf( "sconvert(%d) called:\n", p-node );
eprint( p );
}
if( p->tn.op != CONV ) cerror( "sconvert" );
l = p->in.left;
t = p->tn.type;
lt = l->tn.type;
o = l->tn.op;
if( o == FCON )
{
/* for a floating point const, paint type,
** round when it is output */
if( t == FLOAT || t == DOUBLE ) goto paint;
/* otherwise, convert it to long and treat as long conversion */
l->tn.op = ICON;
l->tn.lval = l->fpn.dval; /* MACHINE-DEPENDENT CONVERSION */
l->tn.rval = NONAME;
goto icon;
}
if( o==CONV && cbigger( l ) )
{
merge:
p->in.left = l->in.left;
l->tn.op = FREE;
tydown( p );
goto again;
}
if( t==FLOAT || t==DOUBLE || t == VOID
|| lt==FLOAT || lt==DOUBLE ) return( p );
if( ISUNSIGNED(t) ) t = DEUNSIGN(t);
if( ISUNSIGNED(lt) ) lt = DEUNSIGN(lt);
if( ISPTR(lt) )
# ifdef MEMONLY
if( o==STAR || o==NAME || o==VAUTO || o==VPARAM )
# endif
lt = PTRTYPE;
if( t == lt ) goto paint;
if( ISPTR(lt) || ISARY(lt) ) return(p);
if( o == ICON )
{
icon:
l->tn.lval = ccast( l->tn.lval, p->tn.type );
paint:
l->tn.type = p->tn.type;
l->fn.csiz = p->fn.csiz;
l->fn.cdim = p->fn.cdim;
p->tn.op = FREE;
if( tydown(l) )
{
l = doptim(l);
}
return( l );
}
if( cbigger(p) ) return( p );
/* p makes things smaller */
if( o==CONV )
{
/* two conversions in a row: the second makes things smaller */
/* make them into one */
goto merge;
}
if( o==STAR || o==NAME || o==VAUTO || o==VPARAM )
{
/* memory reference: determine the adjustment */
# ifdef RTOLBYTES
# ifdef LOWINT
if( lt == LONG ) if( !adjust( l, LOWINT )) cerror( "adj" );
# endif
# else
register adj = 0;
if( lt == LONG ) adj = SZLONG;
else if( lt == INT ) adj = SZINT;
else if( lt == SHORT ) adj = SZSHORT;
else cerror( "sconv:lt 0%o", lt );
if( t == INT ) adj -= SZINT;
else if( t == SHORT ) adj -= SZSHORT;
else if( t == CHAR ) adj -= SZCHAR;
else cerror( "sconv:t 0%o", t );
# ifdef LOWINT
if( lt == LONG ) adj += LOWINT;
# endif
if( adj ) if( !adjust( l, adj ) ) cerror( "adj1" );
# endif
goto paint;
}
/* other cases are where it is computed into a reg; */
/* simply paint the type */
/* must avoid clobbering the type for assignment nodes */
/* however, we must copy (e.g., apply the CONV) for register vars */
/* if( o == REG || asgop(o) ) */
return( p );
/* goto paint; */
}
# endif
NODE *
pvconvert( p )
register NODE *p;
{
/* p is a CONV node; convert */
/* this does something only when the descendent is not a ptr */
register NODE *l;
register int o;
l = p->in.left;
if( ISPTR( l->tn.type ) ) return( clocal(p) );
# ifdef MEMONLY
o = l->tn.op;
if( o==STAR || o==NAME || o==VAUTO || o==VPARAM || o==ICON )
# endif
{
/* optimize this reference */
/* sconvert and optimize to PTRTYPE */
l = makety( l, PTRTYPE, 0, PTRTYPE );
if( l->tn.op == CONV ) l = sconvert( l );
l->tn.type = p->tn.type;
l->fn.cdim = p->fn.cdim;
l->fn.csiz = p->fn.csiz;
p->tn.op = FREE;
p = l;
}
return( clocal(p) );
}
NODE *
fortarg( p )
register 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( STAR, p, NIL );
}
return( optim(p) );
}
/* mapping relationals when the sides are reversed */
short revrel[] =
{
EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT
};
# define REPORT(x) if(opdebug)printf( "optim turns %d into %d\n",(int)(p-node),(int)(x-node));
NODE *
doptim(p)
register NODE *p;
{
/* local optimizations, most of which are machine independent */
/* doptim is called for each node by optim; it assumes that
** the children of p are already optimized
*/
/* p is not a leaf */
register NODE *l, *r, *sp;
register o, i;
register TWORD t;
#ifndef NODBG
if( opdebug )
{
printf("operator %s mit goal 0x%x\n",opst[p->tn.op],p->tn.goal);
printf( "doptim called on:\n" );
eprint(p);
}
#endif
if( (t=BTYPE(p->in.type))==ENUMTY || t==MOETY ) econvert(p);
switch( optype( o = p->tn.op ) )
{
case BITYPE:
r = p->in.right;
/* FALLTHRU */
case UTYPE:
l = p->in.left;
break;
case LTYPE:
/* nothing more to do (after doing the enum stuff) */
return( p );
}
sp = conval( p );
/* return only if conval did something */
if( sp != p ) return( doptim(sp) );
if( (o == PLUS && ISPTR(r->tn.type)) ||
((l->tn.op == ICON || l->tn.op == FCON)
&& (o == MUL || o == OR || o == ER || o == AND))){
commute(p);
l = p->in.left;
r = p->in.right;
}
/* Hier sollte eine Vereinfachung der Pointerarithmetik eingefuegt werden.
D.h. Pointer+/-Long ist schneller als (hinterer Teil Pointer)+/-Int
zu realisieren.
if((o==PLUS||o==ASG PLUS||o==MINUS||o==ASG MINUS||o==INCR||o==DECR) &&
ISPTR(l->tn.type) && r->tn.type==LONG) {
if(r->tn.op==CONV && r->in.left->tn.type < LONG) {
r->tn.op = FREE;
r = r->in.left;
} else
r = makety(r, INT, 0, INT);
p->in.right = r;
}
*/
#ifndef NODBG
if( opdebug )
{
printf( "doptim works on:\n" );
eprint(p);
}
#endif
if(optype(o)==BITYPE) {
if(p->tn.goal==CCC && r->tn.op==FCON
&& r->fpn.dval==0) {
r->tn.op = FREE;
r = bcon(0);
p->in.right = r;
}
if((r->tn.op == ICON && r->tn.lval == 0 && !(ISPTR(r->tn.type)))
|| (r->tn.op == FCON && r->fpn.dval == 0))
switch(o)
{
case PLUS:
case MINUS:
case ASG PLUS:
case ASG MINUS:
/* a + 0.0 or a - 0.0 */
goto or;
case MUL:
/* a * 0 */
free:
l->tn.op = FREE;
p->in.op = FREE;
r->tn.type = p->tn.type;
p = r;
return(p);
case ASG MUL:
/* a *= 0 */
asg: p->in.op = ASSIGN;
o = ASSIGN;
break;
case DIV:
case MOD:
/* a / 0 */
werror("divide by 0, convert to const 0");
goto free;
case ASG DIV:
case ASG MOD:
/* a /= 0 */
werror("divide by 0");
goto asg;
case OR:
case ASG OR:
/* a | 0 and a |= 0 */
or: r->tn.op = FREE;
p->in.op = FREE;
l->tn.type = p->tn.type;
p = l;
return(p);
case AND:
/* a & 0 */
goto free;
case ASG AND:
/* a &= 0 */
goto asg;
}
}
switch(o)
{
case ER:
case ASG ER:
/* a ^ a and a ^= a */
if((optype(l->tn.op)==LTYPE)&&(optype(r->tn.op)==LTYPE)
&& r->tn.op == l->tn.op && r->tn.name == l->tn.name
&& r->tn.lval == l->tn.lval && r->tn.rval == l->tn.rval)
{
p->tn.op = ASSIGN;
r->tn.op = FREE;
r = bcon(0);
r->tn.type = p->tn.type;
if(o == ER) {
er: p->tn.op = FREE;
l->tn.op = FREE;
p = r;
return(p);
}
p->in.right = r;
o = ASSIGN;
}
break;
case OR:
case ASG OR:
if(r->tn.op == ICON && r->tn.lval == -1)
goto er;
break;
case AND:
case ASG AND:
if(r->tn.op == ICON && r->tn.lval == -1) {
and: p->tn.op = FREE;
r->tn.op = FREE;
l->tn.type = p->tn.type;
p = l;
return(p);
}
break;
case DIV:
case MOD:
/* 0 / a */
if((l->tn.op == ICON && l->tn.lval == 0)
|| (l->tn.op == FCON && l->fpn.dval == 0))
goto and;
case ASSIGN:
if(((i = l->tn.op)==VAUTO || i == VPARAM || i == REG ||
i == TEMP || i == NAME)
&& (r->in.op == PLUS || r->in.op == MINUS))
{
sp = r->in.left;
if(sp->tn.op == i && r->in.right->tn.op==ICON &&
!(ISPTR(r->in.right->tn.type)) &&
r->in.right->tn.lval<17&&l->tn.lval==sp->tn.lval
&& l->tn.rval == sp->tn.rval)
{
p->in.op = ASG r->in.op;
p->in.right = r->in.right;
tfree(sp);
r->in.op = FREE;
return(p);
}
}
break;
}
switch(o)
{
case CONV:
/* someday, make pvconvert and sconvert the same */
return( ISPTR(p->tn.type)?pvconvert(p):sconvert(p) );
case ASG PLUS:
case ASG MINUS:
case ASG AND:
case ASG OR:
case ASG ER:
case ASG LS:
case ASG RS:
case ASG MUL:
case ASG DIV:
case ASG MOD:
/* if conversion ops on the lhs, transfer them to the rhs */
t = l->in.type;
/* (CONV A) op= B into A op= (CONV B)
** this only holds if the result depends only on the
** low order part of B (e.g., that part of B that
** is the width of A
** this is not true for /=, %=, or floats */
if( l->tn.op == CONV && t!=FLOAT && t!=DOUBLE
&& o!=ASG DIV && o != ASG MOD )
{
p->in.left = l->in.left;
l->tn.op = FREE;
r = makety( r, p->in.type, p->fn.cdim, p->fn.csiz );
p->in.right = doptim( r );
}
if( !nncon(r) ) break; /* no more optimization */
/* get rid of 0 ops that don't change anything... */
if( !r->tn.lval && (o==ASG PLUS || o==ASG MINUS || o==ASG OR ||
o==ASG ER || o==ASG LS || o==ASG RS) )
{
/* the answer is the lhs */
goto bless;
}
if( r->tn.lval == 1 && (o==ASG MUL || o==ASG DIV) )
{
/* the answer is the lhs */
goto bless;
}
if( (i = ispow2( r->tn.lval ))>=0 && o==ASG MUL )
{
o = p->in.op = ASG LS;
r->tn.lval = i;
}
break;
case LS:
case RS:
if( !nncon(r) || r->tn.lval )
break; /* do nothing */
goto bless; /* shifts by 0 */
case FORTCALL:
p->in.right = fortarg( r );
break;
case UNARY AND:
switch( l->tn.op )
{
case STAR:
/* fake up to use setuleft */
l->tn.op = FREE;
l=l->in.left;
goto setuleft;
case VAUTO:
case VPARAM:
/* the next two lines come from short structs */
case CALL:
case UNARY CALL:
break;
case RNODE:
# ifdef ARGSRET
/* RNODE disappears if structure simple */
if( simpstr( p->fn.cdim, p->fn.csiz ) == STRTY )
{
/* complicated: make it look like first arg */
l->tn.op = VPARAM;
l->tn.lval = BITOOR(ARGINIT);
l->tn.rval = NONAME;
}
break;
#else
# ifdef STATSRET
/* simple structures will disappear */
if( simpstr( p->fn.cdim, p->fn.csiz ) != STRTY ) break;
/* otherwise, make & RNODE into ICON for static area */
l->tn.rval = -strftn;
# else
break; /* & of RNODE is just fine */
#endif
#endif
case NAME:
# ifdef ANDABLE
if( !ANDABLE(l) ) return(p);
# endif
l->tn.op = ICON;
setuleft:
/* set the type of lhs with the type of the top */
l->in.type = p->in.type;
l->fn.cdim = p->fn.cdim;
l->fn.csiz = p->fn.csiz;
p->in.op = FREE;
REPORT(l);
return( l );
default:
cerror( "& error" );
}
break;
case STCALL:
case UNARY STCALL:
/* use l in case return type overwritten */
t = simpstr( l->fn.cdim, l->fn.csiz );
if( t != STRTY )
{
/* take some care to keep the types OK */
/* the type of the return might well have been
** overwritten by (say) a structure reference
*/
/* MAY NOT BE QUITE RIGHT IF TWO FLAVORS OF PTR */
l = p;
p->tn.type = DECREF( p->tn.type );
p = buildtree( UNARY AND, l, NIL );
if( o == STCALL ) l->tn.op = CALL;
else l->tn.op = UNARY CALL;
l->fn.type = l->fn.csiz = t;
l->fn.cdim = 0;
}
break;
case STAR:
if( p->tn.type == STRTY || p->tn.type == UNIONTY )
{
p->tn.op = FREE;
REPORT(l);
return( l );
}
if( l->tn.op == UNARY AND && !callop(l->in.left->tn.op) )
{
/* & of call used in structure optimization */
/* fake up to use setuleft */
l->tn.op = FREE;
l = l->in.left;
goto setuleft;
}
if( l->tn.op != ICON ) break;
l->tn.op = NAME;
goto setuleft;
case MINUS:
if( !nncon(r) ) break;
r->tn.lval = - r->tn.lval;
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( o==r->tn.op || nncon(l) || ( ISCON(l) && !ISCON(r) ) )
{
/* make ops tower to the left, not the right */
/* also, put constants on the right */
sp = l;
l = p->in.left = r;
r = p->in.right = sp;
}
/* do (A + C1) + C2, etc. */
/* the number of special cases is horrifying */
/* many bugs have been found here; this code is very cautious */
/* (A + C1) + C2, where C2 can be a ptr, C1 not */
if( o==PLUS && l->tn.op==PLUS && ISCON(r) &&
nncon(l->in.right) )
{
p->in.left = l->in.left;
l->tn.op = FREE;
l = l->in.right;
r->tn.lval += l->tn.lval;
l->tn.op = FREE;
return( doptim( p ) );
}
/* (A + C1) + C2, where C1 can be a ptr, C2 not */
if( o==PLUS && l->tn.op==PLUS && nncon(r) &&
ISCON(l->in.right) )
{
l->in.right->tn.lval += r->tn.lval;
goto bless; /* return l as the result */
}
/* (A - C1) + C2, where C2 can be a ptr, C1 not */
if( o==PLUS && l->tn.op==MINUS && ISCON(r) &&
nncon(l->in.right) )
{
p->in.left = l->in.left;
l->tn.op = FREE;
l = l->in.right;
r->tn.lval -= l->tn.lval;
l->tn.op = FREE;
return( doptim( p ) );
}
/* (&A)+C */
if( o==PLUS && l->tn.op == UNARY AND && ISCON(r) )
{
switch( l->in.left->tn.op )
{
case NAME:
case VPARAM:
case VAUTO:
l->in.left->tn.lval += r->tn.lval;
goto bless;
}
}
/* change muls to shifts */
if( o==MUL && nncon(r) && (i=ispow2(r->tn.lval))>=0)
{
if( i == 0 )
{
/* multiplication by 1 */
bless:
/* return l, with the type of p */
l = makety( l, p->tn.type, p->fn.cdim,
p->fn.csiz );
r->tn.op = FREE;
p->tn.op = FREE;
/* if a conversion op was added, optimize */
l = doptim( l );
#ifndef NODBG
if( opdebug )
{
printf( "optim replaces op1 (%d) by:\n",
p-node );
eprint(l);
}
#endif
return( l );
}
o = p->in.op = LS;
r->tn.lval = i;
}
/* change +'s of negative consts back to - */
if( o==PLUS && nncon(r) && r->tn.lval<0 )
{
r->tn.lval = -r->tn.lval;
o = p->in.op = MINUS;
}
if( nncon(r) && !r->tn.lval && (o==PLUS||o==MINUS) )
{
/* get rid of add or subtract of 0 */
goto bless;
}
# ifdef PTRLEFT
if( o==PLUS && ISPTR(p->tn.type) && ISPTR(r->tn.type)
# ifdef CONSRIGHT
&& r->tn.op != ICON
# endif
)
{
sp = l;
p->in.left = r;
p->in.right = sp;
}
# endif
# ifdef PTRRIGHT
if( o==PLUS && ISPTR(p->tn.type) && ISPTR(l->tn.type)
# ifdef CONSRIGHT
&& r->tn.op != ICON
# endif
)
{
sp = l;
p->in.left = r;
p->in.right = sp;
}
# endif
break;
case DIV:
if( nncon( r ) && r->tn.lval == 1 ) goto bless;
break;
case EQ:
case NE:
case LT:
case LE:
case GT:
case GE:
case ULT:
case ULE:
case UGT:
case UGE:
if( ISCON(l) && !ISCON(r) )
{
/* exchange operands */
p->in.op = revrel[p->in.op - EQ ];
sp = l;
l = p->in.left = r;
r = p->in.right = sp;
}
break;
case STASG:
if( (t=simpstr( p->fn.cdim, p->fn.csiz ) ) != STRTY )
{
/* rewrite = as simpler */
if( ISPTR(r->tn.type) )
{
r = buildtree( STAR, r, NIL );
r->fn.type = r->fn.csiz = t;
r->fn.cdim = 0;
p->in.right = r = doptim( r );
}
l = buildtree( STAR, l, NIL );
l->fn.type = l->fn.csiz = t;
l->fn.cdim = 0;
p->in.left = l = doptim( l );
p->fn.type = p->fn.csiz = t;
p->fn.cdim = 0;
p->fn.op = ASSIGN;
return( p );
}
case STARG:
if( (t=simpstr( p->fn.cdim, p->fn.csiz ) ) != STRTY )
{
/* rewrite as simpler */
if( ISPTR(l->fn.type) )
{
l = buildtree( STAR, l, NIL );
l->fn.type = l->fn.csiz = t;
l->fn.cdim = 0;
p->in.left = l = doptim( l );
}
p->fn.type = p->fn.csiz = (t==LONG ? LONG : INT);
p->fn.cdim = 0;
p->fn.op = FUNARG;
return( p );
}
# ifdef ENDSTRUCT
p->in.left = aadjust( l, p->stn.stsize );
# endif
break;
}
return(p);
}
NODE *
optim( p )
register NODE *p;
{
register NODE *q;
if( opdebug )
printf("in optim p->tn.op=%s p->tn.type=0x%x\n",opst[p->tn.op],p->tn.type);
if(((p->tn.op == ASG RS) || (p->tn.op == RS)) &&
(p->in.right->tn.op != ICON)) {
q = talloc();
*q = *p;
q->tn.op = UNARY MINUS;
q->in.left = p->in.right;
q->in.right = NIL;
p->in.right = q;
p->tn.op += (LS - RS);
if(p->tn.type==LONG || p->tn.type==ULONG) {
q->in.left = makety(q->in.left,INT,0,INT);
q->tn.type = INT;
}
if(p->tn.type==CHAR) q->tn.type = SHORT;
if(p->tn.type==UCHAR) q->tn.type = USHORT;
if( opdebug )
printf("optim 2. p->tn.type = 0x%x q = 0x%x\n", p->tn.type,q->tn.type);
}
if((p->tn.op==ASG RS||p->tn.op==RS||p->tn.op==ASG LS||p->tn.op == LS)
&&(p->in.right->tn.type!=INT)) {
if(p->in.right->tn.op!=ICON
&&(p->tn.type==LONG||p->tn.type==ULONG))
p->in.right = makety(p->in.right,INT,0,INT);
if( p->in.right->tn.op == ICON &&
(p->in.right->tn.type == CHAR||p->in.right->tn.type == UCHAR||
p->in.right->tn.type == LONG||p->in.right->tn.type == ULONG)){
p->in.right->tn.type = INT;
}
}
switch( optype( p->tn.op ) )
{
case BITYPE:
p->in.right = optim( p->in.right );
/* FALLTHRU */
case UTYPE:
p->in.left = optim( p->in.left );
}
return( doptim( p ) );
}
ispow2( c )
register CONSZ c;
{
register i;
if( c <= 0 || (c&(c-1)) ) return(-1);
for( i=0; c>1; ++i) c >>= 1;
return(i);
}
nncon( p )
register NODE *p;
{
/* is p a constant without a name */
return( p->tn.op == ICON && p->tn.rval == NONAME && !ISPTR(p->tn.type));
}
/* some routines for debugging and tree transformation */
#ifndef MYOFFCON
NODE *
offcon( off, t, d, s )
OFFSZ off;
TWORD t;
{
/* return a node, for structure references, which is suitable for
** being added to a pointer of type t, in order to be off bits offset
** into a structure
*/
register NODE *p;
/* t, d, and s are the type, dimension offset, and size offset */
/* in general they may be necessary for offcon */
p = bcon(0);
p->tn.lval = BITOOR(off);
/* 11.4.
p->fn.type = p->fn.csiz = PTRTYPE;
*/
p->fn.type = p->fn.csiz = INT;
return(p);
}
# endif
bccode()
{
/* called just before executing code */
/* beware: called several times if there is auto. initialization */
/*# ifdef SDB
/* static bcclev;
/* if( blevel != bcclev )
/* {
/* bcclev = blevel;
/* pstab( S_LBRAC, blevel-1 );
/* }
/*# endif
/**/
# ifdef MYBCCODE
MYBCCODE;
# endif
p2bbeg( autooff, regvar );
}