V9/cmd/sun/pcc/local2.c

Compare this file to the similar file:
Show the results in this format:

#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