static char *sccsid
="@(#)optim.c 4.7 (Berkeley) 1/8/86";
# 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)
/* fortran function arguments */
p
->in
.left
= fortarg( p
->in
.left
);
p
->in
.right
= fortarg( p
->in
.right
);
while( ISPTR(p
->in
.type
) ){
p
= buildtree( UNARY MUL
, p
, NIL
);
/* mapping relationals when the sides are reversed */
short revrel
[] ={ EQ
, NE
, GE
, GT
, LE
, LT
, UGE
, UGT
, ULE
, ULT
};
optim(p
) register NODE
*p
; {
/* local optimizations, most of which are probably machine independent */
if( (t
=BTYPE(p
->in
.type
))==ENUMTY
|| t
==MOETY
) econvert(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
);
p
->in
.right
= fortarg( p
->in
.right
);
if( LO(p
) != NAME
|| !andable(p
->in
.left
) ) return(p
);
/* 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
;
if( LO(p
) != ICON
) break;
if( !nncon(p
->in
.right
) ) break;
/* 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 */
/* now, put together again */
if(o
== PLUS
&& LO(p
) == MINUS
&& RCON(p
) && RCON(p
->in
.left
) &&
conval(p
->in
.right
, MINUS
, p
->in
.left
->in
.right
)){
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
) ){
else if( LCON(p
) && RCON(p
) &&
conval( p
->in
.left
, o
, p
->in
.right
) ){
p
->in
.left
= makety( p
->in
.left
, p
->in
.type
, p
->fn
.cdim
, p
->fn
.csiz
);
return( clocal( p
->in
.left
) );
/* 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 */
/* c2 will turn 'i << 1' into 'i + i' for us */
p
->in
.op
= (asgop(o
) ? ASG LS
: LS
);
p
->in
.right
->in
.type
= p
->in
.right
->fn
.csiz
= INT
;
/* change +'s of negative consts back to - */
if( o
==PLUS
&& nncon(p
->in
.right
) && RV(p
)<0 ){
/* Operations with zero */
if( nncon(p
->in
.right
) && RV(p
) == 0 ) {
if( o
== MUL
|| o
== ASG MUL
||
o
== AND
|| o
== ASG AND
) {
else if( optype(LO(p
)) == LTYPE
) {
p
->in
.op
= COMOP
; /* side effects */
else if( o
== PLUS
|| o
== MINUS
||
o
== ASG PLUS
|| o
== ASG MINUS
||
if( !ISUNSIGNED(p
->in
.left
->in
.type
) )
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
;
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;
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
;
if( nncon(p
->in
.right
) ){
if( RV(p
) == 0 ) uerror("modulus of zero");
else if( RV(p
) == 1 ){ /* mod by one gives zero */
else if( optype(LO(p
)) == LTYPE
) {
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
);
p
->in
.left
= p
->in
.right
;
p
->in
.op
= revrel
[p
->in
.op
- EQ
];
if( c
<= 0 || (c
&(c
-1)) ) return(-1);
for( i
=0; c
>1; ++i
) c
>>= 1;