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

1190 lines
25 KiB
C

#
/*
Copyright 1981
Alcyon Corporation
8474 Commerce Av.
San Diego, Ca. 92121
*/
#include "cgen.h"
#include "cskel.h"
#define SK_TYPE(x) (x&017)
/* scodegen - over-all code generation for expression*/
/* Picks off post-fix ++, --.*/
scodegen(tp,cookie,reg) /* returns register result is in*/
struct tnode *tp;
int cookie;
int reg;
{
struct tnode *clist[20];
struct tnode **clp;
register struct tnode **cp;
register int r;
register int ccflag;
register struct tnode *rtp;
ccflag = 0;
clp = clist;
tp = addptree(tp,&clp);
if( clp > clist ) {
/*post ++, -- in tree. We need to compile the tree sans post operators*/
/*then generate code to do the post operators, then do any fix up of*/
/*condition codes since the Stupid 68000 architect was a nimnul.*/
if( cookie == FORCC ) {
/*here we make the observation that if we are comparing something with*/
/*zero OR the top operator of the tree is not a comparison operator,*/
/*we can compile the tree to a register, and then set the condition*/
/*codes OK with a tst instruction at the end.*/
if( relop(tp->t_op) ) {
if( (rtp=constant(tp->t_right)) && rtp->t_value == 0 ) {
ccflag = 1;
tp = tp->t_left;
cookie = FORREG;
}
else
ccflag = 2;
}
else {
ccflag = 1;
cookie = FORREG;
}
}
}
r = codegen(tp,cookie,reg);
if( clp > clist ) {
if( ccflag == 2 )
outccsave(r);
for( cp = clist; cp < clp; cp++ )
codegen(*cp,FOREFF,r+1);
if( ccflag == 1 )
outcmp0(r,tp);
else if( ccflag == 2 )
outccrestore(r);
}
return(r);
}
/* addptree - prune off postfix ++, -- from expression tree*/
/* This prunes off ++, -- and collects those expressions for*/
/* scodegen.*/
char *addptree(tp,clp) /* returns pointer to pruned tree*/
struct tnode *tp;
struct tnode ***clp;
{
register int op;
op = tp->t_op;
if( leafop(op) )
return(tp);
if( op == POSTINC || op == POSTDEC ) {
*(*clp)++ = tp;
return( tcopy(tp->t_left) );
}
if( binop(op) )
tp->t_right = addptree(tp->t_right,clp);
tp->t_left = addptree(tp->t_left,clp);
return(tp);
}
/* codegen - generate code for expression*/
/* This calls up rcodegen, which prunes off any special register*/
/* optimization code, then calls ucodegen (unrecursive) code*/
/* generation.*/
codegen(tp,cookie,reg) /* returns reg result is in*/
struct tnode *tp; /* tree pointer*/
int cookie; /* code generation goals*/
int reg; /* first available register*/
{
register int size, savestk, ssize, r, i, scookie;
register struct tnode *rtp;
#ifndef NODEBUG
if( cflag )
printf("codegen op=%d cookie=%d reg=%d\n",tp->t_op,cookie,reg);
#endif
switch( tp->t_op ) {
case CALL:
case NACALL:
ssize = 0;
savestk = stacksize;
if( tp->t_left->t_op != SYMBOL )
stacksize++;
if( tp->t_op == CALL ) {
rtp = tp->t_right;
while( rtp->t_op == COMMA ) {
ssize =+ dofarg(rtp->t_right);
rtp = rtp->t_left;
}
ssize =+ dofarg(rtp);
}
tp->t_op = FJSR; /*generate JSR (unary op)*/
codegen(tp,FORREG,reg);
popstack(ssize);
stacksize = savestk;
fixresult(tp,cookie,0);
return(0); /*result in R0*/
case COMMA:
codegen(tp->t_left,FOREFF,reg);
return(codegen(tp->t_right,cookie,reg));
case AND:
if( cookie == FORCC && (i=isonebit(tp->t_right)) >= 0 &&
(i=dobitadd(tp->t_left,i)) >= 0 ) {
if( convop(tp->t_right->t_op) )
tp->t_right = tp->t_right->t_left;
tp->t_right->t_value = i;
tp->t_op = BTST;
tp = canon(tp);
sucomp(tp,reg,1);
}
break;
}
if( rcodegen(&tp,cookie,reg) ) {
if( cookie == FORCC && tp->t_op == SYMBOL ) {
if( indexreg(tp) )
outcmp0(tp->t_reg,tp);
return(reg);
}
}
r = ucodegen(tp,cookie,reg);
return(r);
}
/* fixresult - fix result of code generation*/
fixresult(tp,cookie,reg) /* returns - none*/
struct tnode *tp;
int cookie; /* wanted this cookie*/
int reg;
{
switch( cookie ) {
case FORCC:
outcmp0(reg,tp);
break;
case FORSP:
case FORSTACK:
stacksize++;
outrpush(reg,tp,cookie==FORSTACK);
break;
}
return(reg);
}
/* ucodegen - generate code for tree given cookie and starting register*/
/* Handles the matching of the expression tree node with the*/
/* corresponding code generation table. When a match is found,*/
/* expand is called to expand the code skeleton macro.*/
ucodegen(tp,cookie,reg) /* returns reg result is in*/
struct tnode *tp; /* pointer to expression tree*/
int cookie; /* (FORCC,FOREFF,FORREG,FORSTACK)*/
int reg; /* first available register*/
{
register int r;
register char *p;
#ifndef NODEBUG
if(cflag)
putexpr("ucodegen",tp);
#endif
switch( tp->t_op ) {
case SYMBOL:
if( cookie == FOREFF )
return(reg);
break;
case LSH:
if( isareg(reg) && (p=constant(tp->t_right)) &&
unsign(tp->t_left->t_type) == 0 &&
(p->t_value == 1 || p->t_value == 2) ) {
r = codegen(tp->t_left,FORREG,reg);
outmovr(r,reg,tp->t_left);
if( p->t_value == 2 )
outaddr(reg,reg,tp);
outaddr(reg,reg,tp);
return(reg);
}
break;
case EQMULT:
case EQDIV:
case LEQMULT:
case LEQDIV:
case EQMOD:
case LEQMOD:
case EQRSH:
case EQLSH:
case EQAND:
case EQOR:
case EQXOR:
if( indexreg(tp->t_left) ) {
reg = dreg(reg);
outmovr(r=tp->t_left->t_reg,reg,tp);
tp->t_left->t_reg = reg;
codegen(tp,cookie,reg+1);
outmovr(reg,r,tp);
return(reg);
}
break;
case ADD:
case EQADD:
if( (p=constant(tp->t_right)) && p->t_value < 0 &&
p->t_value >= -QUICKVAL ) {
p->t_value = - p->t_value;
tp->t_op =+ (SUB-ADD);
}
break;
}
sucomp(tp,reg,1);
if( (r=loadexpr(tp,cookie,reg)) >= 0 )
return(r);
if( (r=cqmark(tp,cookie,reg)) >= 0 )
return(r);
if( (r=hardrel(tp,cookie,reg)) >= 0 )
return(r);
if( cookie == FORCC && (p=match(tp,FOREFF,reg)) != 0 ) {
r = expand(tp,FOREFF,reg,p);
if( asgop(tp->t_op) && indexreg(tp->t_left) )
outcmp0(tp->t_left->t_reg,tp->t_left);
}
else if( p = match(tp,cookie,reg) )
r = expand(tp,cookie,reg,p);
else if( cookie != FORREG )
r = fixresult(tp,cookie,ucodegen(tp,FORREG,reg));
else
error("no code table for %d",tp->t_op);
return(r);
}
/* expand - code skeleton expansion*/
/* Handles the expansion of code skeleton macros.*/
expand(tp,cookie,freg,skp) /* returns register result is in*/
struct tnode *tp; /* pointer to expression tree*/
int cookie; /* goal of expression tree*/
int freg; /* register to leave results in*/
struct skeleton *skp; /* pointer to code skeleton*/
{
register int op, nreg, reg;
register int c;
register int extf, i2f;
register struct tnode *ltp, *rtp;
register char *p;
register int i, inaddreg, sreg, flag, subtrees, scookie;
register char *macro;
#ifndef NODEBUG
if( eflag )
printf("expand op=%d left=%x right=%x skp=%o\n",tp->t_op,
skp->sk_left,skp->sk_right,skp);
#endif
if( ((op=tp->t_op) >= MULT && op <= XOR) || tp->t_type == CHAR )
freg = dreg(freg);
macro = skp->sk_def;
extf = 0;
i2f = 0;
rtp = ltp = tp->t_left;
subtrees = 1;
if( binop(op) ) {
subtrees++;
rtp = tp->t_right;
if( longorptr(tp->t_type) && (op == DIV || op == MOD ||
(op != MULT && isdreg(freg) &&
longorptr(ltp->t_type)==0 && longorptr(rtp->t_type)==0)) )
extf++;
switch( op ) {
case RSH:
case LSH:
case EQLSH:
case EQRSH:
if( unsign(ltp->t_type) )
i2f++;
break;
case MULT:
case EQMULT:
case DIV:
case MOD:
case EQDIV:
case EQMOD:
if( unsign(ltp->t_type) || unsign(rtp->t_type) )
i2f++;
break;
}
}
nreg = freg + 1;
while( c = *macro++ ) {
c =& 0xff;
switch( c ) {
default:
putchar(c);
break;
case POP:
stacksize--;
printf("(sp)+");
break;
case POP8:
stacksize =- 2;
popstack(8);
break;
case PSH:
if( cookie == FORSP ) /*don't affect sp*/
printf("(sp)");
else
printf("-(sp)");
stacksize++;
break;
case MOV:
case MOVL:
case JSR:
case CLR:
case CLRL:
case EXTW:
case EXTL:
case LEA:
case STK:
printf("%s",strtab[c-128]);
break;
case TLEFT:
outtype( leafop(op) ? tp->t_type : ltp->t_type );
break;
case TLEFTL:
outatype( leafop(op) ? tp->t_type : ltp->t_type );
break;
case TEITHER:
if( longorptr(rtp->t_type) || longorptr(ltp->t_type) )
outtype(LONG);
break;
case TRIGHT:
outtype(rtp->t_type);
break;
case OP:
case AOP:
if( c == AOP || i2f )
i = optab[op][1];
else
i = optab[op][0];
printf(mnemonics[i]);
break;
case LADDR:
case RADDR:
p = (c==RADDR?rtp:ltp);
outaexpr(p,IMMED);
break;
case CR:
outcreg(freg);
break;
case NR:
outcreg(nreg);
break;
case CAR:
outcreg(areg(freg));
break;
case NAR:
outcreg(areg(nreg));
break;
case EXL:
outextend(ltp,LONG,freg);
break;
case EXRL:
case EXRLN:
outextend(rtp,ltp->t_type,c==EXRL?freg:nreg);
break;
case EXLR:
case EXLRN:
outextend(ltp,rtp->t_type,c==EXLR?freg:nreg);
break;
case LEFT:
case RIGHT:
subtrees--;
case TREE:
p = (c==LEFT?ltp:c==RIGHT?rtp:tp);
flag = *macro++;
scookie = FORREG;
if( flag & S_STACK ) {
if( cookie == FORSP )
scookie = FORSP;
else
scookie = FORSTACK;
}
else if( flag & S_FORCC )
scookie = FORCC;
if( flag & S_NEXT )
reg = nreg;
else
reg = freg;
if( flag & S_INDR ) {
if( p->t_op != INDR )
error("code skeleton error: %d\n",op);
p = p->t_left; /*skip INDR*/
i = 0;
if( coffset(p) ) {
p = p->t_left;
i++; /*need in An*/
}
if( i || p->t_op == SYMBOL || p->t_op == CINT ) {
/*we need address of "* expr" in an address register. If this is a*/
/*leaf node or the type of expression is not character, it is ok to*/
/*try to compile directly to the A register. Otherwise, we may as*/
/*well compile to D register anyway. This is fixed up immediately*/
/*after codegen below...*/
if( leafop(p->t_op) || p->t_type != CHAR )
reg = areg(reg);
}
}
sreg = codegen(p,scookie,reg); /*code for subtree*/
if( scookie == FORREG ) {
if( flag & S_INDR ) {
if( isdreg(sreg) )
outmovr(sreg,areg(reg),p);
}
else if( flag & S_NEXT )
nreg = sreg;
else if( sreg != reg ) {
/*result was not in expected register, if remaining sub-tree can be*/
/*compiled using the remaining registers, update current and next*/
/*registers, saving us the trouble of moving the register.*/
if( c == TREE || (isdreg(sreg) && subtrees > 0 &&
((c == LEFT &&
sucomp(rtp,sreg,0) <= skp->sk_right &&
sucomp(rtp,sreg,1) <= SU_ANY) ||
( c == RIGHT &&
sucomp(ltp,sreg,0) <= skp->sk_left &&
sucomp(ltp,sreg,1) <= SU_ANY))) ) {
freg = dreg(sreg);
nreg = freg + 1;
}
else
outmovr(sreg,dreg(freg),p);
}
}
break;
case LOFFSET:
case ROFFSET:
p = (c==LOFFSET) ? ltp->t_left : rtp->t_left;
if((p=coffset(p)) != 0 && (p->t_op != CINT || p->t_value != 0))
outaexpr(p,NOTIMMED);
break;
case MODSWAP:
switch( op ) {
case MOD:
case EQMOD:
case LMOD:
case LEQMOD:
outswap(freg);
}
break;
}
}
if( extf && cookie == FORREG && isdreg(freg) ) {
if( unsign(ltp->t_type) || unsign(rtp->t_type) )
outuext(freg);
else
outext(freg);
}
#ifndef NODEBUG
if( eflag )
printf("ending expand skp=%o\n",skp);
#endif
return(freg);
}
/* match - try to match expression tree with code skeleton*/
/* Given the expression tree, tries to match the given tree with*/
/* the appropriate code skeleton. The code skeleton list is*/
/* gotten from the root operator and the cookie value. The code*/
/* skeleton list is then searched, checking the Sethy-Ullman numbers*/
/* of the sub-trees against the Sethy-Ullman numbers in the code*/
/* skeleton list. If the Sethy-Ullman numbers are OK, then the*/
/* left and right sub-trees are checked for compatability, e.g.*/
/* integer pointers, etc. If a match is found, the code skeleton*/
/* list pointer is returned.*/
char *match(tp,cookie,reg) /* returns pointer to code skeleton*/
/* or 0 if no skeleton*/
struct tnode *tp; /* pointer to tree*/
int cookie; /* goal for code expansion*/
int reg; /* register to use*/
{
register struct skeleton *skp;
register int op, bop, i, opndx;
register struct tnode *ltp, *rtp;
#ifndef NODEBUG
if( mflag )
printf("match op=%d cookie=%d reg=%d\n",tp->t_op,cookie,reg);
#endif
if( (op=tp->t_op) >= LCGENOP )
return(0);
if( leafop(op) )
ltp = tp;
else
ltp = tp->t_left;
if( (bop=binop(op)) ) {
rtp = tp->t_right;
if( convop(ltp->t_op) ) {
if( op != LSH && notconvop(rtp->t_op) ) {
tp->t_left = ltp->t_left;
if( (unsign(ltp->t_left->t_type) == 0 || op == ASSIGN) &&
(skp=match(tp,cookie,reg)) != 0 )
return(skp);
tp->t_left = ltp;
}
}
else if( convop(rtp->t_op) ) {
tp->t_right = rtp->t_left;
if( (unsign(rtp->t_left->t_type) == 0 || op == ASSIGN) &&
(skp=match(tp,cookie,reg)) != 0 )
return(skp);
tp->t_right = rtp;
}
}
switch( cookie ) {
case FORCC:
i = 3;
break;
case FOREFF:
i = 2;
break;
case FORSTACK:
case FORSP:
i = 4;
break;
case FORREG:
i = 5;
break;
default:
error("match cookie=%d\n",cookie);
return(0);
}
if( (i=optab[op][i]) == 0 )
return(0);
skp = codeskels[i];
#ifndef NODEBUG
if(mflag) {
printf("match LEFT ");
puttsu(ltp);
if(bop) {
printf(" RIGHT ");
puttsu(rtp);
}
putchar('\n');
}
#endif
for( ; skp->sk_left != 0; skp++ ) {
#ifndef NODEBUG
if( mflag > 1 )
printf("sk_left=%x sk_right=%x\n",skp->sk_left,skp->sk_right);
#endif
if( skelmatch(ltp,skp->sk_left) == 0 )
continue;
if( bop && skelmatch(rtp,skp->sk_right) == 0 )
continue;
#ifndef NODEBUG
if( mflag )
printf("match found skp=%o left=%x right=%x\n",skp,
skp->sk_left,skp->sk_right);
#endif
return(skp);
}
return(0);
}
/* unsign - check for UNSIGNED type*/
unsign(type) /* returns 1 for unsigned, 0 otherwise*/
int type; /* type to check*/
{
return(type == UNSIGNED);
}
/* longorptr - check for being long or ptr*/
longorptr(type) /* returns 1 for yes 0 for no*/
int type;
{
return( type == LONG || suptype(type) );
}
unorptr(type)
int type;
{
if( type == UNSIGNED )
return(1);
if( suptype(type) )
return(1);
return( 0 );
}
/* basetype - get the btype info sans unsigned*/
basetype(type) /* returns signed base type*/
int type; /* type to check*/
{
return( type == UNSIGNED ? INT : type);
}
/* dreg - get corresponding data register*/
dreg(reg) /* returns data register index*/
int reg; /* register index*/
{
return( reg & (~AREGLO) );
}
/* areg - return corresponding address register*/
areg(reg) /* returns address register index*/
int reg; /* register index*/
{
return( reg | AREGLO );
}
/* isareg - check register for being an address register*/
isareg(reg)
int reg;
{
return( reg >= AREGLO );
}
/* isdreg - check register for being data register*/
isdreg(reg) /* returns 1 if data reg, 0 otherwise*/
int reg; /* register index*/
{
return( reg < AREGLO );
}
/* isreg - tests tree for being a register*/
isreg(tp) /* returns 1 if is reg, else 0*/
struct tnode *tp; /* pointer to tree*/
{
return( tp->t_op == SYMBOL && tp->t_sc == REGISTER );
}
/* skelmatch - sub-tree type matching for match*/
/* This checks a subtree for type compatability in match.*/
skelmatch(tp,skinfo) /* returns 1 if matched, else 0*/
struct tnode *tp; /* pointer to expression tree*/
int skinfo;
{
register int type, unsignf, const, stype;
if( tp->t_su > skinfo || ((skinfo&T_INDR) && tp->t_op != INDR) )
return(0);
stype = SK_TYPE(skinfo);
type = tp->t_type;
if( function(type) )
type = btype(type);
if( unsignf = unsign(type) )
type = basetype(type);
const = 0;
switch( tp->t_op ) {
case CLONG:
if( tp->t_su > SU_CONST )
break;
case CINT:
const++;
break;
}
switch( stype ) {
case T_CHAR:
return( type == CHAR );
case T_ANY: /*either int or char*/
if( type == CHAR )
return(1);
case T_INT:
return( type == INT || const );
case T_UNSN:
return( unsignf );
case T_LONG:
return( longorptr(type) );
default:
error("skelmatch type: %x",stype);
return(0);
}
}
/* loadexpr - load an addressable expression into a register*/
/* This checks for any possible usage of the register indexed*/
/* addressing mode. Note that this relies on the good graces of the*/
/* load code skeletons not to muck up the compiler registers before*/
/* loading an addressable expression...*/
loadexpr(tp,cookie,reg) /* returns register loaded or -1*/
struct tnode *tp; /* pointer to expression tree*/
int reg; /* register to load*/
{
register struct tnode *rtp, *ltp, *xtp, *atp;
register int off, r, type, nr, ar, xr, xt;
if( tp->t_op == INDR || LOADABLE(tp) ) {
type = tp->t_type;
if( tp->t_op == INDR && (ltp=tp->t_left)->t_op == ADD ) {
rtp = ltp->t_right;
ltp = ltp->t_left;
off = 0;
if( rtp->t_op == CINT && ((off=rtp->t_value) < -128 ||
off > 127 || ltp->t_op != ADD ) ) {
tp = snalloc(type,AUTO,off,0,0);
if( indexreg(ltp) )
tp->t_reg = ltp->t_reg;
else {
r = codegen(ltp,FORREG,areg(reg));
if( isdreg(r) )
outmovr(r,areg(r),ltp);
tp->t_reg = areg(r);
}
}
else {
if( rtp->t_op == CINT ) {
rtp = ltp->t_right;
ltp = ltp->t_left;
}
if( indexreg(rtp) || (indexreg(ltp) == 0 && isreg(rtp)) ) {
xtp = ltp;
ltp = rtp;
rtp = xtp;
}
xtp = 0;
atp = 0;
if( indexreg(ltp) ) {
ar = ltp->t_reg;
if( isreg(rtp) && rtp->t_type != CHAR ) {
xr = rtp->t_reg;
xt = rtp->t_type;
}
else
xtp = rtp;
}
else if( isreg(ltp) && ltp->t_type != CHAR &&
(lflag || rtp->t_op != ADDR) ) {
xr = ltp->t_reg;
xt = ltp->t_type;
atp = rtp;
}
else if( rtp->t_op == ADDR ) {
atp = ltp;
xtp = rtp;
}
else {
atp = rtp;
xtp = ltp;
}
nr = 0;
if( atp )
nr++;
if( xtp && (xtp->t_op != ADDR || lflag ) )
nr++;
if( dreg(nr+reg) <= HICREG ) {
r = reg;
if( atp ) {
ar = codegen(atp,FORREG,areg(r));
if( isdreg(ar) ) {
outmovr(ar,areg(ar),atp);
ar = areg(ar);
}
r++;
}
if( xtp && xtp->t_op == ADDR && lflag == 0 ) {
tp = xtp->t_left;
tp->t_sc =+ (EXTOFF-EXTERNAL);
tp->t_offset =+ off;
tp->t_reg = ar;
}
else {
if( xtp ) {
xr = codegen(xtp,FORREG,areg(r));
xt = xtp->t_type;
}
tp = xnalloc(type,ar,off,xr,xt);
}
}
}
}
if( isareg(reg) && tp->t_type == CHAR )
reg = dreg(reg);
tp = tnalloc(LOAD,tp->t_type,SU_EASY,0,tp,null);
return( codegen(tp,cookie,reg) );
}
return(-1);
}
/* coffset - check offset for addressable node*/
char *coffset(tp) /* returns ptr to const off node*/
struct tnode *tp; /* pointer to node*/
{
register struct tnode *rtp;
if( tp->t_op == ADD ) {
rtp = tp->t_right;
if( rtp->t_op == CINT )
return(rtp);
if( lflag == 0 ) {
if( rtp->t_op == ADDR )
return(rtp->t_left);
rtp = tp->t_left;
if( rtp->t_op == ADDR ) {
tp->t_left = tp->t_right;
tp->t_right = rtp;
return(rtp->t_left);
}
}
}
return(0);
}
/* hardrel - do relationals returning a value*/
hardrel(tp,cookie,reg) /* returns reg or -1*/
struct tnode *tp; /* pointer to tree*/
int cookie; /* cookie for code generation*/
int reg; /* low register*/
{
char *p;
int op, lab1, lab2;
if( cookie != FORCC && (relop(op=tp->t_op) || op == LOR ||
op == LAND || op == NOT) ) {
lab1 = nextlabel++;
condbr(tp,TRUE,lab1,reg);
p = canon(cnalloc(INT,0));
codegen(p,cookie,reg);
lab2 = nextlabel++;
outgoto(lab2);
outlab(lab1);
p = canon(cnalloc(INT,1));
codegen(p,cookie,reg);
outlab(lab2);
return(reg);
}
return(-1);
}
/* cqmark - compile question mark operator*/
/* This does the compilation of the question mark operator.*/
cqmark(tp,cookie,reg) /* returns reg or -1*/
struct tnode *tp;
int cookie;
int reg;
{
register int lab1, lab2, savestk, r;
if( tp->t_op == QMARK && cookie != FORCC ) {
lab1 = nextlabel++;
condbr(tp->t_left,FALSE,lab1,reg);
savestk = stacksize;
r = codegen(tp->t_right->t_left,cookie,reg);
outmovr(r,reg,tp);
stacksize = savestk;
outgoto(lab2=nextlabel++);
outlab(lab1);
r = codegen(tp->t_right->t_right,cookie,reg);
outmovr(r,reg,tp);
outlab(lab2);
return(reg);
}
return(-1);
}
/* condbr - handle conditional branch code generation*/
/* This handles the conditional branch code generation, handling*/
/* the special cases for constants, ||, &&, ! and generating the*/
/* correct conditional branch instruction.*/
condbr(tp,dir,lab,reg)
struct tnode *tp;
int dir;
int lab;
int reg;
{
register struct tnode *ltp, *rtp;
register int lab1, optype, op, subdir;
ltp = tp->t_left;
if( binop(op=tp->t_op) )
rtp = tp->t_right;
subdir = dir; /*set up for LOR*/
switch( op ) {
case CINT:
if( tp->t_value == 0 ) {
if( dir == FALSE )
outgoto(lab);
}
else if( dir != FALSE )
outgoto(lab);
break;
case NOT:
condbr(ltp,!dir,lab,reg);
break;
case LAND:
dir = !dir;
case LOR:
if( dir == FALSE ) {
lab1 = nextlabel++;
condbr(ltp,!subdir,lab1,reg);
condbr(rtp,subdir,lab,reg);
outlab(lab1);
}
else {
condbr(ltp,subdir,lab,reg);
condbr(rtp,subdir,lab,reg);
}
break;
case COMMA:
scodegen(tp->t_left,FOREFF,reg);
condbr(tp->t_right,dir,lab,reg);
break;
default:
if( relop(op) && ltp->t_op == AUTOINC && rtp->t_op == AUTOINC &&
ltp->t_type == rtp->t_type )
outcmpm(tp);
else
scodegen(tp,FORCC,reg);
optype = 0;
if( relop(op) ) {
if( unorptr(ltp->t_type) || unorptr(rtp->t_type) )
optype =+ 1;
}
else
op = NEQUALS;
if( dir == 0 )
op = invrel[op-EQUALS];
optype = brtab[op-EQUALS][optype];
printf("%s L%d\n",mnemonics[optype],lab);
break;
}
}
rcodegen(tpp,cookie,reg) /* returns changed flag*/
struct tnode **tpp; /* pointer to tree*/
int cookie; /* code generation cookie*/
int reg; /* register to use for code*/
{
register int change, op;
register struct tnode *tp;
tp = *tpp;
op = tp->t_op;
change = 0;
if( notleafop(op) && op != COMMA ) {
change =+ rcodegen(&tp->t_left,cookie,reg);
if( binop(op) )
change =+ rcodegen(&tp->t_right,cookie,reg);
change =+ rcgen(tpp,cookie,reg);
}
if( change )
*tpp = canon(*tpp);
return(change);
}
rcgen(tpp,cookie,reg) /* returns changed flag*/
struct tnode **tpp; /* pointer to tree*/
int cookie; /* code generation goals*/
int reg; /* register to use*/
{
register struct tnode *tp, *p, *ltp, *rtp;
register int op, change;
change = 0;
for( tp = *tpp ; binop(op=tp->t_op); *tpp=tp=canon(tp), change++ ) {
ltp = tp->t_left;
if( ltp->t_op != SYMBOL )
break;
rtp = tp->t_right;
switch( op ) {
case ASSIGN:
if( ltp->t_sc != REGISTER )
return(change);
switch( rtp->t_op ) {
case MULT:
case DIV:
case AND:
case OR:
case XOR:
case LSH:
case RSH:
if( isareg(ltp->t_reg) )
return(change);
case ADD:
case SUB:
p = rtp->t_right;
if( NOTADDRESSABLE(p) || (p->t_op == SYMBOL &&
p->t_sc == REGISTER && p->t_reg == ltp->t_reg) )
return(change);
p = rtp->t_left;
if( p->t_op != SYMBOL || p->t_sc != REGISTER ||
p->t_reg != ltp->t_reg ) {
tp->t_right = p;
#ifndef NODEBUG
if( cflag > 1 )
putexpr("rcgen",tp);
#endif
codegen(tp,FOREFF,reg);
}
tp->t_right = rtp->t_right;
tp->t_op = rtp->t_op + (EQADD-ADD);
continue;
}
case EQLSH:
case EQRSH:
if( ltp->t_sc != REGISTER )
return(change);
case EQADD:
case EQSUB:
case EQAND:
case EQOR:
case EQXOR:
#ifndef NODEBUG
if( cflag > 1 )
putexpr("rcgen",tp);
#endif
ucodegen(tp,FOREFF,reg);
tp = ltp;
continue;
case PREDEC:
case PREINC:
if( cookie == FORCC )
return(change);
ucodegen(tp,FOREFF,reg);
tp = ltp;
continue;
}
break;
}
return(change);
}
/* cdsize - compute size of data item*/
cdsize(tp) /* returns data size in bytes*/
struct tnode *tp;
{
register int type;
type = tp->t_type;
if( suptype(type) )
return(PTRSIZE);
switch( type ) {
case CHAR:
case INT:
case UNSIGNED:
return(INTSIZE);
case LONG:
return(LONGSIZE);
}
error("cdsize: invalid type");
return(0);
}
dofarg(tp) /* returns number of bytes pushed*/
struct tnode *tp; /* pointer to expression tree*/
{
register int nb;
nb = 0;
if( tp->t_op == SYMBOL && tp->t_sc == STRUCT )
error("structure operation not implemented");
else if( stacksize ) {
codegen(tp,FORSTACK,0);
nb = cdsize(tp);
}
else
codegen(tp,FORSP,0);
return( nb );
}
/* dobitadd - do bit operation address checking and fixup*/
dobitadd(tp,bitno) /* returns -1 if can't or bitno*/
struct tnode *tp;
int bitno;
{
register int offset;
if( tp->t_type == CHAR )
offset = 0;
else
offset = cdsize(tp) - (bitno/BITSPBYTE) - 1;
if( tp->t_op == SYMBOL ) {
switch( tp->t_sc ) {
case REGISTER:
if( isdreg(tp->t_reg) )
return(bitno);
default:
return(-1);
case EXTERNAL:
case STATIC:
case REGOFF:
case STATOFF:
case EXTOFF:
tp->t_offset =+ offset;
return( bitno % BITSPBYTE );
}
}
else if( tp->t_op == INDR ) {
tp->t_left = tnalloc(ADD,tp->t_left->t_type,0,0,tp->t_left,
cnalloc(INT,offset));
return( bitno % BITSPBYTE );
}
return(-1);
}
isonebit(tp) /* returns -1 if not 1 bit, else bitno*/
struct tnode *tp; /* pointer to tree*/
{
if( tp = constant(tp) )
return( onebit(tp->t_value) );
return(-1);
}