mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 08:54:17 +00:00
1190 lines
25 KiB
C
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);
|
|
}
|