V9/cmd/sun/pcc/local2.c
#include "cpass2.h"
#include "ctype.h"
#ifndef lint
static char sccsid[] = "@(#)local2.c 1.1 86/02/03 Copyr 1985 Sun Micro";
#endif
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
# ifdef FORT
int ftlab1, ftlab2;
# endif
/* a lot of the machine dependent parts of the second pass */
#ifdef FORT
# define fltfun 0
#else
extern int fltfun;
#endif
# define BITMASK(n) ((1L<<(n))-1)
int toff = 0; /* number of stack locations used for args */
int maxtoff;
void stmove();
void eval_field();
void shiftreg();
void incraddr();
/* everything you never wanted to know about condition codes */
char *
ccodes[] = { "eq", "ne", "le", "lt", "ge", "gt", "ls", "cs", "cc", "hi" };
char *
fccodes[] = { "eq", "neq", "le", "lt", "ge", "gt" };
char *
fnegccodes[] = { "neq", "eq", "nle", "nlt", "nge", "ngt" };
/* logical relations when compared in reverse order (cmp R,L) */
#ifdef FORT
short revrel[] = { EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT };
#else
extern short revrel[];
#endif
/* negated logical relations -- integer comparisons only */
int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
zzzcode( p, c, cookie ) NODE *p;
{
register m,temp;
NODE *s;
switch( c ){
/* BCDEFGHIJKLMNOPRSTVWXabcdfglmrtv` '0-~ */
case 'C':
switch (p->in.left->in.op) {
case ICON: print_str("\tjbsr\t");
acon(p->in.left);
return;
case REG:
if (indexreg(p->in.left)){
/* already in an address register */
print_str("\tjsr\t");
adrput(p->in.left);
putchar('@');
return;
} /* else fall through */
case NAME:
case OREG: print_str("\tmovl\t");
adrput(p->in.left);
print_str(",a0\n\tjsr\ta0@");
return;
default: cerror("bad subroutine name");
}
case 'E': /* load doubles with overly complex addressing */
{
/*
* accomplished by simplifying addressing, then
* falling through to case 'D'.
*/
expand(p, cookie, " lea AR,A2\n");
/*
* we would like, at this point, just to paint over
* p with the place where we have the address calculated
* and be done with it. too bad we can't: reclaim
* needs to look at it. So we must RECUR here
*/
resc[1].tn.op = OREG;
resc[1].tn.lval = 0;
resc[1].tn.type = INCREF(DOUBLE);
zzzcode( &resc[1], 'D', cookie );
return;
}
case 'D': /* load-store doubles with auto-incr/decr addressing */
{
/* cases are: ASSIGN, or rewrite LEAF-node */
# define FORW 0
# define REVR 1
static char * lrewrite[] = { "\tmovl\tA.,A1\n\tmovl\tU.,U1\n",
"\tmovl\tU.,U1\n\tmovl\tA.,A1\n"};
static char * asreg[] = { "\tmovl\tAR,AL\n\tmovl\tUR,UL\n",
"\tmovl\tUR,UL\n\tmovl\tAR,AL\n"};
char **rstring;
NODE * q;
if (p->in.op == ASSIGN){
rstring = asreg; q = p->in.left;
} else {
rstring = lrewrite; q = p;
}
if (q->in.op == UNARY MUL && q->in.left->in.op == ASG MINUS)
expand( p, cookie, rstring[REVR] );
else
expand( p, cookie, rstring[FORW] );
# undef FORW
# undef REVR
}
return;
case 'K':
/*
* 68881 floating point source operand
* This is essentially the same as AR, but
* in addition we check for the opportunity
* to use floating-point immediate mode.
* Only supported by the assembler in
* coprocessor instructions.
*/
switch(optype(p->in.op)) {
case LTYPE:
break;
case UTYPE:
if (p->in.op != UNARY MUL)
p = p->in.left;
break;
case BITYPE:
p = p->in.right;
break;
}
if (p->in.op == FCON) {
floatimmed(p);
} else {
adrput(p);
}
return;
case 'L':
m = p->in.left->in.type;
goto suffix;
case 'R':
m = p->in.right->in.type;
goto suffix;
case 'B':
m = p->in.type; /* fall into suffix: */
suffix:
switch(m) {
case CHAR:
case UCHAR:
c = 'b';
break;
case SHORT:
case USHORT:
c = 'w';
break;
default:
c = 'l';
break;
}
putchar(c);
return;
case 'F':
/*
* print type characters for the source operand of
* a 68881 floating point instruction.
*/
switch(optype(p->in.op)) {
case LTYPE:
break;
case UTYPE:
if (p->in.op != UNARY MUL)
p = p->in.left;
break;
case BITYPE:
p = p->in.right;
break;
}
/*
* at this point, p is assumed to have matched
* the shape SFLOAT_SRCE (cf. special())
*/
if (p->in.op == SCONV)
p = p->in.left;
goto float_suffix;
case 'G':
/*
* print type character for the left subtree
*/
p = p->in.left;
if (p->in.op == SCONV)
p = p->in.left;
goto float_suffix;
case '.':
float_suffix:
if (p->in.op == REG && iscreg(p->tn.rval)) {
/*
* source is coprocessor reg; data
* is in extended precision
*/
putchar('x');
return;
}
/*
* print type character for the root node
*/
switch(BTYPE(p->in.type)) {
case CHAR:
c = 'b';
break;
case SHORT:
c = 'w';
break;
case FLOAT:
c = 's';
break;
case DOUBLE:
c = 'd';
break;
case UCHAR:
case USHORT:
/*
* the 68881 sign-extends integer operands
*/
cerror("compiler botched unsigned operand");
/*NOTREACHED*/
default:
c = 'l';
break;
}
putchar(c);
return;
case 'N': /* logical ops, turned into 0-1 */
/* use register given by RESC1 */
branch(m=getlab());
/* FALL THROUGH */
make_boolean:
deflab( p->bn.label );
temp = getlr( p, '1' )->tn.rval;
printf( " clrl %s\n", rnames[temp]);
markused(temp);
deflab( m );
return;
case 'H':
cbgen(p->in.op, p->in.left->in.type, p->bn.label,
p->bn.reversed, FCCODES);
return;
case 'I':
cbgen(p->in.op, p->in.left->in.type, p->bn.label,
p->bn.reversed, CCODES);
return;
/* stack management macros */
case '-':
print_str( "sp@-" );
case 'P':
toff += 4;
if (toff > maxtoff) maxtoff = toff;
return;
case '0':
toff = 0; return;
case '~':
/* complimented CR */
p->in.right->tn.lval = ~p->in.right->tn.lval;
conput( getlr( p, 'R' ) );
p->in.right->tn.lval = ~p->in.right->tn.lval;
return;
case 'M':
/* negated CR */
p->in.right->tn.lval = -p->in.right->tn.lval;
case 'O':
conput( getlr( p, 'R' ) );
p->in.right->tn.lval = -p->in.right->tn.lval;
return;
case 'T':
/* Truncate longs for type conversions:
INT|UNSIGNED -> CHAR|UCHAR|SHORT|USHORT
increment offset to second word */
m = p->in.type;
p = p->in.left;
switch( p->in.op ){
case NAME:
case OREG:
if (p->in.type==SHORT || p->in.type==USHORT)
p->tn.lval += (m==CHAR || m==UCHAR) ? 1 : 0;
else p->tn.lval += (m==CHAR || m==UCHAR) ? 3 : 2;
return;
case REG:
return;
default:
cerror( "Illegal ZT type conversion" );
return;
}
case 't':
/*
* Lengthen little (unsigned) things. Try to be smart
* about instruction sequences.
*/
s = p->in.left;
m = s->in.type;
if (ISUNSIGNED(m)){
/* zero-extending into temp register */
if ( istnode(s) && s->tn.rval == resc[0].tn.rval ){
/* must use andl instructions */
print_str_str( " andl #0x", (m==UCHAR)?"ff":"ffff");
} else {
print_str_str_nl( " moveq #0,", rnames[ resc[0].tn.rval ] );
printf( " mov%c ", (m==UCHAR)?'b':'w');
adrput( s );
}
putchar(','); print_str_nl(rnames[ resc[0].tn.rval ] );
} else {
/* sign-extending into temp register */
if (!(istnode(s) && s->tn.rval == resc[0].tn.rval) ){
/* not already in its register */
printf( " mov%c ", (m==CHAR)?'b':'w');
adrput( s );
putchar(','); print_str_nl(rnames[ resc[0].tn.rval ] );
}
/* sign-extend */
if (m == CHAR)
print_str_str_nl( " extw ", rnames[resc[0].tn.rval]);
if (p->in.type != SHORT && p->in.type != USHORT)
print_str_str_nl( " extl ", rnames[resc[0].tn.rval]);
}
return;
case 'W': /* structure size */
if( p->in.op == STASG )
print_d(p->stn.stsize);
else cerror( "Not a structure" );
return;
case 'S': /* structure assignment */
stmove( p, cookie );
return;
case 'X':{ /* indexed effective address */
NODE fake,*lp,*rp;
int flags;
lp = p->in.left;
rp = p->in.right;
R2PACKFLGS(flags, rp->in.type == SHORT, 0, 0);
fake.in.op = OREG;
fake.tn.rval = R2PACK(lp->in.left->tn.rval, rp->tn.rval, flags);
fake.tn.name = "\0";
fake.tn.lval = lp->in.right->tn.lval;
oregput(&fake);
return;
}
case 'a':
/* assign something to a bit field */
case 'b':
/* extract a bit field */
case 'c':
/* compare bit field with constant for CC only */
eval_field( p, c, cookie);
return;
case 'f': /* floating-point operation */
/* since the floating-point format may be changed with a
* compile-time switch, we need to go think about this
*/
floatcode( p, cookie );
fltused++;
return;
case 'g': /* floating-point conversion to normal register */
/* anything that looks like a floating type conversion
* or a floating-register load or store comes here.
*/
floatconv( p, c, cookie );
fltused++;
return;
case 'm': /* multiplication by a constant */
conmul( p, cookie );
return;
case 'd': /* division by a constant */
condiv( p, cookie );
return;
case 'r': /* remainder by a constant */
conrem( p, cookie );
return;
case ' ': /* leaf-type for effect only */
/*
* usually this will generate NO code.
* the exception is INCR or ASG MINUS, as in
* *p++, *--p;
* these are recognized as side effects of addressing
* modes, so have not been dealt with by higher functions.
*/
if (p->in.op == UNARY MUL){
if (p->in.left->in.op == INCR){
printf(" addql #%d, %s\n",
tlen(p), rnames[p->in.left->in.left->tn.rval]);
} else if (p->in.left->in.op == ASG MINUS){
printf(" subql #%d, %s\n",
tlen(p), rnames[p->in.left->in.left->tn.rval]);
}
}
return;
case 'l': /* lea or addl instruction, as appropriate */
if (p->in.left->tn.rval == resc[0].tn.rval){
/* really a += */
expand( p, cookie, " addZR AR,A1\n");
} else {
/* really is a 3-address lea */
expand( p, cookie, " lea AL@(0,AR:ZR),A1\n");
}
return;
case 'v': /* generate trapv for signed arithmetic */
trapv(p->in.type);
return;
case 'V': /* generate bound-testing code */
bound_test(p, cookie);
return;
default:
cerror( "illegal zzzcode" );
}
}
#define checkout if (resc[opno].tn.op != REG) cerror("struct-assign botch")
NODE *
cpytmp( l, opno ) NODE *l;
{
NODE *new;
print_str( (l->in.op == REG)||(ISPTR(l->in.type))? " movl " : " lea ");
adrput( l );
checkout;
new = &resc[opno];
new->tn.type = ISPTR(l->in.type)?l->in.type:INCREF(l->in.type);
markused(new->tn.rval);
putchar(','); print_str_nl(rnames[new->tn.rval] );
return new;
}
void
stmove( p , cookie ) register NODE *p;
{
register NODE *l, *r;
register size, i;
extern NODE resc[];
int opno = 1;
int rcopy;
int xsize;
int labl;
int loopcode;
register char *cnt, *lhs, *rhs;
char **moves;
# define MOVBSTRNG 0
# define MOVWSTRNG 1
# define MOVLSTRNG 2
static char * asgstrings[] = {
" movb AR,AL\n",
" movw AR,AL\n",
" movl AR,AL\n",
};
static char * argstrings[] = {
" movb AR,sp@-\n",
" movw AR,sp@-\n",
" movl AR,sp@-\n",
};
if( p->in.op == STASG ){
l = p->in.left;
r = p->in.right;
moves = asgstrings;
} else if( p->in.op == STARG ){ /* store an arg onto the stack */
/*
* "r" and "l" are obviously misnomers here.
* they should be "from" and, perhaps, "to".
*/
r = p->in.left;
checkout;
l = &resc[opno++];
markused(l->tn.rval);
moves = argstrings;
} else
cerror( "STASG bad" );
if ( r->in.op == ICON )
r->in.op = NAME;
/*
* avoid complicated memory operands
*/
if (l->in.op == OREG && R2TEST(l->tn.rval)) {
l = cpytmp( l, opno++ );
}
if (r->in.op == OREG && R2TEST(r->tn.rval)) {
r = cpytmp( r, opno++ );
}
size = p->stn.stsize;
xsize = size + (size&1); /* must be even */
/*
* now we make a totally arbitrary decision about
* when to loop, and when to emit straight-line code.
*/
if (size <= 8){
/* straight-line */
NODE xxx;
/* the MIT strategy -- gross, no? */
if( l->in.op != REG && ISPTR(l->in.type))
l = cpytmp( l, opno++ );
if( r->in.op != REG && ISPTR(r->in.type))
r = cpytmp( r, opno++ );
xxx.in.op = STASG;
xxx.in.left = l;
xxx.in.right = r;
if( r->tn.op == REG ){
r->tn.op = OREG;
r->tn.type = DECREF(r->tn.type);
}
if( l->in.op == REG ) l->in.op = OREG;
r->tn.lval += size;
l->tn.lval += size;
switch (size&03){
/* do special cases */
case 1:
case 3:
r->tn.lval -= 1;
l->tn.lval -= 1;
expand( &xxx, cookie, moves[MOVBSTRNG] );
if ((size&03) == 1) break;
/* case 3 falls through */
case 2:
r->tn.lval -= 2;
l->tn.lval -= 2;
expand( &xxx, cookie, moves[MOVWSTRNG] );
}
size -= size&03;
/* assert( size%4 == 0 ) */
while( size ){ /* simple load/store loop */
r->tn.lval -= 4;
l->tn.lval -= 4;
size -= 4;
expand( &xxx, cookie, moves[MOVLSTRNG] );
}
} else {
/* loop code */
loopcode = size >= 20;
if (loopcode) {
cnt = rnames[resc[0].tn.rval];
printf(" mov%c #%d,%s\n", (size<(1<<16))?'w':'l',
size/4-1, cnt);
}
if ( !istnode(l)){
if (l->tn.op==OREG && !R2TEST(l->tn.rval)
&& istreg(l->tn.rval) && l->tn.lval==0)
l->tn.op=REG;
else
l = cpytmp( l, opno++ );
}
if ( !istnode(r) ){
r = cpytmp( r, opno++ );
rcopy = 1; /* this is not our real rhs */
} else
rcopy = 0;
lhs = rnames[l->tn.rval];
rhs = rnames[r->tn.rval];
if (p->in.op==STARG){
/*
* structure argument:
* push space on stack (lea sp@(size),sp)
* copy sp to a temp register we can bomb
* go for it.
*/
if (xsize <(1<<16))
printf( " lea sp@(-%d),sp\n", xsize);
else
printf( " subl #%d,sp\n", xsize);
printf(" movl sp,%s\n", lhs);
}
if (loopcode) {
print_label(labl= getlab());
/* now emit the 2-instruction loop */
printf(" movl %s@+,%s@+\n", rhs, lhs);
printf(" dbra %s,L%d\n", cnt, labl);
if (size>=(1<<16)){
/* "long dbra" */
printf(" clrw %s\n", cnt);
printf(" subql #1,%s\n", cnt);
printf(" jcc L%d\n", labl);
}
} else {
/* use autoincrement mode in an unrolled loop */
int n;
for (n = 0; n < size/4; n++)
printf(" movl %s@+,%s@+\n", rhs, lhs);
}
switch (size&03) {
/* oops -- stuff leftover */
case 3:
printf(" movw %s@+,%s@+\n", rhs, lhs);
/* fall thorugh */
case 1:
printf(" movb %s@,%s@\n", rhs, lhs);
break;
case 2:
printf(" movw %s@,%s@\n", rhs, lhs);
break;
}
if (cookie&(INBREG|INTBREG) && !rcopy){
/* oh damn, must repair damage */
int temp;
temp = p->stn.stsize;
p->stn.stsize &= ~0x3;
if (size <(1<<16))
expand( p, FOREFF, " lea AR@(-ZW),AR\n");
else
expand( p, FOREFF, " subl #ZW,AR\n");
p->stn.stsize = temp;
}
}
if (p->in.op==STARG){
/* keep toff up-to-date */
if (xsize<3){
/* must pad */
printf(" subqw #2,sp\n");
xsize = 4;
}
toff += xsize;
if (toff>maxtoff) maxtoff= toff;
} else {
r = p->in.right;
if ( r->in.op == NAME )
r->in.op = ICON;
else if (!(cookie&SANY) && r->tn.op==OREG && !ISPTR(r->tn.type)){
/* we get to make up a (choke) address here */
if (r->tn.lval == 0){
r->in.op = REG;
r->tn.type = INCREF(r->tn.type);
} else
cerror("trapped in a multiple-structue-assigment");
}
}
}
#undef checkout
/*
* alignfield(p, byteoff)
* Align an operand for a 68020 bit field operation. If byteoff
* is nonzero, subtract it (it was previously added to the offset
* part of p->in.left, possibly resulting in an odd offset). Then
* longword-align the offset, assuming that names and activation
* records are longword-aligned.
*/
static
alignfield(p, byteoff)
register NODE *p; /* assumed to be FLD op */
int byteoff;
{
register NODE *lp; /* assumed to be operand address */
int fieldoff, fieldsize, residue;
lp = p->in.left;
switch( lp->in.op ){
case NAME:
case ICON:
case OREG:
if (byteoff) {
/* undo it */
lp->tn.lval -= byteoff;
}
residue = lp->tn.lval % (SZLONG/SZCHAR);
if (residue < 0) {
/*
* careful about AUTOs --
* the offsets are negative
*/
residue += (SZLONG/SZCHAR);
}
fieldoff = UPKFOFF(p->tn.rval) + residue*SZCHAR;
fieldsize = UPKFSZ(p->tn.rval);
if (fieldoff + fieldsize <= SZLONG) {
/*
* take bytes away from the operand address,
* and put bits back in the field offset.
*/
lp->tn.lval -= residue;
p->tn.rval = PKFIELD(fieldsize, fieldoff);
}
break;
default:
cerror( "illegal address in alignfield" );
break;
}
}
expandfield(p)
register NODE *p;
{
printf( "{#%d:#%d}", UPKFOFF(p->tn.rval), UPKFSZ(p->tn.rval) );
}
void
eval_field( p, c, cookie )
NODE *p;
char c;
{
register temp, m;
register NODE *l, *r;
int lobyte, hibyte;
char *regname;
NODE *fieldnode;
int conval;
l = p->in.left;
r = p->in.right;
fieldnode = (c == 'b') ? p : p->in.left;
lobyte = (SZINT - fldshf - 1)/SZCHAR; /* byte containing low-order bit */
hibyte = (SZINT -fldshf -fldsz)/SZCHAR;/* byte containing high-order bit */
if (fieldnode->in.left->tn.op == REG){
if ( ISPTR(fieldnode->in.left->tn.type)){
fieldnode->in.left->tn.op = OREG;
} else {
/* always use longword accesses to registers */
hibyte = 0;
temp = SZINT;
p->in.type = UNSIGNED;
goto longonly;
}
}
if (lobyte==hibyte){
/* ok to do byte accesses to memory */
temp = SZCHAR;
p->in.type = UCHAR;
} else if ((hibyte&1) || (hibyte < (lobyte-1))){
/* must do longword access */
hibyte = 0;
temp = SZINT;
p->in.type = UNSIGNED;
} else {
/* word access */
temp = SZSHORT;
p->in.type = USHORT;
}
/* adjust shift value, paint over left type and address */
fldshf = temp - (SZINT-fldshf -(hibyte*SZCHAR));
if (hibyte){
incraddr( fieldnode, hibyte);
}
longonly:
switch (c){
case 'a':
/* assignment of a value to a bit field */
/* the two cases are: constant r-h-s, and variable r-h-s */
/* the constant case has several interesting sub-cases */
if (r->tn.op == ICON){
/* easy case */
conval = r->tn.lval;
m = r->tn.lval;
if (fldsz == 1) {
/* very easy case */
print_str_d( (m&1)?" bset #":" bclr #", fldshf); putchar(',');
adrput( l );
} else {
/*
* wide field:
* depending on field size and alignment, we may
* have to do word or longword accesses
*/
if (m==0){
/* clearing entire field */
if (fldshf==0 && fldsz == temp){
/* no masking involved -- whole unit */
expand( p, cookie, " clrZB AL");
} else {
expand( p, cookie, " andZB #N,AL");
}
} else if ( m==-1 || m==BITMASK(fldsz)){
/* setting entire field */
if (fldshf==0 && fldsz == temp){
/* no masking involved -- whole unit */
if (fldsz == SZCHAR) {
expand( p, cookie, " st AL");
} else {
expand( p, cookie, " movZB #CR,AL");
}
} else {
expand( p, cookie, " orZB #M,AL" );
}
} else {
/* -- inserting value -- */
if (fldshf==0 && fldsz == temp){
/* no masking involved -- whole unit */
expand( p, cookie, " movZB #CR,AL");
} else {
m &= BITMASK(fldsz);
r->tn.lval = m<<fldshf;
expand(p, cookie, " andZB #N,AL\n orZB #CR,AL");
}
}
}
/* restore old ICON value in case we want to use it as
the result of the assignment */
r->tn.lval = conval;
} else {
/* non-constant */
/* there are only two cases here :
shifting and masking, or
not shifting or masking
*/
if (fldsz == temp && fldshf == 0){
/* direct move */
expand( p, cookie, " movZB AR,AL");
} else if (use68020) {
/* the normal, ugly case, with 68020 instructions */
alignfield(fieldnode, hibyte);
expand( p, cookie, " bfins AR,AL");
expandfield(fieldnode);
} else {
/* the normal, ugly case, with 68010 instructions */
/* clear field in destination */
expand( p, cookie, " andZB #N,AL\n");
/* move value to temp and adjust */
temp = fldshf;
fldshf = 0;
if (r->tn.op == REG && istreg(r->tn.rval) && (cookie&FOREFF)){
/* do it in place */
regname = rnames[r->tn.rval];
/* mask source to the right number of bits, and */
expand( p, cookie, " andZB #M,AR\n");
/* shift into place */
shiftreg( temp, regname , -1, 0, 'l', UNSIGNED);
/* combine source into destination */
expand( p, cookie, " orZB AR,AL");
} else {
/* must copy over */
rmove( resc[0].tn.rval, r->tn.rval, UNSIGNED );
expand( p, cookie, " andZB #M,A1\n");
regname = rnames[ resc[0].tn.rval ];
shiftreg( temp, regname , -1, 0, 'l', UNSIGNED);
expand( p, cookie, " orZB A1,AL");
}
}
}
p->in.type = UNSIGNED;
return;
case 'b':
/* extracting field value -- either for CC or for value */
if (cookie & FORCC){
compare_with_zero:
/* only extracting value to compare it with zero */
if (fldsz == 1){
/* snap case -- so long as fields are unsigned! */
print_str_d( " btst #", fldshf); putchar(',');
adrput( l );
} else if (fldsz == temp && fldshf == 0){
/* direct memory test */
expand( p, cookie, " tstZB AL");
} else {
/*
* move value into a register -- and with mask to set CC.
* We would have to worry about setting the N condition
* here, but our unsigned-ness prevents this from being
* a problem.
*/
if (l->tn.op == REG && istreg(l->tn.rval)){
expand( p, cookie, " andl #M,AL");
} else {
expand( p, cookie,
" movZB AL,A1\n andZB #M,A1");
}
}
} else {
/* extracting value for value's sake */
if (l->tn.op == REG && istreg(l->tn.rval)){
regname = rnames[ l->tn.rval ];
if (use68020 && fldshf != 0) {
alignfield(fieldnode, hibyte);
expand( p, cookie, " bfextu AL");
expandfield(fieldnode);
putchar(','); print_str(regname);
} else {
shiftreg( -fldshf, regname , resc[0].tn.rval, 0, 'l', UNSIGNED);
fldshf = 0;
expand( p, cookie, " andl #M,AL");
}
} else {
regname = rnames[ resc[0].tn.rval ];
if (use68020 && fldshf != 0) {
alignfield(fieldnode, hibyte);
expand( p, cookie, " bfextu AL");
expandfield(fieldnode);
putchar(','); print_str(regname);
} else {
if (temp != SZINT){
print_str_str_nl(" moveq #0,", regname );
}
expand( p, cookie, " movZB AL,A1");
if (fldsz != temp || fldshf != 0){
putchar('\n');
shiftreg( -fldshf, regname, -1, 0, 'l', UNSIGNED);
fldshf = 0;
expand( p, cookie, " andZB #M,A1");
}
}
}
}
fieldnode->in.type = UNSIGNED;
return;
case 'c':
/* comparison of field value with constant value for CC only */
m = r->tn.lval;
if (m==0) goto compare_with_zero;
r->tn.lval = m << fldshf;
if (temp == fldsz && fldshf == 0 ){
/* compare directly to memory */
expand(p, cookie, " cmpZB #CR,AL");
} else if (l->tn.op == REG && istreg(l->tn.rval) && cookie&FOREFF){
/* munge in place */
expand( p, cookie," andZB #M,AL\n cmpZB #CR,AL");
} else {
/* move to register, mask, compare */
expand( p, cookie,
" movZB AL,A1\n andZB #M,A1\n cmpZB #CR,A1");
}
}
}
/* routine used by the field-evaluation code to emit shifting instructions.
"val" is the amount to shift, s is the name of the register to shift,
and "reg" is the register NUMBER of a helper, if one is available.
If val<0, we're doing right shifts
If needclr != 0, must clear lower word after swap.
*/
void
shiftreg( val, s , reg, needclr, typechar, type )
char *s;
char typechar;
{
char *t;
char *shift = "lsll";
int lshift;
if (val < 0 ){
shift = "lsrl";
val = -val;
lshift = 0;
} else{
lshift = 1;
shift[0] = (ISUNSIGNED(type) || ISPTR(type))? 'l' : 'a';
}
shift[3] = typechar; /* ugly hack */
if (val > 16 ){
if (reg >= 0){
printf(" movl #%d,%s\n", val, t=rnames[ reg ]);
printf(" %s %s,%s\n", shift, t, s);
trapv(type);
return;
}
if (!(chk_ovfl && shift[0] == 'a')){
print_str_str_nl(" swap ", s);
if (needclr&&lshift)
print_str_str_nl(" clrw ", s);
val -= 16;
}
}
while (val > 0){
if (val> 8){
printf(" %s #8,%s\n", shift, s);
val -= 8;
} else {
if (val==1 && lshift)
printf(" add%c %s,%s\n", typechar, s,s);
else
printf(" %s #%d,%s\n", shift, val, s);
val = 0;
}
trapv(type);
}
}
void
incraddr( p , v)
register NODE *p;
long v;
{
/* bump the address p by the value b. */
if( p->in.op == FLD ){
p = p->in.left;
}
switch( p->in.op ){
case NAME:
case ICON:
case OREG:
p->tn.lval += v;
break;
default:
cerror( "illegal incraddr address" );
break;
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
insput( p ) register NODE *p;
{
#ifndef IEEECCODES
printf(ccodes[p->in.op-EQ]);
#else IEEECCODES
if (ISFLOATING(p->in.left->in.type)) {
printf(fccodes[p->in.op-EQ]);
} else {
printf(ccodes[p->in.op-EQ]);
}
#endif IEEECCODES
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/*
* Generate conditional branches from a relational operator.
* The exact form of the branch depends on:
* 1. whether or not the compared operands have floating point types
* 2. whether or not the coprocessor condition code is used
* 3. whether the operator has been negated.
*/
cbgen( o, type, label, reversed, mode )
int o; /* relational op {EQ, NE, LT, LE, ...} */
TWORD type; /* operand type - determines opcode */
int label; /* destination label */
int reversed; /* =1 if op is to be negated */
int mode; /* if FCCODES, use coprocessor condition codes */
{
char *prefix;
char *opname;
#ifndef IEEECCODES
if (reversed) {
/* treat !(a < b) as (a >= b) */
o = negrel[o-EQ];
}
if (mode == FCCODES) {
prefix = "fj";
opname = fccodes[o-EQ];
} else {
prefix = "j";
opname = ccodes[o-EQ];
}
#else IEEECCODES
if (ISFLOATING(type)) {
prefix = (mode == FCCODES ? "fj" : "jf");
opname = (reversed ? fnegccodes[o-EQ] : fccodes[o-EQ]);
} else {
prefix = "j";
if (reversed)
o = negrel[o-EQ];
opname = ccodes[o-EQ];
}
#endif IEEECCODES
printf(" %s%s L%d\n", prefix, opname, label);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
#ifdef FORT
branch(lab)
int lab;
{
printf(" jra L%d\n", lab);
}
#endif FORT