xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 33351)
132890Sdonn #ifndef lint
2*33351Sdonn static char sccsid[] = "@(#)local2.c	1.29 (Berkeley) 01/14/88";
332890Sdonn #endif
425828Ssam 
526076Ssam # include "pass2.h"
626076Ssam # include <ctype.h>
726162Ssam 
826162Ssam # define putstr(s)	fputs((s), stdout)
929672Ssam # define ISCHAR(p)	(p->in.type == UCHAR || p->in.type == CHAR)
1026162Ssam 
1125828Ssam # ifdef FORT
1225828Ssam int ftlab1, ftlab2;
1325828Ssam # endif
1425828Ssam /* a lot of the machine dependent parts of the second pass */
1525828Ssam 
1625828Ssam # define BITMASK(n) ((1L<<n)-1)
1725828Ssam 
1825828Ssam # ifndef ONEPASS
1932886Sdonn /*ARGSUSED*/
2025828Ssam where(c){
2125828Ssam 	fprintf( stderr, "%s, line %d: ", filename, lineno );
2225828Ssam 	}
2325828Ssam # endif
2425828Ssam 
2525828Ssam lineid( l, fn ) char *fn; {
2625828Ssam 	/* identify line l and file fn */
2725828Ssam 	printf( "#	line %d, file %s\n", l, fn );
2825828Ssam 	}
2925828Ssam 
3025828Ssam int ent_mask;
3125828Ssam 
3225828Ssam eobl2(){
3325828Ssam 	register OFFSZ spoff;	/* offset from stack pointer */
3425828Ssam #ifndef FORT
3525828Ssam 	extern int ftlab1, ftlab2;
3625828Ssam #endif
3725828Ssam 
3825828Ssam 	spoff = maxoff;
3925828Ssam 	spoff /= SZCHAR;
4025828Ssam 	SETOFF(spoff,4);
4125828Ssam #ifdef FORT
4225828Ssam #ifndef FLEXNAMES
4332886Sdonn 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
4425828Ssam #else
4525828Ssam 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
4632886Sdonn 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
4725828Ssam #endif
4825828Ssam 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
4925828Ssam #else
5025828Ssam 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
5125828Ssam 	printf( "L%d:\n", ftlab1);
5225828Ssam 	if( maxoff > AUTOINIT )
5332886Sdonn 		printf( "	subl3	$%ld,fp,sp\n", spoff);
5425828Ssam 	printf( "	jbr 	L%d\n", ftlab2);
5525828Ssam #endif
5625828Ssam 	ent_mask = 0;
5725828Ssam 	maxargs = -1;
5825828Ssam 	}
5925828Ssam 
6025828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = {
6125828Ssam 
6225828Ssam 	PLUS,	"add",
6325828Ssam 	MINUS,	"sub",
6425828Ssam 	MUL,	"mul",
6525828Ssam 	DIV,	"div",
6625828Ssam 	MOD,	"div",
6725828Ssam 	OR,	"or",
6825828Ssam 	ER,	"xor",
6925828Ssam 	AND,	"and",
7025828Ssam 	-1,	""    };
7125828Ssam 
7225828Ssam hopcode( f, o ){
7325828Ssam 	/* output the appropriate string from the above table */
7425828Ssam 
7525828Ssam 	register struct hoptab *q;
7625828Ssam 
7725828Ssam 	if(asgop(o))
7825828Ssam 		o = NOASG o;
7925828Ssam 	for( q = ioptab;  q->opmask>=0; ++q ){
8025828Ssam 		if( q->opmask == o ){
8125828Ssam 			if(f == 'E')
8225828Ssam 				printf( "e%s", q->opstring);
8325828Ssam 			else
8425828Ssam 				printf( "%s%c", q->opstring, tolower(f));
8525828Ssam 			return;
8625828Ssam 			}
8725828Ssam 		}
8825828Ssam 	cerror( "no hoptab for %s", opst[o] );
8925828Ssam 	}
9025828Ssam 
9125828Ssam char *
9225828Ssam rnames[] = {  /* keyed to register number tokens */
9325828Ssam 
9425828Ssam 	"r0", "r1",
9525828Ssam 	"r2", "r3", "r4", "r5",
9625828Ssam 	"r6", "r7", "r8", "r9", "r10", "r11",
9725828Ssam 	"r12", "fp", "sp", "pc",
9825828Ssam 	};
9925828Ssam 
10025828Ssam /* output register name and update entry mask */
10125828Ssam char *
10225828Ssam rname(r)
10325828Ssam 	register int r;
10425828Ssam {
10525828Ssam 
10632887Sdonn 	if (!istreg(r))
10732887Sdonn 		ent_mask |= 1<<r;
10825828Ssam 	return(rnames[r]);
10925828Ssam }
11025828Ssam 
11125828Ssam int rstatus[] = {
11225828Ssam 	SAREG|STAREG, SAREG|STAREG,
11325828Ssam 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
11425828Ssam 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
11525828Ssam 	SAREG, SAREG, SAREG, SAREG,
11625828Ssam 	};
11725828Ssam 
11825828Ssam tlen(p) NODE *p;
11925828Ssam {
12025828Ssam 	switch(p->in.type) {
12125828Ssam 		case CHAR:
12225828Ssam 		case UCHAR:
12325828Ssam 			return(1);
12425828Ssam 
12525828Ssam 		case SHORT:
12625828Ssam 		case USHORT:
12732886Sdonn 			return(SZSHORT/SZCHAR);
12825828Ssam 
12925828Ssam 		case DOUBLE:
13032886Sdonn 			return(SZDOUBLE/SZCHAR);
13125828Ssam 
13225828Ssam 		default:
13332886Sdonn 			return(SZINT/SZCHAR);
13425828Ssam 		}
13525828Ssam }
13625828Ssam 
13732886Sdonn mixtypes(p, q) NODE *p, *q;
13830360Ssam {
13930360Ssam 	register TWORD tp, tq;
14030360Ssam 
14130360Ssam 	tp = p->in.type;
14230360Ssam 	tq = q->in.type;
14332886Sdonn 
14432886Sdonn 	return( (tp==FLOAT || tp==DOUBLE) !=
14532886Sdonn 		(tq==FLOAT || tq==DOUBLE) );
14630360Ssam }
14730360Ssam 
14825828Ssam prtype(n) NODE *n;
14925828Ssam {
15025828Ssam 	switch (n->in.type)
15125828Ssam 		{
15225828Ssam 
15325828Ssam 		case DOUBLE:
15426162Ssam 			putchar('d');
15525828Ssam 			return;
15625828Ssam 
15725828Ssam 		case FLOAT:
15826162Ssam 			putchar('f');
15925828Ssam 			return;
16025828Ssam 
16132886Sdonn 		case LONG:
16232886Sdonn 		case ULONG:
16325828Ssam 		case INT:
16425828Ssam 		case UNSIGNED:
16526162Ssam 			putchar('l');
16625828Ssam 			return;
16725828Ssam 
16825828Ssam 		case SHORT:
16925828Ssam 		case USHORT:
17026162Ssam 			putchar('w');
17125828Ssam 			return;
17225828Ssam 
17325828Ssam 		case CHAR:
17425828Ssam 		case UCHAR:
17526162Ssam 			putchar('b');
17625828Ssam 			return;
17725828Ssam 
17825828Ssam 		default:
17925828Ssam 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
18025828Ssam 			else {
18126162Ssam 				putchar('l');
18225828Ssam 				return;
18325828Ssam 				}
18425828Ssam 		}
18525828Ssam }
18625828Ssam 
18725828Ssam zzzcode( p, c ) register NODE *p; {
18825828Ssam 	register int m;
18925828Ssam 	int val;
19025828Ssam 	switch( c ){
19125828Ssam 
19225828Ssam 	case 'N':  /* logical ops, turned into 0-1 */
19325828Ssam 		/* use register given by register 1 */
19425828Ssam 		cbgen( 0, m=getlab(), 'I' );
19525828Ssam 		deflab( p->bn.label );
19625828Ssam 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
19725828Ssam 		deflab( m );
19825828Ssam 		return;
19925828Ssam 
20025828Ssam 	case 'P':
20125828Ssam 		cbgen( p->in.op, p->bn.label, c );
20225828Ssam 		return;
20325828Ssam 
20432876Sdonn 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
20525828Ssam 		{
20632876Sdonn 		register NODE *l, *r, *s;
20732876Sdonn 		int lt, rt;
20825828Ssam 
20932876Sdonn 		l = p->in.left;
21032876Sdonn 		r = p->in.right;
21132876Sdonn 		s = talloc();
21232876Sdonn 		rt = r->in.type;
21332876Sdonn 		lt = l->in.type;
21425828Ssam 
21532876Sdonn 		if (lt != INT && lt != UNSIGNED) {
21632876Sdonn 			s->in.op = SCONV;
21732876Sdonn 			s->in.left = l;
21832876Sdonn 			s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
21932876Sdonn 			zzzcode(s, 'U');
22032876Sdonn 			putstr("\n\t");
22125828Ssam 		}
22232876Sdonn 
22332876Sdonn 		if (ISUNSIGNED(lt)) {
22432876Sdonn 			s->in.op = SCONV;
22532876Sdonn 			s->in.left = lt == UNSIGNED ? l : resc;
22632876Sdonn 			s->in.type = rt;
22732876Sdonn 			unsigned_to_float(s);
22832876Sdonn 		} else {
22932876Sdonn 			putstr("cvl");
23032876Sdonn 			prtype(r);
23132876Sdonn 			putchar('\t');
23232876Sdonn 			adrput(lt == INT ? l : resc);
23332876Sdonn 		}
23432876Sdonn 		putstr("\n\t");
23532876Sdonn 
23632876Sdonn 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
23726162Ssam 		putchar('\t');
23825828Ssam 		adrput(r);
23932876Sdonn 
24032876Sdonn 		if (ISUNSIGNED(lt)) {
24132876Sdonn 			putstr("\n\t");
24232876Sdonn 			s->in.op = SCONV;
24332876Sdonn 			s->in.left = r;		/* we need only the type */
24432876Sdonn 			s->in.type = UNSIGNED;
24532876Sdonn 			float_to_unsigned(s);
24632876Sdonn 		} else {
24732876Sdonn 			putstr("\n\tcv");
24832876Sdonn 			prtype(r);
24932876Sdonn 			putstr("l\t");
25032876Sdonn 			if (lt == INT)
25132876Sdonn 				adrput(l);
25232876Sdonn 			else
25332876Sdonn 				adrput(resc);
25432876Sdonn 		}
25532876Sdonn 		if (lt != INT) {
25632876Sdonn 			putstr("\n\t");
25732876Sdonn 			s->in.op = ASSIGN;
25832876Sdonn 			s->in.left = l;
25932876Sdonn 			s->in.right = resc;
26032876Sdonn 			s->in.type = lt;
26132876Sdonn 			zzzcode(s, 'U');
26232876Sdonn 		}
26332876Sdonn 
26432876Sdonn 		s->in.op = FREE;
26525828Ssam 		return;
26625828Ssam 		}
26725828Ssam 
26832886Sdonn 	case 'J':	/* unsigned DIV/MOD with constant divisors */
26932886Sdonn 		{
27032886Sdonn 		register int ck = INAREG;
27132886Sdonn 		int label1, label2;
27232886Sdonn 
27332886Sdonn 		/* case constant <= 1 is handled by optim() in pass 1 */
27432886Sdonn 		/* case constant < 0x80000000 is handled in table */
27532886Sdonn 		switch( p->in.op ) {
27632887Sdonn 		/* case DIV: handled in optim2() */
27732886Sdonn 		case MOD:
27832886Sdonn 			if( p->in.left->in.op == REG &&
27932886Sdonn 			    p->in.left->tn.rval == resc->tn.rval )
28032886Sdonn 				goto asgmod;
28132886Sdonn 			label1 = getlab();
28232886Sdonn 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
28332886Sdonn 			printf("\tjlssu\tL%d\n", label1);
28432886Sdonn 			expand(p, ck, "\tsubl2\tAR,A1\n");
28532886Sdonn 			printf("L%d:", label1);
28632886Sdonn 			break;
28732886Sdonn 		case ASG DIV:
28832886Sdonn 			label1 = getlab();
28932886Sdonn 			label2 = getlab();
29032886Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
29132886Sdonn 			printf("\tjgequ\tL%d\n", label1);
29232886Sdonn 			expand(p, ck, "\tmovl\t$1,AL\n");
29332886Sdonn 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
29432886Sdonn 			expand(p, ck, "\tclrl\tAL\n");
29532886Sdonn 			printf("L%d:", label2);
29632886Sdonn 			break;
29732886Sdonn 		case ASG MOD:
29832886Sdonn 		asgmod:
29932886Sdonn 			label1 = getlab();
30032886Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
30132886Sdonn 			printf("\tjlssu\tL%d\n", label1);
30232886Sdonn 			expand(p, ck, "\tsubl2\tAR,AL\n");
30332886Sdonn 			printf("L%d:", label1);
30432886Sdonn 			break;
30532886Sdonn 			}
30632886Sdonn 		return;
30732886Sdonn 		}
30832886Sdonn 
30925828Ssam 	case 'B':	/* get oreg value in temp register for shift */
31025828Ssam 		{
31125828Ssam 		register NODE *r;
31225828Ssam 		if (xdebug) eprint(p, 0, &val, &val);
31325828Ssam 		r = p->in.right;
31432886Sdonn 		if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
31526162Ssam 			putstr("movl");
31625828Ssam 		else {
31726162Ssam 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
31825828Ssam 			prtype(r);
31926162Ssam 			putchar('l');
32025828Ssam 			}
32125828Ssam 		return;
32225828Ssam 		}
32325828Ssam 
32432886Sdonn 	case 'C':	/* generate 'call[fs] $bytes' */
32525828Ssam 		{
32625828Ssam 		extern int gc_numbytes;
32725828Ssam 		extern int xdebug;
32825828Ssam 
32925828Ssam 		if (xdebug) printf("->%d<-",gc_numbytes);
33025828Ssam 
33125828Ssam 		printf("call%c	$%d",
33225828Ssam 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
33325828Ssam 		 gc_numbytes+4);
33432886Sdonn 		/* don't change to double (here's the only place to catch it) */
33525828Ssam 		if(p->in.type == FLOAT)
33625828Ssam 			rtyflg = 1;
33725828Ssam 		return;
33825828Ssam 		}
33925828Ssam 
34025828Ssam 	case 'D':	/* INCR and DECR */
34132876Sdonn 		zzzcode(p->in.left, 'U');
34226162Ssam 		putstr("\n	");
34325828Ssam 
34425828Ssam 	case 'E':	/* INCR and DECR, FOREFF */
34525828Ssam  		if (p->in.right->tn.lval == 1)
34625828Ssam 			{
34726162Ssam 			putstr(p->in.op == INCR ? "inc" : "dec");
34825828Ssam 			prtype(p->in.left);
34926162Ssam 			putchar('\t');
35025828Ssam 			adrput(p->in.left);
35125828Ssam 			return;
35225828Ssam 			}
35326162Ssam 		putstr(p->in.op == INCR ? "add" : "sub");
35425828Ssam 		prtype(p->in.left);
35526162Ssam 		putstr("2	");
35625828Ssam 		adrput(p->in.right);
35726162Ssam 		putchar(',');
35825828Ssam 		adrput(p->in.left);
35925828Ssam 		return;
36025828Ssam 
36125828Ssam 	case 'F':	/* masked constant for fields */
36225947Ssam 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
36325828Ssam 		return;
36425828Ssam 
36532884Sdonn 	case 'I':	/* produce value of bitfield assignment */
36632884Sdonn 			/* avoid shifts -- shifts are SLOW on this machine */
36732887Sdonn 			/* XXX this wouldn't be necessary if we were smarter
36832887Sdonn 			       and masked BEFORE shifting XXX */
36932884Sdonn 		{
37032886Sdonn 		register NODE *r = p->in.right;
37132886Sdonn 		if(r->in.op == ICON && r->tn.name[0] == '\0') {
37232886Sdonn 			putstr("movl\t");
37332886Sdonn 			printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
37432886Sdonn 			}
37532886Sdonn 		else {
37632886Sdonn 			putstr("andl3\t");
37732886Sdonn 			printf(ACONFMT, (1 << fldsz) - 1);
37832884Sdonn 			putchar(',');
37932886Sdonn 			adrput(r);
38032884Sdonn 			}
38132886Sdonn 		putchar(',');
38232886Sdonn 		adrput(resc);
38332886Sdonn 		break;
38432886Sdonn 		}
38532884Sdonn 
38625828Ssam 	case 'H':	/* opcode for shift */
38725828Ssam 		if(p->in.op == LS || p->in.op == ASG LS)
38826162Ssam 			putstr("shll");
38925828Ssam 		else if(ISUNSIGNED(p->in.left->in.type))
39026162Ssam 			putstr("shrl");
39125828Ssam 		else
39226162Ssam 			putstr("shar");
39325828Ssam 		return;
39425828Ssam 
39525828Ssam 	case 'L':	/* type of left operand */
39625828Ssam 	case 'R':	/* type of right operand */
39725828Ssam 		{
39825828Ssam 		register NODE *n;
39925828Ssam 		extern int xdebug;
40025828Ssam 
40125828Ssam 		n = getlr ( p, c);
40225828Ssam 		if (xdebug) printf("->%d<-", n->in.type);
40325828Ssam 
40425828Ssam 		prtype(n);
40525828Ssam 		return;
40625828Ssam 		}
40725828Ssam 
40830360Ssam 	case 'M': {  /* initiate ediv for mod and unsigned div */
40932887Sdonn 		putstr("clrl\t");
41032887Sdonn 		adrput(resc);
41132887Sdonn 		putstr("\n\tmovl\t");
41225828Ssam 		adrput(p->in.left);
41332887Sdonn 		putchar(',');
41432887Sdonn 		upput(resc, SZLONG);
41532887Sdonn 		printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
41632887Sdonn 		adrput(resc);
41732887Sdonn 		putchar('\n');
41832887Sdonn 		deflab(m);
41925828Ssam 		return;
42030360Ssam 	}
42125828Ssam 
42230360Ssam 	case 'T': {	/* rounded structure length for arguments */
42330360Ssam 		int size = p->stn.stsize;
42425828Ssam 		SETOFF( size, 4);
42525828Ssam 		printf("movab	-%d(sp),sp", size);
42625828Ssam 		return;
42730360Ssam 	}
42825828Ssam 
42925828Ssam 	case 'S':  /* structure assignment */
43025977Ssam 		stasg(p);
43125977Ssam 		break;
43225828Ssam 
43332886Sdonn #ifdef I_don_t_understand_this
43429672Ssam 	case 'X':	/* multiplication for short and char */
43529672Ssam 		if (ISUNSIGNED(p->in.left->in.type))
43629672Ssam 			printf("\tmovz");
43729672Ssam 		else
43829672Ssam 			printf("\tcvt");
43929672Ssam 		zzzcode(p, 'L');
44029672Ssam 		printf("l\t");
44129672Ssam 		adrput(p->in.left);
44229672Ssam 		printf(",");
44329672Ssam 		adrput(&resc[0]);
44429672Ssam 		printf("\n");
44529672Ssam 		if (ISUNSIGNED(p->in.right->in.type))
44629672Ssam 			printf("\tmovz");
44729672Ssam 		else
44829672Ssam 			printf("\tcvt");
44929672Ssam 		zzzcode(p, 'R');
45029672Ssam 		printf("l\t");
45129672Ssam 		adrput(p->in.right);
45229672Ssam 		printf(",");
45329672Ssam 		adrput(&resc[1]);
45429672Ssam 		printf("\n");
45529672Ssam 		return;
45632886Sdonn #endif
45729672Ssam 
45830360Ssam 	case 'U':		/* SCONV */
45930360Ssam 	case 'V':		/* SCONV with FORCC */
46030360Ssam 		sconv(p, c == 'V');
46130360Ssam 		break;
46230360Ssam 
46332879Sdonn 	case 'W': {		/* SCONV or ASSIGN float/double => unsigned */
46432879Sdonn 		NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
46532879Sdonn 
46632876Sdonn 		putstr("ld");
46732879Sdonn 		prtype(src);
46832876Sdonn 		putchar('\t');
46932879Sdonn 		adrput(src);
47032876Sdonn 		putstr("\n\t");
47132876Sdonn 		float_to_unsigned(p);
47232876Sdonn 		break;
47332879Sdonn 	}
47432876Sdonn 
47532879Sdonn 	case 'Y':		/* SCONV or ASSIGN unsigned => float/double */
47632876Sdonn 		unsigned_to_float(p);	/* stores into accumulator */
47732876Sdonn 		putstr("\n\tst");
47832876Sdonn 		prtype(p);
47932876Sdonn 		putchar('\t');
48032879Sdonn 		if (p->in.op == SCONV)
48132879Sdonn 			adrput(resc);
48232879Sdonn 		else
48332879Sdonn 			adrput(p->in.left);
48432879Sdonn 		rtyflg = 1;
48532876Sdonn 		break;
48632876Sdonn 
48732886Sdonn #ifdef I_don_t_understand_this
48830360Ssam 	case 'Z':
48930360Ssam 		p = p->in.right;
49030360Ssam 		switch (p->in.type) {
49130360Ssam 		case SHORT: {
49230360Ssam 			short w = p->tn.lval;
49330360Ssam 			p->tn.lval = w;
49430360Ssam 			break;
49530360Ssam 		}
49630360Ssam 		case CHAR: {
49730360Ssam 			char c = p->tn.lval;
49830360Ssam 			p->tn.lval = c;
49930360Ssam 			break;
50030360Ssam 		}
50130360Ssam 		}
50230360Ssam 		printf("$%d", p->tn.lval);
50330360Ssam 		break;
50432886Sdonn #endif
50530360Ssam 
50625977Ssam 	default:
50725977Ssam 		cerror( "illegal zzzcode" );
50825977Ssam 	}
50930360Ssam }
51025828Ssam 
51125977Ssam #define	MOVB(dst, src, off) { \
51226162Ssam 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
51325977Ssam 	upput(dst, off); putchar('\n'); \
51425977Ssam }
51525977Ssam #define	MOVW(dst, src, off) { \
51626162Ssam 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
51725977Ssam 	upput(dst, off); putchar('\n'); \
51825977Ssam }
51925977Ssam #define	MOVL(dst, src, off) { \
52026162Ssam 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
52125977Ssam 	upput(dst, off); putchar('\n'); \
52225977Ssam }
52325977Ssam /*
52425977Ssam  * Generate code for a structure assignment.
52525977Ssam  */
52625977Ssam stasg(p)
52725977Ssam 	register NODE *p;
52825977Ssam {
52925977Ssam 	register NODE *l, *r;
53025977Ssam 	register int size;
53125828Ssam 
53225977Ssam 	switch (p->in.op) {
53325977Ssam 	case STASG:			/* regular assignment */
53425977Ssam 		l = p->in.left;
53525977Ssam 		r = p->in.right;
53625977Ssam 		break;
53725977Ssam 	case STARG:			/* place arg on the stack */
53825977Ssam 		l = getlr(p, '3');
53925977Ssam 		r = p->in.left;
54025977Ssam 		break;
54125977Ssam 	default:
54225977Ssam 		cerror("STASG bad");
54325977Ssam 		/*NOTREACHED*/
54425977Ssam 	}
54525977Ssam 	/*
54625977Ssam 	 * Pun source for use in code generation.
54725977Ssam 	 */
54825977Ssam 	switch (r->in.op) {
54925977Ssam 	case ICON:
55025977Ssam 		r->in.op = NAME;
55125977Ssam 		break;
55225977Ssam 	case REG:
55325977Ssam 		r->in.op = OREG;
55425977Ssam 		break;
55525977Ssam 	default:
55625977Ssam 		cerror( "STASG-r" );
55725977Ssam 		/*NOTREACHED*/
55825977Ssam 	}
55925977Ssam 	size = p->stn.stsize;
56025977Ssam 	if (size <= 0 || size > 65535)
56125977Ssam 		cerror("structure size out of range");
56225977Ssam 	/*
56325977Ssam 	 * Generate optimized code based on structure size
56425977Ssam 	 * and alignment properties....
56525977Ssam 	 */
56625977Ssam 	switch (size) {
56725828Ssam 
56825977Ssam 	case 1:
56926162Ssam 		putstr("\tmovb\t");
57025977Ssam 	optimized:
57125977Ssam 		adrput(r);
57226162Ssam 		putchar(',');
57325977Ssam 		adrput(l);
57426162Ssam 		putchar('\n');
57525977Ssam 		break;
57625828Ssam 
57725977Ssam 	case 2:
57825977Ssam 		if (p->stn.stalign != 2) {
57925977Ssam 			MOVB(l, r, SZCHAR);
58026162Ssam 			putstr("\tmovb\t");
58125977Ssam 		} else
58226162Ssam 			putstr("\tmovw\t");
58325977Ssam 		goto optimized;
58425977Ssam 
58525977Ssam 	case 4:
58625977Ssam 		if (p->stn.stalign != 4) {
58725977Ssam 			if (p->stn.stalign != 2) {
58825977Ssam 				MOVB(l, r, 3*SZCHAR);
58925977Ssam 				MOVB(l, r, 2*SZCHAR);
59025977Ssam 				MOVB(l, r, 1*SZCHAR);
59126162Ssam 				putstr("\tmovb\t");
59225947Ssam 			} else {
59325977Ssam 				MOVW(l, r, SZSHORT);
59426162Ssam 				putstr("\tmovw\t");
59525828Ssam 			}
59625977Ssam 		} else
59726162Ssam 			putstr("\tmovl\t");
59825977Ssam 		goto optimized;
59925828Ssam 
60025977Ssam 	case 6:
60125977Ssam 		if (p->stn.stalign != 2)
60225977Ssam 			goto movblk;
60325977Ssam 		MOVW(l, r, 2*SZSHORT);
60425977Ssam 		MOVW(l, r, 1*SZSHORT);
60526162Ssam 		putstr("\tmovw\t");
60625977Ssam 		goto optimized;
60725977Ssam 
60825977Ssam 	case 8:
60925977Ssam 		if (p->stn.stalign == 4) {
61025977Ssam 			MOVL(l, r, SZLONG);
61126162Ssam 			putstr("\tmovl\t");
61225977Ssam 			goto optimized;
61325977Ssam 		}
61425977Ssam 		/* fall thru...*/
61525977Ssam 
61625977Ssam 	default:
61725977Ssam 	movblk:
61825977Ssam 		/*
61925977Ssam 		 * Can we ever get a register conflict with R1 here?
62025977Ssam 		 */
62126162Ssam 		putstr("\tmovab\t");
62232890Sdonn 		if(r->in.op == OREG && r->tn.rval == R1)
62332890Sdonn 		{
62432890Sdonn 			adrput(r);
62532890Sdonn 			printf(",r0\n\tmovab\t");
62632890Sdonn 			adrput(l);
62732890Sdonn 			putstr(",r1\n");
62832890Sdonn 		}
62932890Sdonn 		else
63032890Sdonn 		{
63132890Sdonn 			adrput(l);
63232890Sdonn 			putstr(",r1\n\tmovab\t");
63332890Sdonn 			adrput(r);
63432890Sdonn 			printf(",r0\n");
63532890Sdonn 		}
63632890Sdonn 		printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
63725977Ssam 		rname(R2);
63825828Ssam 		break;
63925977Ssam 	}
64025977Ssam 	/*
64125977Ssam 	 * Reverse above pun for reclaim.
64225977Ssam 	 */
64325977Ssam 	if (r->in.op == NAME)
64425977Ssam 		r->in.op = ICON;
64525977Ssam 	else if (r->in.op == OREG)
64625977Ssam 		r->in.op = REG;
64725977Ssam }
64825828Ssam 
64925977Ssam /*
65032876Sdonn  * Convert a float or double in the accumulator into an unsigned int.
65132876Sdonn  * Unlike the vax, the tahoe stores 0 into the destination
65232876Sdonn  *	on a conversion of > 2 ** 31, so we compensate.
65332876Sdonn  */
65432876Sdonn float_to_unsigned(p)
65532876Sdonn 	NODE *p;
65632876Sdonn {
65732876Sdonn 	register NODE *l = p->in.left;
65832876Sdonn 	int label1 = getlab();
65932876Sdonn 	int label2 = getlab();
66032876Sdonn 	int label3 = getlab();
66132879Sdonn 	NODE *src, *dst;
66232876Sdonn 
66332879Sdonn 	if (p->in.op == SCONV) {
66432879Sdonn 		src = p->in.left;
66532879Sdonn 		dst = resc;
66632879Sdonn 	} else {
66732879Sdonn 		src = p->in.right;
66832879Sdonn 		dst = p->in.left;
66932879Sdonn 	}
67032879Sdonn 
67132876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
67232879Sdonn 	if (src->in.type == DOUBLE)
67332879Sdonn 		putstr(", 0x00000000 # .double");
67432879Sdonn 	else
67532879Sdonn 		putstr(" # .float");
67632879Sdonn 	putstr(" 2147483648\n\t.text\n\tcmp");
67732879Sdonn 	prtype(src);
67832876Sdonn 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
67932879Sdonn 	prtype(src);
68032876Sdonn 	printf("\tL%d\n\tcv", label1);
68132879Sdonn 	prtype(src);
68232876Sdonn 	putstr("l\t");
68332879Sdonn 	adrput(dst);
68432876Sdonn 	putstr("\n\taddl2\t$-2147483648,");
68532879Sdonn 	adrput(dst);
68632876Sdonn 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
68732879Sdonn 	prtype(src);
68832876Sdonn 	putstr("l\t");
68932879Sdonn 	adrput(dst);
69032876Sdonn 	printf("\nL%d:", label3);
69132876Sdonn }
69232876Sdonn 
69332876Sdonn /*
69432876Sdonn  * Convert an unsigned int into a float or double, leaving the result
69532876Sdonn  *	in the accumulator.
69632876Sdonn  */
69732876Sdonn unsigned_to_float(p)
69832876Sdonn 	register NODE *p;
69932876Sdonn {
70032876Sdonn 	int label1 = getlab();
70132876Sdonn 	int label2 = getlab();
70232879Sdonn 	NODE *src, *dst;
70332876Sdonn 
70432879Sdonn 	if (p->in.op == SCONV) {
70532879Sdonn 		src = p->in.left;
70632879Sdonn 		dst = resc;
70732879Sdonn 	} else {
70832879Sdonn 		src = p->in.right;
70932879Sdonn 		dst = p->in.left;
71032879Sdonn 	}
71132879Sdonn 
71232876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
71332876Sdonn 	if (p->in.type == DOUBLE)
71432879Sdonn 		putstr(", 0x00000000 # .double");
71532879Sdonn 	else
71632879Sdonn 		putstr(" # .float");
71732879Sdonn 	putstr(" 4294967296\n\t.text\n\tmovl\t");
71832879Sdonn 	adrput(src);
71932876Sdonn 	putchar(',');
72032879Sdonn 	adrput(dst);
72132876Sdonn 	putstr("\n\tcvl");
72232876Sdonn 	prtype(p);
72332876Sdonn 	putchar('\t');
72432879Sdonn 	adrput(dst);
72532879Sdonn 	printf("\n\tjgeq\tL%d\n\tadd", label1);
72632879Sdonn 	prtype(p);
72732879Sdonn 	printf("\tL%d\nL%d:", label2, label1);
72832876Sdonn }
72932876Sdonn 
73032876Sdonn /*
73132875Sdonn  * Prlen() is a cheap prtype()...
73232875Sdonn  */
73332875Sdonn static char convtab[SZINT/SZCHAR + 1] = {
73432875Sdonn 	'?', 'b', 'w', '?', 'l'
73532875Sdonn };
73632875Sdonn #define	prlen(len)	putchar(convtab[len])
73732875Sdonn 
73832875Sdonn 
73932875Sdonn /*
74032873Sdonn  * Generate code for integral scalar conversions.
74132875Sdonn  * Some of this code is designed to work around a tahoe misfeature
74232875Sdonn  *	that causes sign- and zero- extension to be defeated in
74332875Sdonn  *	certain circumstances.
74432875Sdonn  * Basically if the source operand of a CVT or MOVZ instruction is
74532875Sdonn  *	shorter than the destination, and the source is a register
74632875Sdonn  *	or an immediate constant, sign- and zero- extension are
74732875Sdonn  *	ignored and the high bits of the source are copied.  (Note
74832875Sdonn  *	that zero-extension is not a problem for immediate
74932875Sdonn  *	constants.)
750*33351Sdonn  * Another problem -- condition codes for a conversion with a
751*33351Sdonn  *	register source reflect the source rather than the destination.
75232873Sdonn  */
75332873Sdonn sconv(p, forcc)
75432873Sdonn 	NODE *p;
75532873Sdonn 	int forcc;
75632873Sdonn {
75732873Sdonn 	register NODE *src, *dst;
75832873Sdonn 	register NODE *tmp;
75932873Sdonn 	register int srclen, dstlen;
76032873Sdonn 	int srctype, dsttype;
76132873Sdonn 	int val;
76232882Sdonn 	int neg = 0;
76330360Ssam 
76432873Sdonn 	if (p->in.op == ASSIGN) {
76532879Sdonn 		src = p->in.right;
76632879Sdonn 		dst = p->in.left;
76732873Sdonn 		dstlen = tlen(dst);
76832873Sdonn 		dsttype = dst->in.type;
76932879Sdonn 	} else if (p->in.op == SCONV) {
77032879Sdonn 		src = p->in.left;
77132879Sdonn 		dst = resc;
77232873Sdonn 		dstlen = tlen(p);
77332873Sdonn 		dsttype = p->in.type;
77432879Sdonn 	} else /* if (p->in.op == OPLEAF) */ {
77532879Sdonn 		src = p;
77632879Sdonn 		dst = resc;
77732879Sdonn 		dstlen = SZINT/SZCHAR;
77832879Sdonn 		dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
77932873Sdonn 	}
78032873Sdonn 
78132875Sdonn 	if (src->in.op == REG) {
78232875Sdonn 		srclen = SZINT/SZCHAR;
78332875Sdonn 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
78432875Sdonn 	} else {
78532875Sdonn 		srclen = tlen(src);
78632875Sdonn 		srctype = src->in.type;
78732875Sdonn 	}
78832873Sdonn 
78932882Sdonn 	if (src->in.op == ICON && src->tn.name[0] == '\0') {
79032875Sdonn 		if (src->tn.lval == 0) {
79132875Sdonn 			putstr("clr");
79232875Sdonn 			prtype(dst);
79332875Sdonn 			putchar('\t');
79432875Sdonn 			adrput(dst);
79532875Sdonn 			return;
79632875Sdonn 		}
79732875Sdonn 		if (dstlen < srclen) {
79832875Sdonn 			switch (dsttype) {
79932875Sdonn 			case CHAR:
80032875Sdonn 				src->tn.lval = (char) src->tn.lval;
80132875Sdonn 				break;
80232875Sdonn 			case UCHAR:
80332875Sdonn 				src->tn.lval = (unsigned char) src->tn.lval;
80432875Sdonn 				break;
80532875Sdonn 			case SHORT:
80632875Sdonn 				src->tn.lval = (short) src->tn.lval;
80732875Sdonn 				break;
80832875Sdonn 			case USHORT:
80932875Sdonn 				src->tn.lval = (unsigned short) src->tn.lval;
81032875Sdonn 				break;
81132875Sdonn 			}
81232875Sdonn 		}
81332875Sdonn 		if (dst->in.op == REG) {
81432875Sdonn 			dsttype = INT;
81532875Sdonn 			dstlen = SZINT/SZCHAR;
81632875Sdonn 		}
81732875Sdonn 		srctype = dsttype;
81832875Sdonn 		srclen = dstlen;
81932887Sdonn 		val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
82032887Sdonn 		if ((unsigned) val < 64) {
82132887Sdonn 			src->tn.lval = val;
82232882Sdonn 			++neg;		/* MNEGx may be shorter */
82332882Sdonn 		}
82432875Sdonn 	}
82532875Sdonn 
82632873Sdonn 	if (srclen < dstlen) {
82732873Sdonn 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
82832873Sdonn 			/* (unsigned short) c; => sign extend to 16 bits */
82932874Sdonn 			putstr("cvtbl\t");
83032873Sdonn 			adrput(src);
83132873Sdonn 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
83232873Sdonn 			adrput(dst);
83332873Sdonn 			putstr("\n\tmovab\t4(sp),sp");
83432873Sdonn 			if (forcc) {
83532873Sdonn 				/* inverted test */
83632873Sdonn 				putstr("\n\tcmpl\t$0,");
83732873Sdonn 				adrput(dst);
83832873Sdonn 			}
83932873Sdonn 			return;
84032873Sdonn 		}
84132873Sdonn 		genconv(ISUNSIGNED(srctype),
84232873Sdonn 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
843*33351Sdonn 			src, dst, forcc);
84432873Sdonn 		return;
84532873Sdonn 	}
84632873Sdonn 
84732873Sdonn 	if (srclen > dstlen && dst->in.op == REG) {
84832875Sdonn 		/* if dst is a register, the result must look like an int */
84932873Sdonn 		if (src->in.op == REG) {
85032873Sdonn 			if (ISUNSIGNED(dsttype)) {
85132873Sdonn 				val = (1 << dstlen * SZCHAR) - 1;
85232873Sdonn 				if (src->tn.rval == dst->tn.rval)
85332873Sdonn 					/* conversion in place */
85432887Sdonn 					printf("andl2\t$%ld,", val);
85532873Sdonn 				else {
85632887Sdonn 					printf("andl3\t$%ld,", val);
85732873Sdonn 					adrput(src);
85832873Sdonn 					putchar(',');
85932873Sdonn 				}
86032873Sdonn 				adrput(dst);
86132873Sdonn 				return;
86232873Sdonn 			}
86332875Sdonn 			/*
86432875Sdonn 			 * Sign extension in register can also be
86532875Sdonn 			 * accomplished by shifts, but unfortunately
86632875Sdonn 			 * shifts are extremely slow, due to the lack
86732875Sdonn 			 * of a barrel shifter.
86832875Sdonn 			 */
86932875Sdonn 			putstr("pushl\t");
87032873Sdonn 			adrput(src);
87132875Sdonn 			putstr("\n\tcvt");
87232875Sdonn 			prlen(dstlen);
87332875Sdonn 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
87432873Sdonn 			adrput(dst);
87532875Sdonn 			putstr("\n\tmovab\t4(sp),sp");
87632875Sdonn 			if (forcc) {
87732875Sdonn 				/* inverted test */
87832875Sdonn 				putstr("\n\tcmpl\t$0,");
87932875Sdonn 				adrput(dst);
88032875Sdonn 			}
88132873Sdonn 			return;
88232873Sdonn 		}
88332873Sdonn 		tmp = talloc();
88432887Sdonn 		if ((src->in.op == NAME) ||
88532887Sdonn 		    (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
88632873Sdonn 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
88732873Sdonn 			/* we can increment src's address & pun it */
88832873Sdonn 			*tmp = *src;
88932873Sdonn 			tmp->tn.lval += srclen - dstlen;
89032873Sdonn 		} else {
89132873Sdonn 			/* we must store src's address */
89232873Sdonn 			*tmp = *dst;
89332875Sdonn 			putstr("mova");
89432875Sdonn 			prlen(srclen);
89532875Sdonn 			putchar('\t');
89632873Sdonn 			adrput(src);
89732873Sdonn 			putchar(',');
89832873Sdonn 			adrput(tmp);
89932874Sdonn 			putstr("\n\t");
90032873Sdonn 			tmp->tn.op = OREG;
90132873Sdonn 			tmp->tn.lval = srclen - dstlen;
90232873Sdonn 		}
903*33351Sdonn 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
90432873Sdonn 		tmp->in.op = FREE;
90532873Sdonn 		return;
90632873Sdonn 	}
90732873Sdonn 
90832882Sdonn 	genconv(neg ? -1 : ISUNSIGNED(dsttype),
90932873Sdonn 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
910*33351Sdonn 		src, dst, forcc);
91132873Sdonn }
91232873Sdonn 
913*33351Sdonn genconv(srcflag, srclen, dstlen, src, dst, forcc)
91432882Sdonn 	int srcflag;
91532875Sdonn 	register int srclen, dstlen;
91632873Sdonn 	NODE *src, *dst;
917*33351Sdonn 	int forcc;
91832873Sdonn {
91932873Sdonn 	if (srclen != dstlen) {
92032882Sdonn 		if (srcflag > 0 && srclen < dstlen)
92132874Sdonn 			putstr("movz");
92232873Sdonn 		else
92332874Sdonn 			putstr("cvt");
92432875Sdonn 		prlen(srclen);
92532882Sdonn 	} else if (srcflag < 0)
92632882Sdonn 		putstr("mneg");
92732882Sdonn 	else
92832874Sdonn 		putstr("mov");
92932875Sdonn 	prlen(dstlen);
93032873Sdonn 	putchar('\t');
93132873Sdonn 	adrput(src);
93232873Sdonn 	putchar(',');
93332873Sdonn 	adrput(dst);
934*33351Sdonn 
935*33351Sdonn 	/*
936*33351Sdonn 	 * This hack is made necessary by architecture problems
937*33351Sdonn 	 *	described above
938*33351Sdonn 	 */
939*33351Sdonn 	if (forcc && src->in.op == REG && srclen > dstlen) {
940*33351Sdonn 		putstr("\n\ttst");
941*33351Sdonn 		prlen(dstlen);
942*33351Sdonn 		putchar('\t');
943*33351Sdonn 		adrput(dst);
944*33351Sdonn 	}
94532873Sdonn }
94632873Sdonn 
94732886Sdonn rmove( rt, rs, t ) TWORD t; {
94825828Ssam 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
94925828Ssam 	if(t==DOUBLE)
95025828Ssam 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
95125828Ssam 	}
95225828Ssam 
95325828Ssam struct respref
95425828Ssam respref[] = {
95525828Ssam 	INTAREG|INTBREG,	INTAREG|INTBREG,
95625828Ssam 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
95725828Ssam 	INTEMP,	INTEMP,
95825828Ssam 	FORARG,	FORARG,
95925828Ssam 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
96025828Ssam 	0,	0 };
96125828Ssam 
96225828Ssam setregs(){ /* set up temporary registers */
96325828Ssam 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
96425828Ssam 	}
96525828Ssam 
96626076Ssam #ifndef szty
96725828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
96825828Ssam 	return(t==DOUBLE ? 2 : 1 );
96925828Ssam 	}
97026076Ssam #endif
97125828Ssam 
97232886Sdonn /*ARGSUSED*/
97325828Ssam rewfld( p ) NODE *p; {
97425828Ssam 	return(1);
97525828Ssam 	}
97625828Ssam 
97732886Sdonn /*ARGSUSED*/
97825828Ssam callreg(p) NODE *p; {
97925828Ssam 	return( R0 );
98025828Ssam 	}
98125828Ssam 
98225828Ssam base( p ) register NODE *p; {
98325828Ssam 	register int o = p->in.op;
98425828Ssam 
98532887Sdonn 	if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
98625828Ssam 	if( o==REG ) return( p->tn.rval );
98725828Ssam     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
98825828Ssam 		return( p->in.left->tn.rval );
98925828Ssam     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
99025828Ssam 		return( p->tn.rval + 0200*1 );
99132887Sdonn 	if( o==NAME ) return( 100 + 0200*1 );
99225828Ssam 	return( -1 );
99325828Ssam 	}
99425828Ssam 
99525828Ssam offset( p, tyl ) register NODE *p; int tyl; {
99625828Ssam 
99732886Sdonn 	if( tyl==1 &&
99832886Sdonn 	    p->in.op==REG &&
99932886Sdonn 	    (p->in.type==INT || p->in.type==UNSIGNED) )
100032886Sdonn 		return( p->tn.rval );
100132886Sdonn 	if( p->in.op==LS &&
100232886Sdonn 	    p->in.left->in.op==REG &&
100332886Sdonn 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
100432886Sdonn 	    p->in.right->in.op==ICON &&
100532886Sdonn 	    p->in.right->in.name[0]=='\0' &&
100632886Sdonn 	    (1<<p->in.right->tn.lval)==tyl)
100725828Ssam 		return( p->in.left->tn.rval );
100832886Sdonn 	if( tyl==2 &&
100932886Sdonn 	    p->in.op==PLUS &&
101032886Sdonn 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
101132886Sdonn 	    p->in.left->in.op==REG &&
101232886Sdonn 	    p->in.right->in.op==REG &&
101332886Sdonn 	    p->in.left->tn.rval==p->in.right->tn.rval )
101432886Sdonn 		return( p->in.left->tn.rval );
101525828Ssam 	return( -1 );
101625828Ssam 	}
101725828Ssam 
101825828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
101925828Ssam 	register NODE *t;
102025828Ssam 	NODE *f;
102125828Ssam 
102225828Ssam 	p->in.op = OREG;
102325828Ssam 	f = p->in.left; 	/* have to free this subtree later */
102425828Ssam 
102525828Ssam 	/* init base */
102625828Ssam 	switch (q->in.op) {
102725828Ssam 		case ICON:
102825828Ssam 		case REG:
102925828Ssam 		case OREG:
103032887Sdonn 		case NAME:
103125828Ssam 			t = q;
103225828Ssam 			break;
103325828Ssam 
103425828Ssam 		case MINUS:
103525828Ssam 			q->in.right->tn.lval = -q->in.right->tn.lval;
103625828Ssam 		case PLUS:
103725828Ssam 			t = q->in.right;
103825828Ssam 			break;
103925828Ssam 
104025828Ssam 		case UNARY MUL:
104125828Ssam 			t = q->in.left->in.left;
104225828Ssam 			break;
104325828Ssam 
104425828Ssam 		default:
104525828Ssam 			cerror("illegal makeor2");
104625828Ssam 	}
104725828Ssam 
104825828Ssam 	p->tn.lval = t->tn.lval;
104925828Ssam #ifndef FLEXNAMES
105032886Sdonn 	{
105132886Sdonn 		register int i;
105232886Sdonn 		for(i=0; i<NCHNAM; ++i)
105332886Sdonn 			p->in.name[i] = t->in.name[i];
105432886Sdonn 	}
105525828Ssam #else
105625828Ssam 	p->in.name = t->in.name;
105725828Ssam #endif
105825828Ssam 
105925828Ssam 	/* init offset */
106025828Ssam 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
106125828Ssam 
106225828Ssam 	tfree(f);
106325828Ssam 	return;
106425828Ssam 	}
106525828Ssam 
106625828Ssam canaddr( p ) NODE *p; {
106725828Ssam 	register int o = p->in.op;
106825828Ssam 
106925828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
107025828Ssam 	return(0);
107125828Ssam 	}
107225828Ssam 
107326076Ssam #ifndef shltype
107425828Ssam shltype( o, p ) register NODE *p; {
107525828Ssam 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
107625828Ssam 	}
107726076Ssam #endif
107825828Ssam 
107925828Ssam flshape( p ) NODE *p; {
108025828Ssam 	register int o = p->in.op;
108125828Ssam 
108225828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
108325828Ssam 	return(0);
108425828Ssam 	}
108525828Ssam 
108632886Sdonn /* INTEMP shapes must not contain any temporary registers */
108725828Ssam shtemp( p ) register NODE *p; {
108832886Sdonn 	int r;
108932886Sdonn 
109025828Ssam 	if( p->in.op == STARG ) p = p->in.left;
109132886Sdonn 
109232886Sdonn 	switch (p->in.op) {
109332886Sdonn 	case REG:
109432886Sdonn 		return( !istreg(p->tn.rval) );
109532886Sdonn 	case OREG:
109632886Sdonn 		r = p->tn.rval;
109732886Sdonn 		if( R2TEST(r) ) {
109832886Sdonn 			if( istreg(R2UPK1(r)) )
109932886Sdonn 				return(0);
110032886Sdonn 			r = R2UPK2(r);
110132886Sdonn 			}
110232886Sdonn 		return( !istreg(r) );
110332886Sdonn 	case UNARY MUL:
110432886Sdonn 		p = p->in.left;
110532886Sdonn 		return( p->in.op != UNARY MUL && shtemp(p) );
110632886Sdonn 		}
110732886Sdonn 
110832886Sdonn 	if( optype( p->in.op ) != LTYPE ) return(0);
110932886Sdonn 	return(1);
111025828Ssam 	}
111125828Ssam 
111225828Ssam shumul( p ) register NODE *p; {
111325828Ssam 	register int o;
111425828Ssam 	extern int xdebug;
111525828Ssam 
111625828Ssam 	if (xdebug) {
111725828Ssam 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
111825828Ssam 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
111925828Ssam 		}
112025828Ssam 
112125828Ssam 	o = p->in.op;
112225828Ssam 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
112325828Ssam 	 && p->in.type != PTR+DOUBLE)
112425828Ssam 		return( STARNM );
112525828Ssam 
112625828Ssam 	return( 0 );
112725828Ssam 	}
112825828Ssam 
112932887Sdonn special( p, shape ) register NODE *p; {
113032887Sdonn 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
113132887Sdonn 	else return(0);
113232887Sdonn }
113332887Sdonn 
113425828Ssam adrcon( val ) CONSZ val; {
113525947Ssam 	printf(ACONFMT, val);
113625828Ssam 	}
113725828Ssam 
113825828Ssam conput( p ) register NODE *p; {
113925828Ssam 	switch( p->in.op ){
114025828Ssam 
114125828Ssam 	case ICON:
114225828Ssam 		acon( p );
114325828Ssam 		return;
114425828Ssam 
114525828Ssam 	case REG:
114626162Ssam 		putstr(rname(p->tn.rval));
114725828Ssam 		return;
114825828Ssam 
114925828Ssam 	default:
115025828Ssam 		cerror( "illegal conput" );
115125828Ssam 		}
115225828Ssam 	}
115325828Ssam 
115432886Sdonn /*ARGSUSED*/
115525828Ssam insput( p ) NODE *p; {
115625828Ssam 	cerror( "insput" );
115725828Ssam 	}
115825828Ssam 
115932886Sdonn /*
116032886Sdonn  * Output the address of the second item in the
116132886Sdonn  * pair pointed to by p.
116232886Sdonn  */
116332886Sdonn upput(p, size)
116432886Sdonn 	register NODE *p;
116532886Sdonn {
116632886Sdonn 	CONSZ save;
116732886Sdonn 
116832886Sdonn 	if (p->in.op == FLD)
116932886Sdonn 		p = p->in.left;
117032886Sdonn 	switch (p->in.op) {
117132886Sdonn 
117232886Sdonn 	case NAME:
117332886Sdonn 	case OREG:
117432886Sdonn 		save = p->tn.lval;
117532886Sdonn 		p->tn.lval += size/SZCHAR;
117632886Sdonn 		adrput(p);
117732886Sdonn 		p->tn.lval = save;
117832886Sdonn 		break;
117932886Sdonn 
118032886Sdonn 	case REG:
118132886Sdonn 		if (size == SZLONG) {
118232886Sdonn 			putstr(rname(p->tn.rval+1));
118332886Sdonn 			break;
118432886Sdonn 		}
118532886Sdonn 		/* fall thru... */
118632886Sdonn 
118732886Sdonn 	default:
118832886Sdonn 		cerror("illegal upper address op %s size %d",
118932886Sdonn 		    opst[p->tn.op], size);
119032886Sdonn 		/*NOTREACHED*/
119132886Sdonn 	}
119232886Sdonn }
119332886Sdonn 
119425828Ssam adrput( p ) register NODE *p; {
119525828Ssam 	register int r;
119625828Ssam 	/* output an address, with offsets, from p */
119725828Ssam 
119825828Ssam 	if( p->in.op == FLD ){
119925828Ssam 		p = p->in.left;
120025828Ssam 		}
120125828Ssam 	switch( p->in.op ){
120225828Ssam 
120325828Ssam 	case NAME:
120425828Ssam 		acon( p );
120525828Ssam 		return;
120625828Ssam 
120725828Ssam 	case ICON:
120825828Ssam 		/* addressable value of the constant */
120926162Ssam 		putchar('$');
121025828Ssam 		acon( p );
121125828Ssam 		return;
121225828Ssam 
121325828Ssam 	case REG:
121426162Ssam 		putstr(rname(p->tn.rval));
121525828Ssam 		if(p->in.type == DOUBLE)	/* for entry mask */
121625828Ssam 			(void) rname(p->tn.rval+1);
121725828Ssam 		return;
121825828Ssam 
121925828Ssam 	case OREG:
122025828Ssam 		r = p->tn.rval;
122125828Ssam 		if( R2TEST(r) ){ /* double indexing */
122225828Ssam 			register int flags;
122325828Ssam 
122425828Ssam 			flags = R2UPK3(r);
122526162Ssam 			if( flags & 1 ) putchar('*');
122625828Ssam 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
122725828Ssam 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
122825828Ssam 			printf( "[%s]", rname(R2UPK2(r)) );
122925828Ssam 			return;
123025828Ssam 			}
123125828Ssam 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
123225828Ssam 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
123325828Ssam 			printf( CONFMT, p->tn.lval );
123426162Ssam 			putstr( "(fp)" );
123525828Ssam 			return;
123625828Ssam 			}
123725828Ssam 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
123825828Ssam 		printf( "(%s)", rname(p->tn.rval) );
123925828Ssam 		return;
124025828Ssam 
124125828Ssam 	case UNARY MUL:
124225828Ssam 		/* STARNM or STARREG found */
124325828Ssam 		if( tshape(p, STARNM) ) {
124426162Ssam 			putchar( '*' );
124525828Ssam 			adrput( p->in.left);
124625828Ssam 			}
124725828Ssam 		return;
124825828Ssam 
124925828Ssam 	default:
125025828Ssam 		cerror( "illegal address" );
125125828Ssam 		return;
125225828Ssam 
125325828Ssam 		}
125425828Ssam 
125525828Ssam 	}
125625828Ssam 
125725828Ssam acon( p ) register NODE *p; { /* print out a constant */
125825828Ssam 
125932886Sdonn 	if( p->in.name[0] == '\0' )
126025828Ssam 		printf( CONFMT, p->tn.lval);
126132886Sdonn 	else {
126225828Ssam #ifndef FLEXNAMES
126325828Ssam 		printf( "%.8s", p->in.name );
126425828Ssam #else
126532886Sdonn 		putstr( p->in.name );
126625828Ssam #endif
126732886Sdonn 		if( p->tn.lval != 0 ) {
126832886Sdonn 			putchar( '+' );
126932886Sdonn 			printf( CONFMT, p->tn.lval );
127032886Sdonn 			}
127125828Ssam 		}
127225828Ssam 	}
127325828Ssam 
127425828Ssam genscall( p, cookie ) register NODE *p; {
127525828Ssam 	/* structure valued call */
127625828Ssam 	return( gencall( p, cookie ) );
127725828Ssam 	}
127825828Ssam 
127925828Ssam genfcall( p, cookie ) register NODE *p; {
128025828Ssam 	register NODE *p1;
128125828Ssam 	register int m;
128225828Ssam 	static char *funcops[6] = {
128325828Ssam 		"sin", "cos", "sqrt", "exp", "log", "atan"
128425828Ssam 	};
128525828Ssam 
128625828Ssam 	/* generate function opcodes */
128725828Ssam 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
128825828Ssam 	 (p1 = p->in.left)->in.op==ICON &&
128925828Ssam 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
129025828Ssam #ifdef FLEXNAMES
129125828Ssam 		p1->in.name++;
129225828Ssam #else
129325828Ssam 		strcpy(p1->in.name, p1->in.name[1]);
129425828Ssam #endif
129525828Ssam 		for(m=0; m<6; m++)
129625828Ssam 			if(!strcmp(p1->in.name, funcops[m]))
129725828Ssam 				break;
129825828Ssam 		if(m >= 6)
129925828Ssam 			uerror("no opcode for fortarn function %s", p1->in.name);
130025828Ssam 	} else
130125828Ssam 		uerror("illegal type of fortarn function");
130225828Ssam 	p1 = p->in.right;
130325828Ssam 	p->in.op = FORTCALL;
130425828Ssam 	if(!canaddr(p1))
130525828Ssam 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
130625828Ssam 	m = match( p, INTAREG|INTBREG );
130725828Ssam 	return(m != MDONE);
130825828Ssam }
130925828Ssam 
131025828Ssam /* tbl */
131125828Ssam int gc_numbytes;
131225828Ssam /* tbl */
131325828Ssam 
131432886Sdonn /*ARGSUSED*/
131525828Ssam gencall( p, cookie ) register NODE *p; {
131625828Ssam 	/* generate the call given by p */
131725828Ssam 	register NODE *p1, *ptemp;
131825828Ssam 	register int temp, temp1;
131925828Ssam 	register int m;
132025828Ssam 
132125828Ssam 	if( p->in.right ) temp = argsize( p->in.right );
132225828Ssam 	else temp = 0;
132325828Ssam 
132425828Ssam 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
132525828Ssam 		/* set aside room for structure return */
132625828Ssam 
132725828Ssam 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
132825828Ssam 		else temp1 = temp;
132925828Ssam 		}
133025828Ssam 
133125828Ssam 	if( temp > maxargs ) maxargs = temp;
133225828Ssam 	SETOFF(temp1,4);
133325828Ssam 
133425828Ssam 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
133525828Ssam 		ptemp = talloc();
133625828Ssam 		ptemp->in.op = OREG;
133725828Ssam 		ptemp->tn.lval = -1;
133825828Ssam 		ptemp->tn.rval = SP;
133925828Ssam #ifndef FLEXNAMES
134025828Ssam 		ptemp->in.name[0] = '\0';
134125828Ssam #else
134225828Ssam 		ptemp->in.name = "";
134325828Ssam #endif
134425828Ssam 		ptemp->in.rall = NOPREF;
134525828Ssam 		ptemp->in.su = 0;
134625828Ssam 		genargs( p->in.right, ptemp );
134725828Ssam 		ptemp->in.op = FREE;
134825828Ssam 		}
134925828Ssam 
135025828Ssam 	p1 = p->in.left;
135125828Ssam 	if( p1->in.op != ICON ){
135225828Ssam 		if( p1->in.op != REG ){
135325828Ssam 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
135425828Ssam 				if( p1->in.op != NAME ){
135525828Ssam 					order( p1, INAREG );
135625828Ssam 					}
135725828Ssam 				}
135825828Ssam 			}
135925828Ssam 		}
136025828Ssam 
136125828Ssam /* tbl
136225828Ssam 	setup gc_numbytes so reference to ZC works */
136325828Ssam 
136425828Ssam 	gc_numbytes = temp&(0x3ff);
136525828Ssam 
136625828Ssam 	p->in.op = UNARY CALL;
136725828Ssam 	m = match( p, INTAREG|INTBREG );
136825828Ssam 
136925828Ssam 	return(m != MDONE);
137025828Ssam 	}
137125828Ssam 
137225828Ssam /* tbl */
137325828Ssam char *
137425828Ssam ccbranches[] = {
137525828Ssam 	"eql",
137625828Ssam 	"neq",
137725828Ssam 	"leq",
137825828Ssam 	"lss",
137925828Ssam 	"geq",
138025828Ssam 	"gtr",
138125828Ssam 	"lequ",
138225828Ssam 	"lssu",
138325828Ssam 	"gequ",
138425828Ssam 	"gtru",
138525828Ssam 	};
138625828Ssam /* tbl */
138725828Ssam 
138832886Sdonn /*ARGSUSED*/
138925828Ssam cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
139025828Ssam 
139132886Sdonn 	if( o != 0 && ( o < EQ || o > UGT ) )
139232886Sdonn 		cerror( "bad conditional branch: %s", opst[o] );
139332886Sdonn 	printf( "	j%s	L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
139425828Ssam 	}
139525828Ssam 
139625828Ssam nextcook( p, cookie ) NODE *p; {
139725828Ssam 	/* we have failed to match p with cookie; try another */
139825828Ssam 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
139925828Ssam 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
140025828Ssam 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
140125828Ssam 	return( FORREW );
140225828Ssam 	}
140325828Ssam 
140432886Sdonn /*ARGSUSED*/
140525828Ssam lastchance( p, cook ) NODE *p; {
140625828Ssam 	/* forget it! */
140725828Ssam 	return(0);
140825828Ssam 	}
140925828Ssam 
141025828Ssam optim2( p ) register NODE *p; {
141125828Ssam 	/* do local tree transformations and optimizations */
141232886Sdonn 
141332886Sdonn 	int o;
141432886Sdonn 	int i, mask;
141530360Ssam 	register NODE *l, *r;
141625828Ssam 
141732886Sdonn 	switch( o = p->in.op ) {
141830360Ssam 
141932887Sdonn 	case ASG PLUS:
142032887Sdonn 	case ASG MINUS:
142132887Sdonn 	case ASG MUL:
142232887Sdonn 	case ASG OR:
142332887Sdonn 		/* simple ASG OPSIMP -- reduce range of constant rhs */
142432887Sdonn 		l = p->in.left;
142532887Sdonn 		r = p->in.right;
142632887Sdonn 		if( tlen(l) < SZINT/SZCHAR &&
142732887Sdonn 		    r->in.op==ICON && r->in.name[0]==0 ){
142832887Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
142932887Sdonn 			if( r->tn.lval & (mask & ~(mask >> 1)) )
143032887Sdonn 				r->tn.lval |= ~mask;
143132887Sdonn 			else
143232887Sdonn 				r->tn.lval &= mask;
143332887Sdonn 			}
143432887Sdonn 		break;
143532887Sdonn 
143632886Sdonn 	case AND:
143732886Sdonn 	case ASG AND:
143832886Sdonn 		r = p->in.right;
143932886Sdonn 		if( r->in.op==ICON && r->in.name[0]==0 ) {
144032886Sdonn 			/* check for degenerate operations */
144132886Sdonn 			l = p->in.left;
144232886Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
144332887Sdonn 			if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
144432887Sdonn 				i = r->tn.lval & mask;
144532886Sdonn 				if( i == mask ) {
144632887Sdonn 					/* redundant mask */
144732886Sdonn 					r->in.op = FREE;
144832886Sdonn 					ncopy(p, l);
144932886Sdonn 					l->in.op = FREE;
145032886Sdonn 					break;
145132886Sdonn 					}
145232886Sdonn 				else if( i == 0 )
145332887Sdonn 					/* all bits masked off */
145432886Sdonn 					goto zero;
145532887Sdonn 				r->tn.lval = i;
145632887Sdonn 				if( tlen(l) < SZINT/SZCHAR ){
145732887Sdonn 					/* sign extend */
145832887Sdonn 					if( r->tn.lval & (mask & ~(mask >> 1)) )
145932887Sdonn 						r->tn.lval |= ~mask;
146032887Sdonn 					else
146132887Sdonn 						r->tn.lval &= mask;
146232887Sdonn 					}
146332886Sdonn 				}
146432886Sdonn 			else if( r->tn.lval == mask &&
146532886Sdonn 				 tlen(l) < SZINT/SZCHAR ) {
146632887Sdonn 				/* use movz instead of and */
146732886Sdonn 				r->in.op = SCONV;
146832886Sdonn 				r->in.left = l;
146932886Sdonn 				r->in.right = 0;
147032886Sdonn 				r->in.type = ENUNSIGN(l->in.type);
147132886Sdonn 				r->in.su = l->in.su > 1 ? l->in.su : 1;
147232886Sdonn 				ncopy(p, r);
147332886Sdonn 				p->in.left = r;
147432886Sdonn 				p->in.type = INT;
147532886Sdonn 				}
147630360Ssam 			}
147732886Sdonn 		break;
147830360Ssam 
147930360Ssam 	case SCONV:
148030360Ssam 		l = p->in.left;
148132886Sdonn 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
148232886Sdonn 		    l->in.type == FLOAT || l->in.type == DOUBLE )
148332886Sdonn 			return;
148432887Sdonn 		if( l->in.op == PCONV )
148532886Sdonn 			return;
148632887Sdonn 		if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
148732887Sdonn 		    l->in.type != INT && l->in.type != UNSIGNED )
148832887Sdonn 			return;
148932879Sdonn 
149032886Sdonn 		/* Only trust it to get it right if the size is the same */
149132886Sdonn 		if( tlen(p) != tlen(l) )
149232886Sdonn 			return;
149330360Ssam 
149432886Sdonn 		/* clobber conversion */
149532886Sdonn 		if( l->in.op != FLD )
149632886Sdonn 			l->in.type = p->in.type;
149732886Sdonn 		ncopy( p, l );
149832886Sdonn 		l->in.op = FREE;
149932886Sdonn 
150032886Sdonn 		break;
150132886Sdonn 
150230360Ssam 	case ASSIGN:
150330360Ssam 		/*
150432886Sdonn 		 * Conversions are equivalent to assignments;
150532886Sdonn 		 * when the two operations are combined,
150632886Sdonn 		 * we can sometimes zap the conversion.
150730360Ssam 		 */
150830360Ssam 		r = p->in.right;
150932886Sdonn 		l = p->in.left;
151032886Sdonn 		if ( r->in.op == SCONV &&
151132886Sdonn 		     !mixtypes(l, r) &&
151232886Sdonn 		     l->in.op != FLD &&
151332886Sdonn 		     tlen(l) == tlen(r) ) {
151430360Ssam 				p->in.right = r->in.left;
151530360Ssam 				r->in.op = FREE;
151630360Ssam 			}
151732886Sdonn 		break;
151832885Sdonn 
151932885Sdonn 	case ULE:
152032885Sdonn 	case ULT:
152132885Sdonn 	case UGE:
152232885Sdonn 	case UGT:
152332886Sdonn 		p->in.op -= (UGE-GE);
152432886Sdonn 		if( degenerate(p) )
152532886Sdonn 			break;
152632886Sdonn 		p->in.op += (UGE-GE);
152732886Sdonn 		break;
152832886Sdonn 
152932885Sdonn 	case EQ:
153032885Sdonn 	case NE:
153132885Sdonn 	case LE:
153232885Sdonn 	case LT:
153332885Sdonn 	case GE:
153432885Sdonn 	case GT:
153532887Sdonn 		if( p->in.left->in.op == SCONV &&
153632887Sdonn 		    p->in.right->in.op == SCONV ) {
153732887Sdonn 			l = p->in.left;
153832887Sdonn 			r = p->in.right;
153932887Sdonn 			if( l->in.type == DOUBLE &&
154032887Sdonn 			    l->in.left->in.type == FLOAT &&
154132887Sdonn 			    r->in.left->in.type == FLOAT ) {
154232887Sdonn 				/* nuke the conversions */
154332887Sdonn 				p->in.left = l->in.left;
154432887Sdonn 				p->in.right = r->in.left;
154532887Sdonn 				l->in.op = FREE;
154632887Sdonn 				r->in.op = FREE;
154732887Sdonn 				}
154832887Sdonn 			/* more? */
154932887Sdonn 			}
155032886Sdonn 		(void) degenerate(p);
155132886Sdonn 		break;
155232886Sdonn 
155332886Sdonn 	case DIV:
155432886Sdonn 		if( p->in.right->in.op == ICON &&
155532886Sdonn 		    p->in.right->tn.name[0] == '\0' &&
155632886Sdonn 		    ISUNSIGNED(p->in.right->in.type) &&
155732886Sdonn 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
155832886Sdonn 			/* easy to do here, harder to do in zzzcode() */
155932886Sdonn 			p->in.op = UGE;
156032886Sdonn 			break;
156132886Sdonn 			}
156232886Sdonn 	case MOD:
156332886Sdonn 	case ASG DIV:
156432886Sdonn 	case ASG MOD:
156532885Sdonn 		/*
156632886Sdonn 		 * optimize DIV and MOD
156732886Sdonn 		 *
156832886Sdonn 		 * basically we spot UCHAR and USHORT and try to do them
156932886Sdonn 		 * as signed ints...  this may need tuning for the tahoe.
157032885Sdonn 		 */
157132886Sdonn 		if( degenerate(p) )
157232886Sdonn 			break;
157332886Sdonn 		l = p->in.left;
157432885Sdonn 		r = p->in.right;
157532886Sdonn 		if( !ISUNSIGNED(r->in.type) ||
157632886Sdonn 		    tlen(l) >= SZINT/SZCHAR ||
157732886Sdonn 		    !(tlen(r) < SZINT/SZCHAR ||
157832886Sdonn 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
157932886Sdonn 			break;
158032886Sdonn 		if( r->in.op == ICON )
158132886Sdonn 			r->tn.type = INT;
158232886Sdonn 		else {
158332886Sdonn 			NODE *t = talloc();
158432886Sdonn 			t->in.left = r;
158532886Sdonn 			r = t;
158632886Sdonn 			r->in.op = SCONV;
158732886Sdonn 			r->in.type = INT;
158832886Sdonn 			r->in.right = 0;
158932886Sdonn 			p->in.right = r;
159032886Sdonn 			}
159132886Sdonn 		if( o == DIV || o == MOD ) {
159232886Sdonn 			NODE *t = talloc();
159332886Sdonn 			t->in.left = l;
159432886Sdonn 			l = t;
159532886Sdonn 			l->in.op = SCONV;
159632886Sdonn 			l->in.type = INT;
159732886Sdonn 			l->in.right = 0;
159832886Sdonn 			p->in.left = l;
159932886Sdonn 			}
160032886Sdonn 		/* handle asgops in table */
160132886Sdonn 		break;
160232886Sdonn 
160332886Sdonn 	case RS:
160432886Sdonn 	case ASG RS:
160532886Sdonn 	case LS:
160632886Sdonn 	case ASG LS:
160732886Sdonn 		/* pick up degenerate shifts */
160832885Sdonn 		l = p->in.left;
160932886Sdonn 		r = p->in.right;
161032886Sdonn 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
161132885Sdonn 			break;
161232885Sdonn 		i = r->tn.lval;
161332886Sdonn 		if( i < 0 )
161432886Sdonn 			/* front end 'fixes' this? */
161532886Sdonn 			if( o == LS || o == ASG LS )
161632886Sdonn 				o += (RS-LS);
161732886Sdonn 			else
161832886Sdonn 				o += (LS-RS);
161932886Sdonn 		if( (o == RS || o == ASG RS) &&
162032886Sdonn 		    !ISUNSIGNED(l->in.type) )
162132886Sdonn 			/* can't optimize signed right shifts */
162232885Sdonn 			break;
162332886Sdonn 		if( o == LS ) {
162432886Sdonn 			if( i < SZINT )
162532886Sdonn 				break;
162632886Sdonn 			}
162732886Sdonn 		else {
162832886Sdonn 			if( i < tlen(l) * SZCHAR )
162932886Sdonn 				break;
163032886Sdonn 			}
163132886Sdonn 	zero:
163232886Sdonn 		if( !asgop( o ) )
163332886Sdonn 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
163432886Sdonn 				/* no side effects */
163532886Sdonn 				tfree(l);
163632886Sdonn 				ncopy(p, r);
163732886Sdonn 				r->in.op = FREE;
163832886Sdonn 				p->tn.lval = 0;
163932886Sdonn 				}
164032886Sdonn 			else {
164132886Sdonn 				p->in.op = COMOP;
164232886Sdonn 				r->tn.lval = 0;
164332886Sdonn 				}
164432886Sdonn 		else {
164532886Sdonn 			p->in.op = ASSIGN;
164632886Sdonn 			r->tn.lval = 0;
164732886Sdonn 			}
164832886Sdonn 		break;
164932885Sdonn 		}
165032886Sdonn 	}
165132885Sdonn 
165232886Sdonn degenerate(p) register NODE *p; {
165332886Sdonn 	int o;
165432886Sdonn 	int result, i;
165532886Sdonn 	int lower, upper;
165632886Sdonn 	register NODE *l, *r;
165732886Sdonn 
165832886Sdonn 	/*
165932886Sdonn 	 * try to keep degenerate comparisons with constants
166032886Sdonn 	 * out of the table.
166132886Sdonn 	 */
166232886Sdonn 	r = p->in.right;
166332886Sdonn 	l = p->in.left;
166432886Sdonn 	if( r->in.op != ICON ||
166532886Sdonn 	    r->tn.name[0] != '\0' ||
166632886Sdonn 	    tlen(l) >= tlen(r) )
166732886Sdonn 		return (0);
166832886Sdonn 	switch( l->in.type ) {
166932886Sdonn 	case CHAR:
167032886Sdonn 		lower = -(1 << SZCHAR - 1);
167132886Sdonn 		upper = (1 << SZCHAR - 1) - 1;
167232886Sdonn 		break;
167332886Sdonn 	case UCHAR:
167432886Sdonn 		lower = 0;
167532886Sdonn 		upper = (1 << SZCHAR) - 1;
167632886Sdonn 		break;
167732886Sdonn 	case SHORT:
167832886Sdonn 		lower = -(1 << SZSHORT - 1);
167932886Sdonn 		upper = (1 << SZSHORT - 1) - 1;
168032886Sdonn 		break;
168132886Sdonn 	case USHORT:
168232886Sdonn 		lower = 0;
168332886Sdonn 		upper = (1 << SZSHORT) - 1;
168432886Sdonn 		break;
168532886Sdonn 	default:
168632886Sdonn 		cerror("unsupported type in degenerate()");
168732886Sdonn 		}
168832886Sdonn 	i = r->tn.lval;
168932886Sdonn 	switch( o = p->in.op ) {
169032886Sdonn 	case DIV:
169132886Sdonn 	case ASG DIV:
169232886Sdonn 	case MOD:
169332886Sdonn 	case ASG MOD:
169432886Sdonn 		/* DIV and MOD work like EQ */
169532886Sdonn 	case EQ:
169632886Sdonn 	case NE:
169732886Sdonn 		if( lower == 0 && (unsigned) i > upper )
169832886Sdonn 			result = o == NE;
169932886Sdonn 		else if( i < lower || i > upper )
170032886Sdonn 			result = o == NE;
170132886Sdonn 		else
170232886Sdonn 			return (0);
170332886Sdonn 		break;
170432886Sdonn 	case LT:
170532886Sdonn 	case GE:
170632886Sdonn 		if( lower == 0 && (unsigned) i > upper )
170732886Sdonn 			result = o == LT;
170832886Sdonn 		else if( i <= lower )
170932886Sdonn 			result = o != LT;
171032886Sdonn 		else if( i > upper )
171132886Sdonn 			result = o == LT;
171232886Sdonn 		else
171332886Sdonn 			return (0);
171432886Sdonn 		break;
171532886Sdonn 	case LE:
171632886Sdonn 	case GT:
171732886Sdonn 		if( lower == 0 && (unsigned) i >= upper )
171832886Sdonn 			result = o == LE;
171932886Sdonn 		else if( i < lower )
172032886Sdonn 			result = o != LE;
172132886Sdonn 		else if( i >= upper )
172232886Sdonn 			result = o == LE;
172332886Sdonn 		else
172432886Sdonn 			return (0);
172532886Sdonn 		break;
172632886Sdonn 	default:
172732886Sdonn 		cerror("unknown op in degenerate()");
172832886Sdonn 		}
172932886Sdonn 
173032886Sdonn 	if( o == MOD || o == ASG MOD ) {
173132886Sdonn 		r->in.op = FREE;
173232886Sdonn 		ncopy(p, l);
173332886Sdonn 		l->in.op = FREE;
173432886Sdonn 		}
173532886Sdonn 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
173632886Sdonn 		/* no side effects */
173732886Sdonn 		tfree(l);
173832886Sdonn 		ncopy(p, r);
173932886Sdonn 		r->in.op = FREE;
174032886Sdonn 		p->tn.lval = result;
174132886Sdonn 		}
174232886Sdonn 	else {
174332886Sdonn 		if( o == ASG DIV )
174432886Sdonn 			p->in.op = ASSIGN;
174532886Sdonn 		else {
174632885Sdonn 			p->in.op = COMOP;
174732885Sdonn 			r->tn.type = INT;
174832886Sdonn 			}
174932886Sdonn 		r->tn.lval = result;
175032885Sdonn 		}
175132886Sdonn 	if( logop(o) )
175232886Sdonn 		p->in.type = INT;
175332886Sdonn 
175432886Sdonn 	return (1);
175525828Ssam 	}
175625828Ssam 
175725828Ssam struct functbl {
175825828Ssam 	int fop;
175932877Sdonn 	TWORD ftype;
176025828Ssam 	char *func;
176132877Sdonn 	} opfunc[] = {
176232877Sdonn 	DIV,		TANY,	"udiv",
176332877Sdonn 	MOD,		TANY,	"urem",
176432877Sdonn 	ASG DIV,	TANY,	"audiv",
176532877Sdonn 	ASG MOD,	TANY,	"aurem",
176632877Sdonn 	0,	0,	0 };
176725828Ssam 
176825828Ssam hardops(p)  register NODE *p; {
176925828Ssam 	/* change hard to do operators into function calls.  */
177025828Ssam 	register NODE *q;
177125828Ssam 	register struct functbl *f;
177232877Sdonn 	register o;
177332877Sdonn 	NODE *old,*temp;
177425828Ssam 
177525828Ssam 	o = p->in.op;
177632877Sdonn 	if( ! (optype(o)==BITYPE &&
177732877Sdonn 	       (ISUNSIGNED(p->in.left->in.type) ||
177832877Sdonn 		ISUNSIGNED(p->in.right->in.type))) )
177932877Sdonn 		return;
178025828Ssam 
178125828Ssam 	for( f=opfunc; f->fop; f++ ) {
178225828Ssam 		if( o==f->fop ) goto convert;
178332877Sdonn 		}
178425828Ssam 	return;
178525828Ssam 
178625828Ssam 	convert:
178732886Sdonn 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
178832886Sdonn 		/* 'J' in zzzcode() -- assumes DIV or MOD operations */
178932886Sdonn 		/* save a subroutine call -- use at most 5 instructions */
179032886Sdonn 		return;
179132886Sdonn 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
179232886Sdonn 		/* optim2() will modify the op into an ordinary int op */
179332886Sdonn 		return;
179425828Ssam 	if( asgop( o ) ) {
179532877Sdonn 		old = NIL;
179632877Sdonn 		switch( p->in.left->in.op ){
179732877Sdonn 		case FLD:
179832877Sdonn 			q = p->in.left->in.left;
179932877Sdonn 			/*
180032877Sdonn 			 * rewrite (lval.fld /= rval); as
180132877Sdonn 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
180232877Sdonn 			 * else the compiler will evaluate lval twice.
180332877Sdonn 			 */
180432877Sdonn 			if( q->in.op == UNARY MUL ){
180532877Sdonn 				/* first allocate a temp storage */
180632877Sdonn 				temp = talloc();
180732877Sdonn 				temp->in.op = OREG;
180832877Sdonn 				temp->tn.rval = TMPREG;
180932877Sdonn 				temp->tn.lval = BITOOR(freetemp(1));
181032877Sdonn 				temp->in.type = INCREF(p->in.type);
181132877Sdonn #ifdef FLEXNAMES
181232877Sdonn 				temp->in.name = "";
181332877Sdonn #else
181432877Sdonn 				temp->in.name[0] = '\0';
181532877Sdonn #endif
181632877Sdonn 				old = q->in.left;
181732877Sdonn 				q->in.left = temp;
181832877Sdonn 			}
181932877Sdonn 			/* fall thru ... */
182025828Ssam 
182132877Sdonn 		case REG:
182232877Sdonn 		case NAME:
182332877Sdonn 		case OREG:
182432877Sdonn 			/* change ASG OP to a simple OP */
182532877Sdonn 			q = talloc();
182632877Sdonn 			q->in.op = NOASG p->in.op;
182732877Sdonn 			q->in.rall = NOPREF;
182832877Sdonn 			q->in.type = p->in.type;
182932877Sdonn 			q->in.left = tcopy(p->in.left);
183032877Sdonn 			q->in.right = p->in.right;
183132877Sdonn 			p->in.op = ASSIGN;
183232877Sdonn 			p->in.right = q;
183332877Sdonn 			p = q;
183432877Sdonn 			f -= 2; /* Note: this depends on the table order */
183532877Sdonn 			/* on the right side only - replace *temp with
183632877Sdonn 			 *(temp = &lval), build the assignment node */
183732877Sdonn 			if( old ){
183832877Sdonn 				temp = q->in.left->in.left; /* the "*" node */
183932877Sdonn 				q = talloc();
184032877Sdonn 				q->in.op = ASSIGN;
184132877Sdonn 				q->in.left = temp->in.left;
184232877Sdonn 				q->in.right = old;
184332877Sdonn 				q->in.type = old->in.type;
184432877Sdonn #ifdef FLEXNAMES
184532877Sdonn 				q->in.name = "";
184625828Ssam #else
184732877Sdonn 				q->in.name[0] = '\0';
184825828Ssam #endif
184932877Sdonn 				temp->in.left = q;
185032877Sdonn 			}
185132877Sdonn 			break;
185225828Ssam 
185332877Sdonn 		case UNARY MUL:
185432877Sdonn 			/* avoid doing side effects twice */
185532877Sdonn 			q = p->in.left;
185632877Sdonn 			p->in.left = q->in.left;
185732877Sdonn 			q->in.op = FREE;
185832877Sdonn 			break;
185932877Sdonn 
186032877Sdonn 		default:
186132877Sdonn 			cerror( "hardops: can't compute & LHS" );
186232877Sdonn 			}
186332877Sdonn 		}
186432877Sdonn 
186525828Ssam 	/* build comma op for args to function */
186632877Sdonn 	q = talloc();
186732877Sdonn 	q->in.op = CM;
186832877Sdonn 	q->in.rall = NOPREF;
186932877Sdonn 	q->in.type = INT;
187032877Sdonn 	q->in.left = p->in.left;
187132877Sdonn 	q->in.right = p->in.right;
187225828Ssam 	p->in.op = CALL;
187325828Ssam 	p->in.right = q;
187425828Ssam 
187525828Ssam 	/* put function name in left node of call */
187625828Ssam 	p->in.left = q = talloc();
187725828Ssam 	q->in.op = ICON;
187825828Ssam 	q->in.rall = NOPREF;
187925828Ssam 	q->in.type = INCREF( FTN + p->in.type );
188025828Ssam #ifndef FLEXNAMES
188132877Sdonn 	strcpy( q->in.name, f->func );
188225828Ssam #else
188332877Sdonn 	q->in.name = f->func;
188425828Ssam #endif
188525828Ssam 	q->tn.lval = 0;
188625828Ssam 	q->tn.rval = 0;
188725828Ssam 
188825828Ssam 	}
188925828Ssam 
189025828Ssam zappost(p) NODE *p; {
189125828Ssam 	/* look for ++ and -- operators and remove them */
189225828Ssam 
189325828Ssam 	register int o, ty;
189425828Ssam 	register NODE *q;
189525828Ssam 	o = p->in.op;
189625828Ssam 	ty = optype( o );
189725828Ssam 
189825828Ssam 	switch( o ){
189925828Ssam 
190025828Ssam 	case INCR:
190125828Ssam 	case DECR:
190225828Ssam 			q = p->in.left;
190325828Ssam 			p->in.right->in.op = FREE;  /* zap constant */
190425828Ssam 			ncopy( p, q );
190525828Ssam 			q->in.op = FREE;
190625828Ssam 			return;
190725828Ssam 
190825828Ssam 		}
190925828Ssam 
191025828Ssam 	if( ty == BITYPE ) zappost( p->in.right );
191125828Ssam 	if( ty != LTYPE ) zappost( p->in.left );
191225828Ssam }
191325828Ssam 
191425828Ssam fixpre(p) NODE *p; {
191525828Ssam 
191625828Ssam 	register int o, ty;
191725828Ssam 	o = p->in.op;
191825828Ssam 	ty = optype( o );
191925828Ssam 
192025828Ssam 	switch( o ){
192125828Ssam 
192225828Ssam 	case ASG PLUS:
192325828Ssam 			p->in.op = PLUS;
192425828Ssam 			break;
192525828Ssam 	case ASG MINUS:
192625828Ssam 			p->in.op = MINUS;
192725828Ssam 			break;
192825828Ssam 		}
192925828Ssam 
193025828Ssam 	if( ty == BITYPE ) fixpre( p->in.right );
193125828Ssam 	if( ty != LTYPE ) fixpre( p->in.left );
193225828Ssam }
193325828Ssam 
193432886Sdonn /*ARGSUSED*/
193525828Ssam NODE * addroreg(l) NODE *l;
193625828Ssam 				/* OREG was built in clocal()
193725828Ssam 				 * for an auto or formal parameter
193825828Ssam 				 * now its address is being taken
193925828Ssam 				 * local code must unwind it
194025828Ssam 				 * back to PLUS/MINUS REG ICON
194125828Ssam 				 * according to local conventions
194225828Ssam 				 */
194325828Ssam {
194425828Ssam 	cerror("address of OREG taken");
194532886Sdonn 	/*NOTREACHED*/
194625828Ssam }
194725828Ssam 
194825828Ssam # ifndef ONEPASS
194925828Ssam main( argc, argv ) char *argv[]; {
195025828Ssam 	return( mainp2( argc, argv ) );
195125828Ssam 	}
195225828Ssam # endif
195325828Ssam 
195430360Ssam strip(p) register NODE *p; {
195530360Ssam 	NODE *q;
195630360Ssam 
195730360Ssam 	/* strip nodes off the top when no side effects occur */
195830360Ssam 	for( ; ; ) {
195930360Ssam 		switch( p->in.op ) {
196030360Ssam 		case SCONV:			/* remove lint tidbits */
196130360Ssam 			q = p->in.left;
196230360Ssam 			ncopy( p, q );
196330360Ssam 			q->in.op = FREE;
196430360Ssam 			break;
196530360Ssam 		/* could probably add a few more here */
196630360Ssam 		default:
196730360Ssam 			return;
196830360Ssam 			}
196930360Ssam 		}
197030360Ssam 	}
197130360Ssam 
197225828Ssam myreader(p) register NODE *p; {
197330360Ssam 	strip( p );		/* strip off operations with no side effects */
197432886Sdonn 	canon( p );		/* expands r-vals for fields */
197525828Ssam 	walkf( p, hardops );	/* convert ops to function calls */
197625828Ssam 	walkf( p, optim2 );
197725828Ssam 	}
1978