# include "mfile2.h" #ifndef RESC4 #define RESC4 0400 #endif # define istnode(p) (p->in.op==REG && istreg(p->tn.rval)) /* ** For God's workes are, like him, all infinite ** And curious search but craftie sin's delight. */ rewcom( p, goal ) NODE *p; { /* find all , ops, move as high as is legal */ /* rewrite p in place; this takes some doing! */ /* while we are at it, take care of setting the goal field */ int o, ty, g1, g2; NODE *l, *r, *ql, *qr; o = p->tn.op; g1 = g2 = NRGS; p->tn.goal = goal; /* special cases for subtrees: ** GENBR has left as Condition codes ** COMOP has left as Effects ** COLON, GENUBR, CM, GENLAB have descendents = node ** CALL, STCALL, FORTCALL has right as Effects ** All others use registers */ switch( o ) { case FREE: cerror( "rewcom(%d) is FREE", p-node ); case GENBR: g1 = CCC; break; case COMOP: g1 = CEFF; g2 = goal; break; case COLON: case GENUBR: case CM: case GENLAB: g1 = g2 = goal; break; case CALL: case STCALL: case FORTCALL: g2 = CEFF; break; } switch( ty = optype(o) ) { case BITYPE: rewcom( r = p->in.right, g2 ); case UTYPE: rewcom( l = p->in.left, g1 ); break; case LTYPE: return; } if( o==COMOP || o==COLON || o==GENLAB ) return; /* look for (A,B) op C and A op (B,C), and rewrite */ /* A,B if A headed by GENBR can't be rewritten */ /* the assumption is that B is executed immediately after A, */ /* and this won't necessarily be true if op is commutative */ if( l->tn.op == COMOP && l->in.left->tn.op != GENBR ) { /* rewrite it... */ /* (A,B) op C => A,(B op C) */ /* also, for unary ops, op (A,B) => A , (op B) */ ql = l->in.left; qr = l->in.right; *l = *p; /* copies op, and other stuff if op is unary */ l->in.left = qr; p->in.right = l; p->in.left = ql; p->tn.op = COMOP; rewcom( p, p->tn.goal ); return; /* must not go on since p is now a COMOP! */ } if( ty == UTYPE ) return; if( r->tn.op == COMOP && r->in.right->tn.op != GENBR ) { /* rewrite, again */ /* A op (B,C) => B,(A op C) */ /* op is not unary now */ ql = r->in.left; qr = r->in.right; *r = *p; p->tn.op = COMOP; p->in.left = ql; r->in.right = qr; rewcom( p, p->tn.goal ); } } rewlhs(p) NODE *p; { /* rewrite x op= y as (x op= y),x */ /* it would be really nice to optimize after doing this . . . */ NODE *q, *t; q = talloc(); *q = *p; t = tcopy( p->in.left ); p->in.left = q; p->in.right = t; p->tn.op = COMOP; return; } rewsto(p) NODE *p; { /* a temp, t, is generated, and p is rewritten as ((t=p),t) */ /* if p has the form x op= A, and x is of the right form, rewrite /* as ((x op= A), x) */ int o, ao; NODE *t, *q; /* probably not perfect for structs: CHECK UP.. */ while( (o=p->tn.op) == COMOP ) p = p->in.right; if( o == TEMP ) return(0); /* nothing to do */ if( o == STARG ) { /* store a structure argument */ /* like storing a usual argument, but we have addresses */ t = talloc(); *t = *p->in.left; /* copy contents, mainly for type, etc. */ q = talloc(); *q = *t; t->tn.op = TEMP; t->tn.lval = freetemp(argsize(p)/SZINT ); t->tn.lval = BITOOR(t->tn.lval); /* t->tn.rval == 0 indicates stack temporary (not register) */ t->tn.rval = 0; t->tn.name = (char *) 0; t->tn.type = TSTRUCT; q->tn.op = UNARY AND; q->in.left = t; /* now, q has & TEMP */ t = talloc(); *t = *p; t->in.left = q; t->in.right = p->in.left; t->tn.op = STASG; /* now, t has (&TEMP) = struct */ p->in.left = talloc(); p->in.left->tn.op = COMOP; p->in.left->in.left = t; p->in.left->in.right = t = talloc(); /* copy q here */ *t = *q; t->in.left = talloc(); *t->in.left = *q->in.left; /* finally, have (&TEMP = struct),(&TEMP) */ /* this should do it: whew! */ if( odebug>1 ) e2print( p ); return( 1 ); } if( odebug>1 ) { e2print( p ); printf( "\nrewritten by rewsto as:\n" ); } if( asgop(o) && o!=INCR && o!=DECR && lhsok( p->in.left ) ) { /* x op= y turns into (x op= y), x */ rewlhs( p ); return( 1 ); } ao = ASG o; if( asgbinop(ao) ) { if( p->in.left->tn.op == TEMP ) { p->tn.op = ao; rewlhs( p ); if( odebug>1 ) e2print( p ); return( 1 ); } } /* to rewrite in place, p becomes a COMOP; rhs is the temp, lsh ** /* is t = p, where p has been converted to the intermediate type */ /* after some debate, the type of the temp will be the type of p */ t = talloc(); *t = *p; /* copy contents, mainly for type, etc. */ q = talloc(); *q = *p; t->tn.op = TEMP; /* see if we can allocate an unused register for the temp */ /* if so rval == 1 && lval == register number */ t->tn.lval = tempreg(&(t->tn.rval), argsize(p)/SZINT, t->tn.type); if (t->tn.lval == 0) { t->tn.rval = 0; /* if not, get one from the stack as usual (rval == 0) - jgh */ t->tn.lval = freetemp(argsize(p)/SZINT ); t->tn.lval = BITOOR(t->tn.lval); } else { t->tn.op = REG; t->tn.lval = 0; } t->tn.name = (char *) 0; q->tn.op = ASSIGN; q->in.left = t; q->in.right = talloc(); *(q->in.right) = *p; /* now, q has (t=p) */ p->in.right = talloc(); *(p->in.right) = *t; p->tn.op = COMOP; p->in.left = q; /* this should do it: whew! */ if( odebug>1 ) e2print( p ); return( 1 ); } iseff( p ) NODE *p; { /* return 1 if p has some side effects, 0 otherwise */ int o; o = p->tn.op; if( callop(o) || asgop(o) ) return( 1 ); switch( optype( o ) ) { case BITYPE: if( iseff( p->in.right ) ) return( 1 ); case UTYPE: return( iseff( p->in.left ) ); } return( 0 ); } NODE * lhsto( p ) NODE *p; { /* find a piece of the LHS to be stored */ /* if found, rewrite tree */ NODE *q; int o; for( q = p->in.left; (o=q->tn.op)!=STAR; q=q->in.left ) { if( optype(o) == LTYPE ) return( (NODE *)0); } /* q is now the * node, if there one */ q = q->in.left; o = q->tn.op; if( optype(o) == LTYPE ) return( (NODE *)0 ); else return( q ); } static int c2bigger( p ) NODE *p; { /* p is a conversion op; does it make things bigger */ register TWORD t, tl; t = p->tn.type; tl = p->in.left->tn.type; if( (t|tl)&TPOINT ) return( 0 ); /* pointers are funny */ if( t&TDOUBLE ) return( 1 ); if( tl&TDOUBLE ) return( 0 ); if( t&TFLOAT ) return( 1 ); if( tl&TFLOAT ) return( 0 ); if( t&(TLONG|TULONG) ) return( 1 ); if( tl&(TLONG|TULONG) ) return( 0 ); if( t&(TINT|TUNSIGNED) ) return( 1 ); if( tl&(TINT|TUNSIGNED) ) return( 0 ); if( t &(TSHORT|TUSHORT) ) return( 1 ); return( 0 ); } NODE * ind2type( p ) register NODE *p; { /* make the type of p be the appropriate type for an argument */ register TWORD t; NODE *q; t = p->tn.type; if( t == TCHAR || t == TSHORT ) t = TINT; else if( t == TUCHAR || t == TUSHORT ) t = TUNSIGNED; else if( t == TFLOAT ) t = TDOUBLE; else return( p ); if( p->tn.op == CONV && c2bigger(p) ) { p->tn.type = t; return( p ); } q = talloc(); q->tn.op = CONV; q->in.left = p; q->in.right = 0; q->tn.name = (char *) 0; q->tn.type = t; q->tn.goal = NRGS; return( q ); } NODE * reweop( p ) register NODE *p; { /* rewrite A op= B as A = A op B */ /* also, rewrite (CONV A) op= B as A = (CONV ( (CONV A) op B ) ) */ /* rewritten in place */ /* on input, the type of the op= equals the type of A */ /* the type of the op node on output is the type of B */ /* the type of the = node on output is the type of A */ register NODE *q, *r, *s, *t; register TWORD ty; if( odebug>1 ) { e2print( p ); printf( "\nrewritten by reweop as:\n" ); } q = talloc(); *q = *p; /* Copy to get type and op info */ r = p->in.right; s = tcopy( p->in.left ); q->in.left = s; /* q->in.right = r, side effect of copy. */ if( p->in.left->tn.op == CONV ) { /* ( CONV (A) ) op= B becomes A = CONV ( CONV(A) op B ) */ /* the op is done to the type of B */ /* the assignment is done to the type of A */ t = p->in.left; ty = t->in.left->tn.type; p->in.left = t->in.left; p->in.right = t; t->in.left = q; /* now, have the tree built; fix the types */ t->tn.type = ty; } else { p->in.right = q; } /* NOTE: no =ops for structures... */ p->tn.op = ASSIGN; q->tn.op = NOASG q->tn.op; p->tn.type = p->in.left->tn.type; q->tn.type = q->in.right->tn.type; if( odebug>1 ) e2print( p ); } rewass( p ) NODE *p; { NODE *q; int o; /* look for =ops to be rewritten */ if( odebug ) { printf( "rewass called with:\n" ); e2print( p ); } o = p->tn.op; if( o == UNARY AND ) { if( p->in.left->tn.op == RNODE ) { /* this should happen only with structure returns */ q = p->in.left; q->tn.op = ICON; *p = *q; q->tn.op = FREE; return(0); /* keep going in costs */ } /* this case should happen only with short structures */ rewsto( p->in.left ); /* & f() has turned into & ( t=f(),t) */ if( odebug ) { printf( "\nrewritten by rewass as:\n" ); e2print( p ); } return(1); } if( !asgop(o) || o==ASSIGN ) { if( o==ASSIGN ) { /* look for funny nodes on lhs */ o = p->in.left->tn.op; if( o==RNODE || o==QNODE || o==SNODE ) { /* force into r0 */ p->in.left->tn.op = REG; if(o == RNODE && p->in.left->tn.type == TDOUBLE) p->in.left->tn.rval = 0; else p->in.left->tn.rval = callreg( p->in.right ); p->in.left->bn.label = typlen(p->in.left->tn.type) >> 1; if( odebug ) { printf( "funny node redone\n" ); e2print(p); } return(0); } } else { TWORD t = p->in.left->tn.type; TWORD t2= p->in.right->tn.type; /* this case is, for example, unsigned char a, b; ... a*b /* we convert both to a reasonable type */ /* the result is assumed to be automatically /* converted downwards if it should be... */ p->in.left = ind2type( p->in.left ); p->in.right = ind2type( p->in.right ); if( odebug ) { printf( "conversions inserted" ); e2print(p); } /* if this didn't work, we are in trouble */ if( ( t != p->in.left->tn.type ) || ( t2 != p->in.right->tn.type) ) { /* we have changed something */ return( 0 ); } } e2print(p); cerror( "can't deal with op %s", opst[o] ); } if( o == INCR || o == DECR ) { /* very crude: a++ becomes (a+=1)-1 */ if( odebug>1 ) { e2print( p ); printf( "\nrewritten by rewass as:\n" ); } q = tcopy(p); regrcl( p->in.left ); tfree( p->in.left ); p->in.left = q; q->tn.op = ((o==INCR)?ASG PLUS:ASG MINUS); p->tn.op = ((o==INCR)?MINUS:PLUS); if( odebug ) { printf( "\nrewritten by rewass as:\n" ); e2print( p ); } return(1); } /* find out if some subtree has to be stored into a temp... */ if( q = lhsto(p) ) { if( !rewsto( q ) ) cerror( "rewass0" ); /* q => t=q,t */ rewcom( p, p->tn.goal ); /* move COMOP to the top */ if( p->tn.op != COMOP ) cerror( "rewass1" ); if( !asgop( p->in.right->tn.op ) ) cerror( "rewass2" ); reweop( p->in.right ); } else reweop( p ); /* rewrite p as an =OP */ return(1); } # ifdef NONEST subcall( p ) register NODE *p; { /* return 1 if p contains a callop */ register o, t; o = p->tn.op; if( callop(o) # ifndef UCALLBAD && o!=UNARY CALL # endif # ifndef STCALLBAD && o!=UNARY STCALL # endif # ifndef UFCALLBAD && o!=UNARY FORTCALL # endif ) return( 1 ); t = optype( o ); if( t==BITYPE && subcall(p->in.right) ) return( 1 ); if( t!=LTYPE ) return( subcall( p->in.left ) ); return( 0 ); } nonest( p ) register NODE *p; { register o, t; /* right now, this is very crude */ /* find arguments below a call; store them */ /* nonest is called up to a call; stocm is called within args */ o = p->tn.op; t = optype( o ); if( o==CALL || o==STCALL || o==FORTCALL) { stocm( p->in.right ); nonest( p->in.left ); return; } if( t == BITYPE ) nonest( p->in.right ); if( t != LTYPE ) nonest( p->in.left ); } stocm( p ) register NODE *p; { /* all call arguments below p must be stored */ register NODE *q; register o; while( (o=p->tn.op) == CM ) { stocm( p->in.right ); p = p->in.left; } if( o != STARG && o != FUNARG ) cerror( "stocm" ); q = p->in.left; if( subcall( q ) ) { if( o == FUNARG ) rewsto( q ); else { /* structure argument with call beneath */ rewsto( p ); } /* now q will be done outside of a call, so use nonest */ nonest( q ); } } # endif outshp( pp ) SHAPE **pp; { SHAPE *p; if (pp == 0) return; for( ; p = *pp; ++pp ) { printf("\t\t"); shpr(p); printf( " (%d)\n", p->sc ); } } tabpr() { register OPTAB *p; for (p =table; ;p++) { printf("Dump of table[%d] (stinline %d)\n", p-table, p->stinline ); printf("\top = %s\n", opst[p->op]); printf("\tnextop = %d\n", p->nextop?p->nextop-table:-1 ); printf("\tlshape = %d\n", p->lshape-pshape); printf("\tltype = 0%o\n", p->ltype); printf("\trshape = %d\n", p->rshape-pshape); printf("\trtype = 0%o\n", p->rtype); printf("\tneeds = %d\n", p->needs); printf("\trewrite = %d\n", p->rewrite); printf("\tcstring = %s", p->cstring); printf("\tcost = %d\n", p->cost); printf("\tLeft:\n"); outshp(p->lshape); printf("\tRight:\n"); outshp(p->rshape); printf("\n"); } } codgen( p ) NODE *p; { /* generate the code for p; */ int i, flag; if (odebug > 5) { tabpr(); /* NOTREACHED */ } # ifdef NONEST nonest(p); # endif /* if we make drastic changes to the tree (e.g., introduce temps) ** /* we will go back and do the whole thing again */ /* statistics indicate that this happens about 10% of the time */ /* if the percentage rises, there are many things that can be done to ** /* improve matters */ /* for example, RNODE, etc., could be removed by reader, and some of ** /* the op rewriting could be discovered by reader as well */ again: /* move the comma ops as high as practical */ rewcom( p, CEFF ); if( odebug ) { printf( "After goals are computed:" ); e2print( p ); } /* compute the costs */ if( costs( p ) ) goto again; /* if rewritten, do again */ if( odebug ) { printf( "After costs are computed:" ); e2print( p ); } /* do a trial code generation */ nins = 0; insout( p, CEFF ); /* rewrite stored subtrees as assignments to temps, with COMOP's */ flag = 0; for( i=0; ip; q = pi->q; c = pi->goal; if( c == CCC && (q->rewrite&RESCC) ) goal = FORCC; else if( c == CEFF ) goal = FOREFF; else goal = INREG; #ifndef NODEBUG if(odebug > 4) { printf("INSOUT: %d c=",i); preff(c); printf(" goal="); prgoal(goal); printf("\n"); e2print(p); } #endif allo( p, q ); expand( p, goal, q->cstring, q ); reclaim( p, q->rewrite, goal ); /* now, if condition codes needed, test */ if( c == CCC && p->tn.op != CCODES ) { cfix( p, CCC ); if( p->tn.op != CCODES ) cerror( "ctest fails" ); } if( c>=0 && c<=NRGS && !istnode( p ) ) { cfix( p, NRGS ); } } } SHTABLE sha; int odebug = 0; cfix( p, goal ) NODE *p; { /* p is to be fixed according to goal (CCC or NRGS) */ OPTAB *q; NODE *pp; int r; #ifndef NODBG if(odebug > 4) { printf("CFIX: goal="); prgoal(goal); printf("\n"); e2print(p); } #endif if( goal == CCC ) { r = RESCC; p->tn.goal = CCC; } else { r = (RESC1|RESC2|RESC3|RESC4); pp = getl( p ); if( istnode( pp ) ) r |= RLEFT; pp = getr( p ); if( istnode( pp ) ) r |= RRIGHT; } if( goal == CCC ) goal = FORCC; else goal = INREG; for( q=0; q = match( p, q ); ) { /* takes the first match (may not be cheapest) */ /* template writers, take note! */ if( q->rewrite & r ) { /* generate the code on the spot */ allo( p, q ); expand( p, goal, q->cstring, q ); reclaim( p, q->rewrite, goal ); return; } } e2print(p); cerror( "cfix trouble" ); } preff(c) { char buf[20]; register char *p; p = c==CCC ? "CCC" : c==CTEMP ? "CTEMP" : c==CEFF ? "CEFF" : 0; if(!p) { sprintf(buf,"0%o",c); p = buf; } printf("%s",p); }