xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32944)
117742Sralph # ifndef lint
2*32944Sdonn static char *sccsid ="@(#)local2.c	1.38 (Berkeley) 12/11/87";
317742Sralph # endif
417742Sralph 
518556Sralph # include "pass2.h"
632935Sdonn # include <ctype.h>
732935Sdonn 
832935Sdonn # define putstr(s)	fputs((s), stdout)
932935Sdonn 
109702Slinton # ifdef FORT
119702Slinton int ftlab1, ftlab2;
129702Slinton # endif
139702Slinton /* a lot of the machine dependent parts of the second pass */
149702Slinton 
159702Slinton # define BITMASK(n) ((1L<<n)-1)
169702Slinton 
1732924Sdonn /*ARGSUSED*/
189702Slinton where(c){
199702Slinton 	fprintf( stderr, "%s, line %d: ", filename, lineno );
209702Slinton 	}
219702Slinton 
229702Slinton lineid( l, fn ) char *fn; {
239702Slinton 	/* identify line l and file fn */
249702Slinton 	printf( "#	line %d, file %s\n", l, fn );
259702Slinton 	}
269702Slinton 
279702Slinton 
289702Slinton eobl2(){
2932935Sdonn 	register OFFSZ spoff;	/* offset from stack pointer */
3032935Sdonn #ifndef FORT
3132935Sdonn 	extern int ftlab1, ftlab2;
3232935Sdonn #endif
3332935Sdonn 
349702Slinton 	spoff = maxoff;
359702Slinton 	if( spoff >= AUTOINIT ) spoff -= AUTOINIT;
369702Slinton 	spoff /= SZCHAR;
379702Slinton 	SETOFF(spoff,4);
3832935Sdonn #ifdef FORT
399702Slinton #ifndef FLEXNAMES
409702Slinton 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
419702Slinton #else
429702Slinton 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
439702Slinton 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
449702Slinton #endif
459702Slinton #else
469702Slinton 	printf( "L%d:\n", ftlab1);
479702Slinton 	if( spoff!=0 )
489702Slinton 		if( spoff < 64 )
499702Slinton 			printf( "	subl2	$%ld,sp\n", spoff);
509702Slinton 		else
519702Slinton 			printf( "	movab	-%ld(sp),sp\n", spoff);
529702Slinton 	printf( "	jbr 	L%d\n", ftlab2);
539702Slinton #endif
549702Slinton 	maxargs = -1;
559702Slinton 	}
569702Slinton 
579702Slinton struct hoptab { int opmask; char * opstring; } ioptab[] = {
589702Slinton 
599702Slinton 	PLUS,	"add",
609702Slinton 	MINUS,	"sub",
619702Slinton 	MUL,	"mul",
629702Slinton 	DIV,	"div",
639702Slinton 	OR,	"bis",
649702Slinton 	ER,	"xor",
659702Slinton 	AND,	"bic",
669702Slinton 	-1, ""    };
679702Slinton 
689702Slinton hopcode( f, o ){
699702Slinton 	/* output the appropriate string from the above table */
709702Slinton 
719702Slinton 	register struct hoptab *q;
729702Slinton 
7332935Sdonn 	if(asgop(o))
7432935Sdonn 		o = NOASG o;
759702Slinton 	for( q = ioptab;  q->opmask>=0; ++q ){
769702Slinton 		if( q->opmask == o ){
7732935Sdonn 			printf( "%s%c", q->opstring, tolower(f));
789702Slinton 			return;
799702Slinton 			}
809702Slinton 		}
819702Slinton 	cerror( "no hoptab for %s", opst[o] );
829702Slinton 	}
839702Slinton 
849702Slinton char *
859702Slinton rnames[] = {  /* keyed to register number tokens */
869702Slinton 
879702Slinton 	"r0", "r1",
889702Slinton 	"r2", "r3", "r4", "r5",
899702Slinton 	"r6", "r7", "r8", "r9", "r10", "r11",
909702Slinton 	"ap", "fp", "sp", "pc",
919702Slinton 	};
929702Slinton 
939702Slinton int rstatus[] = {
949702Slinton 	SAREG|STAREG, SAREG|STAREG,
959702Slinton 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
969702Slinton 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
979702Slinton 	SAREG, SAREG, SAREG, SAREG,
989702Slinton 	};
999702Slinton 
1009702Slinton tlen(p) NODE *p;
1019702Slinton {
1029702Slinton 	switch(p->in.type) {
1039702Slinton 		case CHAR:
1049702Slinton 		case UCHAR:
1059702Slinton 			return(1);
1069702Slinton 
1079702Slinton 		case SHORT:
1089702Slinton 		case USHORT:
10932937Sdonn 			return(SZSHORT/SZCHAR);
1109702Slinton 
1119702Slinton 		case DOUBLE:
11232937Sdonn 			return(SZDOUBLE/SZCHAR);
1139702Slinton 
1149702Slinton 		default:
11532937Sdonn 			return(SZINT/SZCHAR);
1169702Slinton 		}
1179702Slinton }
1189702Slinton 
1199702Slinton mixtypes(p, q) NODE *p, *q;
1209702Slinton {
12116181Sralph 	register TWORD tp, tq;
1229702Slinton 
1239702Slinton 	tp = p->in.type;
1249702Slinton 	tq = q->in.type;
1259702Slinton 
1269702Slinton 	return( (tp==FLOAT || tp==DOUBLE) !=
1279702Slinton 		(tq==FLOAT || tq==DOUBLE) );
1289702Slinton }
1299702Slinton 
1309702Slinton prtype(n) NODE *n;
1319702Slinton {
1329702Slinton 	switch (n->in.type)
1339702Slinton 		{
13432935Sdonn 
1359702Slinton 		case DOUBLE:
13624418Smckusick 			putchar('d');
1379702Slinton 			return;
1389702Slinton 
1399702Slinton 		case FLOAT:
14024418Smckusick 			putchar('f');
1419702Slinton 			return;
1429702Slinton 
1439702Slinton 		case LONG:
1449702Slinton 		case ULONG:
1459702Slinton 		case INT:
1469702Slinton 		case UNSIGNED:
14724418Smckusick 			putchar('l');
1489702Slinton 			return;
1499702Slinton 
1509702Slinton 		case SHORT:
1519702Slinton 		case USHORT:
15224418Smckusick 			putchar('w');
1539702Slinton 			return;
1549702Slinton 
1559702Slinton 		case CHAR:
1569702Slinton 		case UCHAR:
15724418Smckusick 			putchar('b');
1589702Slinton 			return;
1599702Slinton 
1609702Slinton 		default:
1619702Slinton 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
1629702Slinton 			else {
16324418Smckusick 				putchar('l');
1649702Slinton 				return;
1659702Slinton 				}
1669702Slinton 		}
1679702Slinton }
1689702Slinton 
1699702Slinton zzzcode( p, c ) register NODE *p; {
17032935Sdonn 	register int m;
17132924Sdonn 	int val;
1729702Slinton 	switch( c ){
1739702Slinton 
1749702Slinton 	case 'N':  /* logical ops, turned into 0-1 */
1759702Slinton 		/* use register given by register 1 */
1769702Slinton 		cbgen( 0, m=getlab(), 'I' );
1779702Slinton 		deflab( p->bn.label );
1789702Slinton 		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->tn.rval] );
1799702Slinton 		deflab( m );
1809702Slinton 		return;
1819702Slinton 
1829702Slinton 	case 'P':
1839702Slinton 		cbgen( p->in.op, p->bn.label, c );
1849702Slinton 		return;
1859702Slinton 
1869702Slinton 	case 'A':
18732935Sdonn 	case 'V':
18832935Sdonn 		sconv( p, c == 'V' );
1899702Slinton 		return;
1909702Slinton 
19125751Sdonn 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
19225751Sdonn 		{
19325751Sdonn 		register NODE *l, *r, *s;
19425751Sdonn 		int rt;
19525751Sdonn 
19625751Sdonn 		l = p->in.left;
19725751Sdonn 		r = p->in.right;
19825751Sdonn 		s = talloc();
19925751Sdonn 		rt = r->in.type;
20025751Sdonn 
20125751Sdonn 		s->in.op = SCONV;
20225751Sdonn 		s->in.left = l;
20325751Sdonn 		s->in.type = rt;
20425751Sdonn 		zzzcode(s, 'A');
20525751Sdonn 		putstr("\n\t");
20625751Sdonn 
20725751Sdonn 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
20825751Sdonn 		putstr("2\t");
20925751Sdonn 		adrput(r);
21025751Sdonn 		putchar(',');
21125751Sdonn 		adrput(resc);
21225751Sdonn 		putstr("\n\t");
21325751Sdonn 
21425751Sdonn 		s->in.op = ASSIGN;
21525751Sdonn 		s->in.left = l;
21625751Sdonn 		s->in.right = resc;
21725751Sdonn 		s->in.type = l->in.type;
21825751Sdonn 		zzzcode(s, 'A');
21925751Sdonn 
22025751Sdonn 		s->in.op = FREE;
22125751Sdonn 		return;
22225751Sdonn 		}
22325751Sdonn 
22432928Sdonn 	case 'J':	/* unsigned DIV/MOD with constant divisors */
22532928Sdonn 		{
22632928Sdonn 		register int ck = INAREG;
22732928Sdonn 		int label1, label2;
22832928Sdonn 
22932928Sdonn 		/* case constant <= 1 is handled by optim() in pass 1 */
23032928Sdonn 		/* case constant < 0x80000000 is handled in table */
23132928Sdonn 		switch( p->in.op ) {
23232938Sdonn 		/* case DIV: handled in optim2() */
23332928Sdonn 		case MOD:
23432928Sdonn 			if( p->in.left->in.op == REG &&
23532928Sdonn 			    p->in.left->tn.rval == resc->tn.rval )
23632928Sdonn 				goto asgmod;
23732928Sdonn 			label1 = getlab();
23832928Sdonn 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
23932928Sdonn 			printf("\tjlssu\tL%d\n", label1);
24032928Sdonn 			expand(p, ck, "\tsubl2\tAR,A1\n");
24132928Sdonn 			printf("L%d:", label1);
24232928Sdonn 			break;
24332928Sdonn 		case ASG DIV:
24432928Sdonn 			label1 = getlab();
24532928Sdonn 			label2 = getlab();
24632928Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
24732928Sdonn 			printf("\tjgequ\tL%d\n", label1);
24832928Sdonn 			expand(p, ck, "\tmovl\t$1,AL\n");
24932928Sdonn 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
25032928Sdonn 			expand(p, ck, "\tclrl\tAL\n");
25132928Sdonn 			printf("L%d:", label2);
25232928Sdonn 			break;
25332928Sdonn 		case ASG MOD:
25432928Sdonn 		asgmod:
25532928Sdonn 			label1 = getlab();
25632928Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
25732928Sdonn 			printf("\tjlssu\tL%d\n", label1);
25832928Sdonn 			expand(p, ck, "\tsubl2\tAR,AL\n");
25932928Sdonn 			printf("L%d:", label1);
26032928Sdonn 			break;
26132928Sdonn 			}
26232928Sdonn 		return;
26332928Sdonn 		}
26432928Sdonn 
2659702Slinton 	case 'B':	/* get oreg value in temp register for left shift */
2669702Slinton 		{
2679702Slinton 		register NODE *r;
2689702Slinton 		if (xdebug) eprint(p, 0, &val, &val);
2699702Slinton 		r = p->in.right;
27032937Sdonn 		if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
27124418Smckusick 			putstr("movl");
2729702Slinton 		else {
27332935Sdonn 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
2749702Slinton 			prtype(r);
27524418Smckusick 			putchar('l');
2769702Slinton 			}
2779702Slinton 		return;
2789702Slinton 		}
2799702Slinton 
2809702Slinton 	case 'C':	/* num words pushed on arg stack */
2819702Slinton 		{
2829702Slinton 		extern int gc_numbytes;
2839702Slinton 		extern int xdebug;
2849702Slinton 
2859702Slinton 		if (xdebug) printf("->%d<-",gc_numbytes);
2869702Slinton 
2879702Slinton 		printf("$%d", gc_numbytes/(SZLONG/SZCHAR) );
2889702Slinton 		return;
2899702Slinton 		}
2909702Slinton 
2919702Slinton 	case 'D':	/* INCR and DECR */
2929702Slinton 		zzzcode(p->in.left, 'A');
29324418Smckusick 		putchar('\n');
29424418Smckusick 		putchar('\t');
2959702Slinton 
2969702Slinton 	case 'E':	/* INCR and DECR, FOREFF */
29732934Sdonn 		if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
2989702Slinton 			{
29932935Sdonn 			putstr(p->in.op == INCR ? "inc" : "dec");
3009702Slinton 			prtype(p->in.left);
30124418Smckusick 			putchar('\t');
3029702Slinton 			adrput(p->in.left);
3039702Slinton 			return;
3049702Slinton 			}
30532935Sdonn 		putstr(p->in.op == INCR ? "add" : "sub");
3069702Slinton 		prtype(p->in.left);
30724418Smckusick 		putchar('2');
30824418Smckusick 		putchar('\t');
3099702Slinton 		adrput(p->in.right);
31024418Smckusick 		putchar(',');
3119702Slinton 		adrput(p->in.left);
3129702Slinton 		return;
3139702Slinton 
3149702Slinton 	case 'F':	/* register type of right operand */
3159702Slinton 		{
3169702Slinton 		register NODE *n;
3179702Slinton 		extern int xdebug;
3189702Slinton 		register int ty;
3199702Slinton 
3209702Slinton 		n = getlr( p, 'R' );
3219702Slinton 		ty = n->in.type;
3229702Slinton 
3239702Slinton 		if (xdebug) printf("->%d<-", ty);
3249702Slinton 
32524418Smckusick 		if ( ty==DOUBLE) putchar('d');
32624418Smckusick 		else if ( ty==FLOAT ) putchar('f');
32724418Smckusick 		else putchar('l');
3289702Slinton 		return;
3299702Slinton 		}
3309702Slinton 
3319702Slinton 	case 'L':	/* type of left operand */
3329702Slinton 	case 'R':	/* type of right operand */
3339702Slinton 		{
3349702Slinton 		register NODE *n;
3359702Slinton 		extern int xdebug;
3369702Slinton 
33716181Sralph 		n = getlr( p, c );
3389702Slinton 		if (xdebug) printf("->%d<-", n->in.type);
3399702Slinton 
3409702Slinton 		prtype(n);
3419702Slinton 		return;
3429702Slinton 		}
3439702Slinton 
34432938Sdonn 	case 'Z':	/* AND for CC with ICON -- lval is complemented */
34532938Sdonn 		{
34632938Sdonn 		register NODE *l, *r;
34732938Sdonn 
34832938Sdonn 		l = getlr( p, 'L' );
34932938Sdonn 		r = getlr( p, 'R' );
35032938Sdonn 		m = (1 << tlen(l) * SZCHAR) - 1;
35132938Sdonn 		r->tn.lval = ~r->tn.lval;
35232938Sdonn 		if( (l->in.type == CHAR || l->in.type == SHORT) &&
35332938Sdonn 		    (r->tn.lval & ~m) ) {
35432938Sdonn 			putstr("cvt");
35532938Sdonn 			prtype(l);
35632938Sdonn 			putstr("l\t");
35732938Sdonn 			adrput(l);
35832938Sdonn 			putchar(',');
35932938Sdonn 			adrput(resc);
36032938Sdonn 			putstr("\n\t");
36132938Sdonn 			resc->tn.type = INT;
36232938Sdonn 			l = resc;
36332938Sdonn 			}
36432938Sdonn 		else if( l->in.type == UCHAR || l->in.type == USHORT )
36532938Sdonn 			/* remove trash left over from complementing */
36632938Sdonn 			r->tn.lval &= m;
36732938Sdonn 		putstr("bit");
36832938Sdonn 		prtype(l);
36932938Sdonn 		printf("\t$%ld", r->tn.lval);
37032938Sdonn 		putchar(',');
37132938Sdonn 		adrput(l);
3729702Slinton 		return;
37332938Sdonn 		}
3749702Slinton 
3759702Slinton 	case 'U':	/* 32 - n, for unsigned right shifts */
3769702Slinton 		printf("$%d", 32 - p->in.right->tn.lval );
3779702Slinton 		return;
3789702Slinton 
3799702Slinton 	case 'T':	/* rounded structure length for arguments */
3809702Slinton 		{
3819702Slinton 		int size;
3829702Slinton 
3839702Slinton 		size = p->stn.stsize;
3849702Slinton 		SETOFF( size, 4);
3859702Slinton 		printf("$%d", size);
3869702Slinton 		return;
3879702Slinton 		}
3889702Slinton 
3899702Slinton 	case 'S':  /* structure assignment */
39032935Sdonn 		stasg(p);
39132935Sdonn 		break;
3929702Slinton 
39332935Sdonn 	default:
39432935Sdonn 		cerror( "illegal zzzcode" );
39532935Sdonn 		}
39632935Sdonn 	}
3979702Slinton 
39832935Sdonn stasg(p)
39932935Sdonn 	register NODE *p;
40032935Sdonn {
40132935Sdonn 	register NODE *l, *r;
40232935Sdonn 	register size;
4039702Slinton 
40432935Sdonn 	if( p->in.op == STASG ){
40532935Sdonn 		l = p->in.left;
40632935Sdonn 		r = p->in.right;
4079702Slinton 
40832935Sdonn 		}
40932935Sdonn 	else if( p->in.op == STARG ){  /* store an arg into a temporary */
41032935Sdonn 		r = p->in.left;
41132935Sdonn 		}
41232935Sdonn 	else cerror( "STASG bad" );
4139702Slinton 
41432935Sdonn 	if( r->in.op == ICON ) r->in.op = NAME;
41532935Sdonn 	else if( r->in.op == REG ) r->in.op = OREG;
41632935Sdonn 	else if( r->in.op != OREG ) cerror( "STASG-r" );
4179702Slinton 
41832935Sdonn 	size = p->stn.stsize;
41932935Sdonn 
42032935Sdonn 	if( size <= 0 || size > 65535 )
42132935Sdonn 		cerror("structure size <0=0 or >65535");
42232935Sdonn 
42332935Sdonn 	switch(size) {
42432935Sdonn 		case 1:
42532935Sdonn 			putstr("	movb	");
42632935Sdonn 			break;
42732935Sdonn 		case 2:
42832935Sdonn 			putstr("	movw	");
42932935Sdonn 			break;
43032935Sdonn 		case 4:
43132935Sdonn 			putstr("	movl	");
43232935Sdonn 			break;
43332935Sdonn 		case 8:
43432935Sdonn 			putstr("	movq	");
43532935Sdonn 			break;
43632935Sdonn 		default:
43732935Sdonn 			printf("	movc3	$%d,", size);
43832935Sdonn 			break;
43932935Sdonn 	}
44032935Sdonn 	adrput(r);
44132935Sdonn 	if( p->in.op == STASG ){
44232935Sdonn 		putchar(',');
44332935Sdonn 		adrput(l);
44432935Sdonn 		putchar('\n');
44532935Sdonn 		}
44632935Sdonn 	else
44732935Sdonn 		putstr(",(sp)\n");
44832935Sdonn 
44932935Sdonn 	if( r->in.op == NAME ) r->in.op = ICON;
45032935Sdonn 	else if( r->in.op == OREG ) r->in.op = REG;
45132935Sdonn 	}
45232935Sdonn 
45332935Sdonn NODE *makearg( ty ) int ty; {
45432935Sdonn 	register NODE *p, *q;
45532935Sdonn 
45632935Sdonn 	/* build a -(sp) operand */
45732935Sdonn 	p = talloc();
45832935Sdonn 	p->in.op = REG;
45932935Sdonn 	/* the type needn't be right, just consistent */
46032935Sdonn 	p->in.type = INCREF(ty);
46132935Sdonn 	p->tn.rval = SP;
46232935Sdonn 	p->tn.lval = 0;
46332935Sdonn 	q = talloc();
46432935Sdonn 	q->in.op = ASG MINUS;
46532935Sdonn 	q->in.type = INCREF(ty);
46632935Sdonn 	q->in.left = p;
46732935Sdonn 	p = talloc();
46832935Sdonn 	p->in.op = ICON;
46932935Sdonn 	p->in.type = INT;
47032935Sdonn 	p->tn.name = "";
47132941Sdonn 	/* size of floating argument is always 2 */
47232941Sdonn 	p->tn.lval = (1 + (ty == FLOAT || ty == DOUBLE)) * (SZINT/SZCHAR);
47332935Sdonn 	q->in.right = p;
47432935Sdonn 	p = talloc();
47532935Sdonn 	p->in.op = UNARY MUL;
47632935Sdonn 	p->in.left = q;
47732935Sdonn 	return( p );
47832935Sdonn 	}
47932935Sdonn 
48032935Sdonn sconv( p, forarg ) register NODE *p; {
48132935Sdonn 	register NODE *l, *r;
48232935Sdonn 	int m, val;
48332935Sdonn 
48432935Sdonn 	if (xdebug) eprint(p, 0, &val, &val);
48532935Sdonn 	r = getlr(p, 'R');
48632935Sdonn 	if (p->in.op == ASSIGN)
48732935Sdonn 		l = getlr(p, 'L');
48832935Sdonn 	else if (p->in.op == SCONV) {
48932935Sdonn 		m = r->in.type;
49032935Sdonn 		if (forarg)
49132935Sdonn 			l = makearg( m );
49232935Sdonn 		else
49332935Sdonn 			l = resc;
49432935Sdonn 		l->in.type = m;
49532935Sdonn 		r = getlr(p, 'L');
49632935Sdonn 		}
49732935Sdonn 	else {		/* OPLTYPE */
49832935Sdonn 		m = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT);
49932935Sdonn 		if (forarg)
50032935Sdonn 			l = makearg( m );
50132935Sdonn 		else
50232935Sdonn 			l = resc;
50332935Sdonn 		l->in.type = m;
50432935Sdonn 		}
50532935Sdonn 	if (r->in.op == ICON)
50632935Sdonn 		if (r->in.name[0] == '\0') {
50732942Sdonn 			if (r->tn.lval == 0 &&
50832942Sdonn 			    (r->in.type == DOUBLE || r->in.type == FLOAT ||
50932942Sdonn 			    !forarg)) {
51032942Sdonn 				if (r->in.type == FLOAT)
51132942Sdonn 					r->in.type = DOUBLE;
51232935Sdonn 				putstr("clr");
51332935Sdonn 				prtype(l);
51432935Sdonn 				putchar('\t');
51516418Sralph 				adrput(l);
51632935Sdonn 				goto cleanup;
51716418Sralph 				}
51832935Sdonn 			if (r->tn.lval < 0 && r->tn.lval >= -63) {
51932935Sdonn 				putstr("mneg");
52032935Sdonn 				prtype(l);
52132935Sdonn 				r->tn.lval = -r->tn.lval;
52232935Sdonn 				goto ops;
52332935Sdonn 				}
52432935Sdonn 			if (r->tn.lval < 0)
52532935Sdonn 				r->in.type = r->tn.lval >= -128 ? CHAR
52632935Sdonn 					: (r->tn.lval >= -32768 ? SHORT
52732935Sdonn 					: INT);
52832935Sdonn 			else if (l->in.type == FLOAT ||
52932935Sdonn 			    l->in.type == DOUBLE)
53032935Sdonn 				r->in.type = r->tn.lval <= 63 ? INT
53132935Sdonn 					: (r->tn.lval <= 127 ? CHAR
53232935Sdonn 					: (r->tn.lval <= 32767 ? SHORT
53332935Sdonn 					: INT));
53416418Sralph 			else
53532935Sdonn 				r->in.type = r->tn.lval <= 63 ? INT
53632935Sdonn 					: (r->tn.lval <= 127 ? CHAR
53732935Sdonn 					: (r->tn.lval <= 255 ? UCHAR
53832935Sdonn 					: (r->tn.lval <= 32767 ? SHORT
53932935Sdonn 					: (r->tn.lval <= 65535 ? USHORT
54032935Sdonn 					: INT))));
54132938Sdonn 			if (forarg && r->in.type == INT) {
54232938Sdonn 				putstr("pushl\t");
54332938Sdonn 				adrput(r);
54432938Sdonn 				goto cleanup;
54532938Sdonn 				}
54632935Sdonn 			}
54732935Sdonn 		else {
54832938Sdonn 			if (forarg && tlen(r) == SZINT/SZCHAR) {
54932938Sdonn 				putstr("pushl\t");
55032938Sdonn 				adrput(r);
55132938Sdonn 				goto cleanup;
55232938Sdonn 				}
55332938Sdonn 			putstr("moval\t");
55432935Sdonn 			acon(r);
55532935Sdonn 			putchar(',');
55632935Sdonn 			adrput(l);
55732935Sdonn 			goto cleanup;
55832935Sdonn 			}
5599702Slinton 
56032935Sdonn 	if (p->in.op == SCONV &&
56132935Sdonn 	    !(l->in.type == FLOAT || l->in.type == DOUBLE) &&
56232935Sdonn 	    !mixtypes(l, r)) {
56332935Sdonn 		/*
56432935Sdonn 		 * Because registers must always contain objects
56532935Sdonn 		 * of the same width as INTs, we may have to
56632935Sdonn 		 * perform two conversions to get an INT.  Can
56732935Sdonn 		 * the conversions be collapsed into one?
56832935Sdonn 		 */
56932935Sdonn 		if (m = collapsible(l, r))
57032935Sdonn 			r->in.type = m;
57132935Sdonn 		else {
57232943Sdonn 			/* two steps are required */
57332940Sdonn 			NODE *x;
5749702Slinton 
57532940Sdonn 			if (forarg) {
57632940Sdonn 				x = resc;
57732940Sdonn 				x->in.type = l->in.type;
57832940Sdonn 				}
57932940Sdonn 			else {
58032940Sdonn 				x = &resc[1];
58132940Sdonn 				*x = *l;
58232940Sdonn 				}
58332940Sdonn 
58432935Sdonn 			if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type))
58532935Sdonn 				putstr("movz");
58632935Sdonn 			else
58732935Sdonn 				putstr("cvt");
58832935Sdonn 			prtype(r);
58932935Sdonn 			prtype(x);
59032935Sdonn 			putchar('\t');
59132935Sdonn 			adrput(r);
59232935Sdonn 			putchar(',');
59332935Sdonn 			adrput(x);
59432935Sdonn 			putchar('\n');
59532935Sdonn 			putchar('\t');
59632935Sdonn 			r = x;
5979702Slinton 			}
59832935Sdonn 		l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT);
59932935Sdonn 		}
6009702Slinton 
60132943Sdonn 	else if ((forarg || l == resc) &&
60232943Sdonn 		 tlen(l) < SZINT/SZCHAR &&
60332943Sdonn 		 mixtypes(l, r)) {
60432943Sdonn 		/* two steps needed here too */
60532943Sdonn 		NODE *x;
60632943Sdonn 
60732943Sdonn 		if (forarg) {
60832943Sdonn 			x = resc;
60932943Sdonn 			x->in.type = l->in.type;
61032943Sdonn 			}
61132943Sdonn 		else {
61232943Sdonn 			x = &resc[1];
61332943Sdonn 			*x = *l;
61432943Sdonn 			}
61532943Sdonn 		putstr("cvt");
61632943Sdonn 		prtype(r);
61732943Sdonn 		prtype(x);
61832943Sdonn 		putchar('\t');
61932943Sdonn 		adrput(r);
62032943Sdonn 		putchar(',');
62132943Sdonn 		adrput(x);
62232943Sdonn 		putstr("\n\t");
62332943Sdonn 		r = x;
62432943Sdonn 		l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT);
62532943Sdonn 		}
62632943Sdonn 
62732943Sdonn 	else if ((r->in.type == UNSIGNED || r->in.type == ULONG) &&
62832935Sdonn 	    mixtypes(l, r)) {
62932935Sdonn 		int label1, label2;
63032940Sdonn 		NODE *x = NULL;
63132935Sdonn 
63232940Sdonn #if defined(FORT) || defined(SPRECC)
63332940Sdonn 		if (forarg)
63432940Sdonn #else
63532940Sdonn 		if (forarg || l == resc)
63632940Sdonn #endif
63732940Sdonn 			{
63832940Sdonn 			/* compute in register, convert to double when done */
63932940Sdonn 			x = l;
64032940Sdonn 			l = resc;
64132940Sdonn 			l->in.type = x->in.type;
64232940Sdonn 			}
64332940Sdonn 
64432935Sdonn 		label1 = getlab();
64532935Sdonn 		label2 = getlab();
64632935Sdonn 
64732935Sdonn 		putstr("movl\t");
64832935Sdonn 		adrput(r);
64932935Sdonn 		putchar(',');
65032935Sdonn 		adrput(l);
65132935Sdonn 		putstr("\n\tjbsc\t$31,");
65232935Sdonn 		adrput(l);
65332935Sdonn 		printf(",L%d\n\tcvtl", label1);
65432935Sdonn 		prtype(l);
65532935Sdonn 		putchar('\t');
65632935Sdonn 		adrput(l);
65732935Sdonn 		putchar(',');
65832935Sdonn 		adrput(l);
65932935Sdonn 		printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1);
66032935Sdonn 		prtype(l);
66132935Sdonn 		putchar('\t');
66232935Sdonn 		adrput(l);
66332935Sdonn 		putchar(',');
66432935Sdonn 		adrput(l);
66532935Sdonn 		putstr("\n\tadd");
66632935Sdonn 		prtype(l);
66732935Sdonn 		putstr("2\t$0");
66832935Sdonn 		prtype(l);
66932935Sdonn 		putstr("2.147483648e9,");
67032935Sdonn 		adrput(l);
67132935Sdonn 		printf("\nL%d:", label2);
67232935Sdonn 
67332943Sdonn #if defined(FORT) || defined(SPRECC)
67432943Sdonn 		if (!forarg)
67532943Sdonn #else
67632940Sdonn 		if (!forarg && (l->in.type == DOUBLE || l != resc))
67732943Sdonn #endif
67832940Sdonn 			goto cleanup;
67932943Sdonn 		if (x == NULL)
68032943Sdonn 			cerror("sconv botch");
68132943Sdonn 		if (l == x) {
68232943Sdonn 			r = &resc[1];
68332943Sdonn 			*r = *l;
68432940Sdonn 			}
68532943Sdonn 		else {
68632943Sdonn 			r = l;
68732943Sdonn 			l = x;
68832943Sdonn 			}
68932943Sdonn 		l->in.type = DOUBLE;
69032940Sdonn 		putstr("\n\t");
6919702Slinton 		}
69232935Sdonn 
69332943Sdonn 	else if( (l->in.type == FLOAT || l->in.type == DOUBLE) &&
69432940Sdonn 	    (r->in.type == UCHAR || r->in.type == USHORT) ) {
69532940Sdonn 		/* skip unnecessary unsigned to floating conversion */
69632940Sdonn #if defined(FORT) || defined(SPRECC)
69732940Sdonn 		if (forarg)
69832940Sdonn #else
69932940Sdonn 		if (forarg || l == resc)
70032940Sdonn #endif
70132940Sdonn 			l->in.type = DOUBLE;
70232940Sdonn 		putstr("movz");
70332940Sdonn 		prtype(r);
70432940Sdonn 		putstr("l\t");
70532940Sdonn 		adrput(r);
70632940Sdonn 		putchar(',');
70732940Sdonn 		adrput(resc);
70832940Sdonn 		putstr("\n\t");
70932940Sdonn 		if (l == resc) {
71032940Sdonn 			r = &resc[1];
71132940Sdonn 			*r = *l;
71232940Sdonn 			}
71332940Sdonn 		else
71432940Sdonn 			r = resc;
71532940Sdonn 		r->in.type = INT;
71632940Sdonn 		}
71732940Sdonn 
71832940Sdonn #if defined(FORT) || defined(SPRECC)
71932940Sdonn 	if (forarg && l->in.type == FLOAT)
72032940Sdonn #else
72132940Sdonn 	if ((forarg || l == resc) && l->in.type == FLOAT)
72232940Sdonn #endif
72332940Sdonn 		{
72432940Sdonn 		/* perform an implicit conversion to double */
72532940Sdonn 		l->in.type = DOUBLE;
72632940Sdonn 		if (r->in.type != FLOAT &&
72732940Sdonn 		    r->in.type != CHAR &&
72832940Sdonn 		    r->in.type != SHORT) {
72932940Sdonn 			/* trim bits from the mantissa */
73032940Sdonn 			putstr("cvt");
73132940Sdonn 			prtype(r);
73232940Sdonn 			putstr("f\t");
73332940Sdonn 			adrput(r);
73432940Sdonn 			putchar(',');
73532940Sdonn 			adrput(resc);
73632940Sdonn 			putstr("\n\t");
73732940Sdonn 			if (l == resc) {
73832940Sdonn 				r = &resc[1];
73932940Sdonn 				*r = *l;
74032940Sdonn 				}
74132940Sdonn 			else
74232940Sdonn 				r = resc;
74332940Sdonn 			r->in.type = FLOAT;
74432940Sdonn 			}
74532940Sdonn 		}
74632940Sdonn 
74732935Sdonn 	if (!mixtypes(l,r)) {
74832935Sdonn 		if (tlen(l) == tlen(r)) {
74932938Sdonn 			if (forarg && tlen(l) == SZINT/SZCHAR) {
75032938Sdonn 				putstr("pushl\t");
75132938Sdonn 				adrput(r);
75232938Sdonn 				goto cleanup;
75332938Sdonn 				}
75432935Sdonn 			putstr("mov");
75532935Sdonn #ifdef FORT
75632935Sdonn 			if (Oflag)
75732935Sdonn 				prtype(l);
75832935Sdonn 			else {
75932935Sdonn 				if (l->in.type == DOUBLE)
76032935Sdonn 					putchar('q');
76132935Sdonn 				else if(l->in.type == FLOAT)
76232935Sdonn 					putchar('l');
76332935Sdonn 				else
76432935Sdonn 					prtype(l);
76532935Sdonn 				}
76632935Sdonn #else
76732935Sdonn 			prtype(l);
76832935Sdonn #endif FORT
76932935Sdonn 			goto ops;
77032935Sdonn 			}
77132935Sdonn 		else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
77232935Sdonn 			putstr("movz");
77332935Sdonn 		else
77432935Sdonn 			putstr("cvt");
77532935Sdonn 		}
77632935Sdonn 	else
77732935Sdonn 		putstr("cvt");
77832935Sdonn 	prtype(r);
77932935Sdonn 	prtype(l);
78032935Sdonn ops:
78132935Sdonn 	putchar('\t');
78232935Sdonn 	adrput(r);
78332935Sdonn 	putchar(',');
78432935Sdonn 	adrput(l);
78532935Sdonn 
78632935Sdonn cleanup:
78732935Sdonn 	if (forarg)
78832935Sdonn 		tfree(l);
7899702Slinton 	}
7909702Slinton 
79123536Sbloom /*
79223536Sbloom  * collapsible(dest, src) -- if a conversion with a register destination
79323536Sbloom  *	can be accomplished in one instruction, return the type of src
79423536Sbloom  *	that will do the job correctly; otherwise return 0.  Note that
79523536Sbloom  *	a register must always end up having type INT or UNSIGNED.
79623536Sbloom  */
79723536Sbloom int
79823536Sbloom collapsible(dest, src)
79923536Sbloom NODE *dest, *src;
80023536Sbloom {
80123536Sbloom 	int st = src->in.type;
80223536Sbloom 	int dt = dest->in.type;
80323536Sbloom 	int newt = 0;
80423536Sbloom 
80523536Sbloom 	/*
80623536Sbloom 	 * Are there side effects of evaluating src?
80723536Sbloom 	 * If the derived type will not be the same size as src,
80824418Smckusick 	 * we may have to use two steps.
80923536Sbloom 	 */
81024418Smckusick 	if (tlen(src) > tlen(dest)) {
81124418Smckusick 		if (tshape(src, STARREG))
81224418Smckusick 			return (0);
81324418Smckusick 		if (src->in.op == OREG && R2TEST(src->tn.rval))
81424418Smckusick 			return (0);
81524418Smckusick 		}
81623536Sbloom 
81723536Sbloom 	/*
81823536Sbloom 	 * Can we get an object of dest's type by punning src?
81923536Sbloom 	 * Praises be to great Cthulhu for little-endian machines...
82023536Sbloom 	 */
82123536Sbloom 	if (st == CHAR && dt == USHORT)
82223536Sbloom 		/*
82323536Sbloom 		 * Special case -- we must sign-extend to 16 bits.
82423536Sbloom 		 */
82523536Sbloom 		return (0);
82623536Sbloom 
82723536Sbloom 	if (tlen(src) < tlen(dest))
82823536Sbloom 		newt = st;
82923536Sbloom 	else
83023536Sbloom 		newt = dt;
83123536Sbloom 
83223536Sbloom 	return (newt);
83323536Sbloom 	}
83423536Sbloom 
83517742Sralph rmove( rt, rs, t ) TWORD t; {
8369702Slinton 	printf( "	%s	%s,%s\n",
83717742Sralph #ifdef FORT
83817742Sralph 		!Oflag ? (t==DOUBLE ? "movq" : "movl") :
83917742Sralph #endif
8409702Slinton 		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
8419702Slinton 		rnames[rs], rnames[rt] );
8429702Slinton 	}
8439702Slinton 
8449702Slinton struct respref
8459702Slinton respref[] = {
8469702Slinton 	INTAREG|INTBREG,	INTAREG|INTBREG,
8479702Slinton 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
8489702Slinton 	INTEMP,	INTEMP,
8499702Slinton 	FORARG,	FORARG,
8509702Slinton 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
8519702Slinton 	0,	0 };
8529702Slinton 
8539702Slinton setregs(){ /* set up temporary registers */
8549702Slinton 	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
8559702Slinton 	}
8569702Slinton 
85732924Sdonn /*ARGSUSED*/
8589702Slinton rewfld( p ) NODE *p; {
8599702Slinton 	return(1);
8609702Slinton 	}
8619702Slinton 
86232924Sdonn /*ARGSUSED*/
8639702Slinton callreg(p) NODE *p; {
8649702Slinton 	return( R0 );
8659702Slinton 	}
8669702Slinton 
8679702Slinton base( p ) register NODE *p; {
8689702Slinton 	register int o = p->in.op;
8699702Slinton 
87032938Sdonn 	if( o==ICON && p->tn.name[0] != '\0' ) return( 100 ); /* ie no base reg */
8719702Slinton 	if( o==REG ) return( p->tn.rval );
8729702Slinton     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
8739702Slinton 		return( p->in.left->tn.rval );
8749702Slinton     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
8759702Slinton 		return( p->tn.rval + 0200*1 );
8769702Slinton 	if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 );
8779702Slinton 	if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 );
8789702Slinton 	if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG
8799702Slinton 	  && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
8809702Slinton 		return( p->in.left->in.left->tn.rval + 0200*(1+2) );
88132938Sdonn 	if( o==NAME ) return( 100 + 0200*1 );
8829702Slinton 	return( -1 );
8839702Slinton 	}
8849702Slinton 
8859702Slinton offset( p, tyl ) register NODE *p; int tyl; {
8869702Slinton 
88724418Smckusick 	if( tyl==1 &&
88824418Smckusick 	    p->in.op==REG &&
88924418Smckusick 	    (p->in.type==INT || p->in.type==UNSIGNED) )
89024418Smckusick 		return( p->tn.rval );
89124418Smckusick 	if( p->in.op==LS &&
89224418Smckusick 	    p->in.left->in.op==REG &&
89324418Smckusick 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
89424418Smckusick 	    p->in.right->in.op==ICON &&
89524418Smckusick 	    p->in.right->in.name[0]=='\0' &&
89624418Smckusick 	    (1<<p->in.right->tn.lval)==tyl)
8979702Slinton 		return( p->in.left->tn.rval );
89824418Smckusick 	if( tyl==2 &&
89924418Smckusick 	    p->in.op==PLUS &&
90024418Smckusick 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
90124418Smckusick 	    p->in.left->in.op==REG &&
90224418Smckusick 	    p->in.right->in.op==REG &&
90324418Smckusick 	    p->in.left->tn.rval==p->in.right->tn.rval )
90424418Smckusick 		return( p->in.left->tn.rval );
9059702Slinton 	return( -1 );
9069702Slinton 	}
9079702Slinton 
9089702Slinton makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
9099702Slinton 	register NODE *t;
9109702Slinton 	NODE *f;
9119702Slinton 
9129702Slinton 	p->in.op = OREG;
9139702Slinton 	f = p->in.left; 	/* have to free this subtree later */
9149702Slinton 
9159702Slinton 	/* init base */
9169702Slinton 	switch (q->in.op) {
9179702Slinton 		case ICON:
9189702Slinton 		case REG:
9199702Slinton 		case OREG:
92032938Sdonn 		case NAME:
9219702Slinton 			t = q;
9229702Slinton 			break;
9239702Slinton 
9249702Slinton 		case MINUS:
9259702Slinton 			q->in.right->tn.lval = -q->in.right->tn.lval;
9269702Slinton 		case PLUS:
9279702Slinton 			t = q->in.right;
9289702Slinton 			break;
9299702Slinton 
9309702Slinton 		case INCR:
9319702Slinton 		case ASG MINUS:
9329702Slinton 			t = q->in.left;
9339702Slinton 			break;
9349702Slinton 
9359702Slinton 		case UNARY MUL:
9369702Slinton 			t = q->in.left->in.left;
9379702Slinton 			break;
9389702Slinton 
9399702Slinton 		default:
9409702Slinton 			cerror("illegal makeor2");
9419702Slinton 	}
9429702Slinton 
9439702Slinton 	p->tn.lval = t->tn.lval;
9449702Slinton #ifndef FLEXNAMES
94532924Sdonn 	{
94632924Sdonn 		register int i;
94732924Sdonn 		for(i=0; i<NCHNAM; ++i)
94832924Sdonn 			p->in.name[i] = t->in.name[i];
94932924Sdonn 	}
9509702Slinton #else
9519702Slinton 	p->in.name = t->in.name;
9529702Slinton #endif
9539702Slinton 
9549702Slinton 	/* init offset */
9559702Slinton 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
9569702Slinton 
9579702Slinton 	tfree(f);
9589702Slinton 	return;
9599702Slinton 	}
9609702Slinton 
9619702Slinton canaddr( p ) NODE *p; {
9629702Slinton 	register int o = p->in.op;
9639702Slinton 
9649702Slinton 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
9659702Slinton 	return(0);
9669702Slinton 	}
9679702Slinton 
96832935Sdonn flshape( p ) NODE *p; {
96932935Sdonn 	register int o = p->in.op;
97032935Sdonn 
97132935Sdonn 	return( o == REG || o == NAME || o == ICON ||
97232935Sdonn 		(o == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
9739702Slinton 	}
9749702Slinton 
97532926Sdonn /* INTEMP shapes must not contain any temporary registers */
9769702Slinton shtemp( p ) register NODE *p; {
97732926Sdonn 	int r;
97832926Sdonn 
9799702Slinton 	if( p->in.op == STARG ) p = p->in.left;
98032926Sdonn 
98132926Sdonn 	switch (p->in.op) {
98232926Sdonn 	case REG:
98332926Sdonn 		return( !istreg(p->tn.rval) );
98432926Sdonn 	case OREG:
98532926Sdonn 		r = p->tn.rval;
98632926Sdonn 		if( R2TEST(r) ) {
98732926Sdonn 			if( istreg(R2UPK1(r)) )
98832926Sdonn 				return(0);
98932926Sdonn 			r = R2UPK2(r);
99032926Sdonn 			}
99132926Sdonn 		return( !istreg(r) );
99232926Sdonn 	case UNARY MUL:
99332926Sdonn 		p = p->in.left;
99432926Sdonn 		return( p->in.op != UNARY MUL && shtemp(p) );
99532926Sdonn 		}
99632926Sdonn 
99732926Sdonn 	if( optype( p->in.op ) != LTYPE ) return(0);
99832926Sdonn 	return(1);
9999702Slinton 	}
10009702Slinton 
10019702Slinton shumul( p ) register NODE *p; {
100232935Sdonn 	register int o;
10039702Slinton 	extern int xdebug;
10049702Slinton 
10059702Slinton 	if (xdebug) {
100632933Sdonn 		int val;
100732933Sdonn 		printf("shumul:\n");
100832933Sdonn 		eprint(p, 0, &val, &val);
10099702Slinton 		}
10109702Slinton 
10119702Slinton 	o = p->in.op;
10129702Slinton 	if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
10139702Slinton 
10149702Slinton 	if( ( o == INCR || o == ASG MINUS ) &&
10159702Slinton 	    ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) &&
10169702Slinton 	    p->in.right->in.name[0] == '\0' )
10179702Slinton 		{
101817659Sralph 		switch (p->in.type)
10199702Slinton 			{
10209702Slinton 			case CHAR|PTR:
10219702Slinton 			case UCHAR|PTR:
10229702Slinton 				o = 1;
10239702Slinton 				break;
10249702Slinton 
10259702Slinton 			case SHORT|PTR:
10269702Slinton 			case USHORT|PTR:
10279702Slinton 				o = 2;
10289702Slinton 				break;
10299702Slinton 
10309702Slinton 			case INT|PTR:
10319702Slinton 			case UNSIGNED|PTR:
10329702Slinton 			case LONG|PTR:
10339702Slinton 			case ULONG|PTR:
10349702Slinton 			case FLOAT|PTR:
10359702Slinton 				o = 4;
10369702Slinton 				break;
10379702Slinton 
10389702Slinton 			case DOUBLE|PTR:
10399702Slinton 				o = 8;
10409702Slinton 				break;
10419702Slinton 
10429702Slinton 			default:
104317742Sralph 				if ( ISPTR(p->in.type) &&
104417742Sralph 				     ISPTR(DECREF(p->in.type)) ) {
10459702Slinton 					o = 4;
10469702Slinton 					break;
10479702Slinton 					}
10489702Slinton 				else return(0);
10499702Slinton 			}
10509702Slinton 		return( p->in.right->tn.lval == o ? STARREG : 0);
10519702Slinton 		}
10529702Slinton 
10539702Slinton 	return( 0 );
10549702Slinton 	}
10559702Slinton 
10569702Slinton adrcon( val ) CONSZ val; {
105724418Smckusick 	putchar( '$' );
10589702Slinton 	printf( CONFMT, val );
10599702Slinton 	}
10609702Slinton 
10619702Slinton conput( p ) register NODE *p; {
10629702Slinton 	switch( p->in.op ){
10639702Slinton 
10649702Slinton 	case ICON:
10659702Slinton 		acon( p );
10669702Slinton 		return;
10679702Slinton 
10689702Slinton 	case REG:
106924418Smckusick 		putstr( rnames[p->tn.rval] );
10709702Slinton 		return;
10719702Slinton 
10729702Slinton 	default:
10739702Slinton 		cerror( "illegal conput" );
10749702Slinton 		}
10759702Slinton 	}
10769702Slinton 
107732923Sdonn /*ARGSUSED*/
107832924Sdonn insput( p ) NODE *p; {
10799702Slinton 	cerror( "insput" );
10809702Slinton 	}
10819702Slinton 
108232928Sdonn upput( p, size ) NODE *p; int size; {
108332928Sdonn 	if( size == SZLONG && p->in.op == REG ) {
108432928Sdonn 		putstr( rnames[p->tn.rval + 1] );
108532928Sdonn 		return;
108632928Sdonn 		}
10879702Slinton 	cerror( "upput" );
10889702Slinton 	}
10899702Slinton 
10909702Slinton adrput( p ) register NODE *p; {
10919702Slinton 	register int r;
10929702Slinton 	/* output an address, with offsets, from p */
10939702Slinton 
10949702Slinton 	if( p->in.op == FLD ){
10959702Slinton 		p = p->in.left;
10969702Slinton 		}
10979702Slinton 	switch( p->in.op ){
10989702Slinton 
10999702Slinton 	case NAME:
11009702Slinton 		acon( p );
11019702Slinton 		return;
11029702Slinton 
11039702Slinton 	case ICON:
11049702Slinton 		/* addressable value of the constant */
110524418Smckusick 		putchar( '$' );
11069702Slinton 		acon( p );
11079702Slinton 		return;
11089702Slinton 
11099702Slinton 	case REG:
111024418Smckusick 		putstr( rnames[p->tn.rval] );
11119702Slinton 		return;
11129702Slinton 
11139702Slinton 	case OREG:
11149702Slinton 		r = p->tn.rval;
11159702Slinton 		if( R2TEST(r) ){ /* double indexing */
11169702Slinton 			register int flags;
11179702Slinton 
11189702Slinton 			flags = R2UPK3(r);
111924418Smckusick 			if( flags & 1 ) putchar('*');
112024418Smckusick 			if( flags & 4 ) putchar('-');
11219702Slinton 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
11229702Slinton 			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
112324418Smckusick 			if( flags & 2 ) putchar('+');
11249702Slinton 			printf( "[%s]", rnames[R2UPK2(r)] );
11259702Slinton 			return;
11269702Slinton 			}
11279702Slinton 		if( r == AP ){  /* in the argument region */
112832925Sdonn 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
11299702Slinton 			printf( CONFMT, p->tn.lval );
113024418Smckusick 			putstr( "(ap)" );
11319702Slinton 			return;
11329702Slinton 			}
11339702Slinton 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
11349702Slinton 		printf( "(%s)", rnames[p->tn.rval] );
11359702Slinton 		return;
11369702Slinton 
11379702Slinton 	case UNARY MUL:
11389702Slinton 		/* STARNM or STARREG found */
11399702Slinton 		if( tshape(p, STARNM) ) {
114024418Smckusick 			putchar( '*' );
11419702Slinton 			adrput( p->in.left);
11429702Slinton 			}
11439702Slinton 		else {	/* STARREG - really auto inc or dec */
11449702Slinton 			register NODE *q;
11459702Slinton 
114617659Sralph 			q = p->in.left;
114717742Sralph 			if( q->in.right->tn.lval != tlen(p) )
114817742Sralph 				cerror("adrput: bad auto-increment/decrement");
114917659Sralph 			printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
115017659Sralph 				rnames[q->in.left->tn.rval],
115117659Sralph 				(q->in.op==INCR ? "+" : "") );
11529702Slinton 			p->in.op = OREG;
115317659Sralph 			p->tn.rval = q->in.left->tn.rval;
115417659Sralph 			p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0);
11559702Slinton #ifndef FLEXNAMES
11569702Slinton 			p->in.name[0] = '\0';
11579702Slinton #else
11589702Slinton 			p->in.name = "";
11599702Slinton #endif
11609702Slinton 			tfree(q);
11619702Slinton 		}
11629702Slinton 		return;
11639702Slinton 
11649702Slinton 	default:
11659702Slinton 		cerror( "illegal address" );
11669702Slinton 		return;
11679702Slinton 
11689702Slinton 		}
11699702Slinton 
11709702Slinton 	}
11719702Slinton 
11729702Slinton acon( p ) register NODE *p; { /* print out a constant */
11739702Slinton 
117432935Sdonn 	if( p->in.name[0] == '\0' )
11759702Slinton 		printf( CONFMT, p->tn.lval);
117632935Sdonn 	else {
11779702Slinton #ifndef FLEXNAMES
11789702Slinton 		printf( "%.8s", p->in.name );
11799702Slinton #else
118024418Smckusick 		putstr( p->in.name );
11819702Slinton #endif
118232935Sdonn 		if( p->tn.lval != 0 ) {
118332935Sdonn 			putchar( '+' );
118432935Sdonn 			printf( CONFMT, p->tn.lval );
118532935Sdonn 			}
11869702Slinton 		}
11879702Slinton 	}
11889702Slinton 
11899702Slinton genscall( p, cookie ) register NODE *p; {
11909702Slinton 	/* structure valued call */
11919702Slinton 	return( gencall( p, cookie ) );
11929702Slinton 	}
11939702Slinton 
11949702Slinton /* tbl */
11959702Slinton int gc_numbytes;
11969702Slinton /* tbl */
11979702Slinton 
119832924Sdonn /*ARGSUSED*/
11999702Slinton gencall( p, cookie ) register NODE *p; {
12009702Slinton 	/* generate the call given by p */
120116418Sralph 	register NODE *p1;
120232935Sdonn 	register int temp, temp1;
120332935Sdonn 	register int m;
12049702Slinton 
12059702Slinton 	if( p->in.right ) temp = argsize( p->in.right );
12069702Slinton 	else temp = 0;
12079702Slinton 
12089702Slinton 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
12099702Slinton 		/* set aside room for structure return */
12109702Slinton 
12119702Slinton 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
12129702Slinton 		else temp1 = temp;
12139702Slinton 		}
12149702Slinton 
12159702Slinton 	if( temp > maxargs ) maxargs = temp;
12169702Slinton 	SETOFF(temp1,4);
12179702Slinton 
12189702Slinton 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
121916418Sralph 		genargs( p->in.right );
12209702Slinton 		}
12219702Slinton 
12229702Slinton 	p1 = p->in.left;
12239702Slinton 	if( p1->in.op != ICON ){
12249702Slinton 		if( p1->in.op != REG ){
12259702Slinton 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
12269702Slinton 				if( p1->in.op != NAME ){
12279702Slinton 					order( p1, INAREG );
12289702Slinton 					}
12299702Slinton 				}
12309702Slinton 			}
12319702Slinton 		}
12329702Slinton 
12339702Slinton /* tbl
12349702Slinton 	setup gc_numbytes so reference to ZC works */
12359702Slinton 
12369702Slinton 	gc_numbytes = temp&(0x3ff);
12379702Slinton /* tbl */
12389702Slinton 
12399702Slinton 	p->in.op = UNARY CALL;
12409702Slinton 	m = match( p, INTAREG|INTBREG );
12419702Slinton 
12429702Slinton 	/* compensate for deficiency in 'ret' instruction ... wah,kre */
12439702Slinton 	/* (plus in assignment to gc_numbytes above, for neatness only) */
12449702Slinton 	if (temp >= 1024)
12459702Slinton 		printf("	addl2	$%d,sp\n", (temp&(~0x3ff)));
12469702Slinton 
12479702Slinton 	return(m != MDONE);
12489702Slinton 	}
12499702Slinton 
12509702Slinton /* tbl */
12519702Slinton char *
12529702Slinton ccbranches[] = {
125332935Sdonn 	"eql",
125432935Sdonn 	"neq",
125532935Sdonn 	"leq",
125632935Sdonn 	"lss",
125732935Sdonn 	"geq",
125832935Sdonn 	"gtr",
125932935Sdonn 	"lequ",
126032935Sdonn 	"lssu",
126132935Sdonn 	"gequ",
126232935Sdonn 	"gtru",
12639702Slinton 	};
12649702Slinton /* tbl */
12659702Slinton 
126632924Sdonn /*ARGSUSED*/
12679702Slinton cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
12689702Slinton 
126932935Sdonn 	if( o != 0 && ( o < EQ || o > UGT ) )
127032935Sdonn 		cerror( "bad conditional branch: %s", opst[o] );
127132935Sdonn 	printf( "	j%s	L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
12729702Slinton 	}
12739702Slinton 
12749702Slinton nextcook( p, cookie ) NODE *p; {
12759702Slinton 	/* we have failed to match p with cookie; try another */
12769702Slinton 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
12779702Slinton 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
12789702Slinton 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
12799702Slinton 	return( FORREW );
12809702Slinton 	}
12819702Slinton 
128232924Sdonn /*ARGSUSED*/
12839702Slinton lastchance( p, cook ) NODE *p; {
12849702Slinton 	/* forget it! */
12859702Slinton 	return(0);
12869702Slinton 	}
12879702Slinton 
12889702Slinton optim2( p ) register NODE *p; {
12899702Slinton 	/* do local tree transformations and optimizations */
12909702Slinton 
129132929Sdonn 	int o;
129232932Sdonn 	int i, mask;
129316181Sralph 	register NODE *l, *r;
12949702Slinton 
129532929Sdonn 	switch( o = p->in.op ) {
12969702Slinton 
1297*32944Sdonn 	case ASG PLUS:
1298*32944Sdonn 	case ASG MINUS:
1299*32944Sdonn 	case ASG MUL:
1300*32944Sdonn 	case ASG OR:
1301*32944Sdonn 		/* simple ASG OPSIMP -- reduce range of constant rhs */
1302*32944Sdonn 		l = p->in.left;
1303*32944Sdonn 		r = p->in.right;
1304*32944Sdonn 		if( tlen(l) < SZINT/SZCHAR &&
1305*32944Sdonn 		    r->in.op==ICON && r->in.name[0]==0 ){
1306*32944Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
1307*32944Sdonn 			if( r->tn.lval & (mask & ~(mask >> 1)) )
1308*32944Sdonn 				r->tn.lval |= ~mask;
1309*32944Sdonn 			else
1310*32944Sdonn 				r->tn.lval &= mask;
1311*32944Sdonn 			}
1312*32944Sdonn 		break;
1313*32944Sdonn 
13149702Slinton 	case AND:
131519933Smckusick 		/* commute L and R to eliminate complements and constants */
131616181Sralph 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
131716181Sralph 		    l->in.op == COMPL ) {
13189702Slinton 			p->in.left = p->in.right;
131916181Sralph 			p->in.right = l;
13209702Slinton 			}
1321*32944Sdonn 		/* fall through */
1322*32944Sdonn 
13239702Slinton 	case ASG AND:
1324*32944Sdonn 		/* change meaning of AND to ~R&L - bic on pdp11/vax */
13259702Slinton 		r = p->in.right;
132632931Sdonn 		if( r->in.op==ICON && r->in.name[0]==0 ) {
132732931Sdonn 			/* check for degenerate operations */
132832931Sdonn 			l = p->in.left;
132932932Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
1330*32944Sdonn 			if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
1331*32944Sdonn 				i = ~r->tn.lval & mask;
133232938Sdonn 				if( i == 0 ) {
1333*32944Sdonn 					/* redundant mask */
133432932Sdonn 					r->in.op = FREE;
133532932Sdonn 					ncopy(p, l);
133632932Sdonn 					l->in.op = FREE;
133732932Sdonn 					break;
133832932Sdonn 					}
133932938Sdonn 				else if( i == mask )
1340*32944Sdonn 					/* all bits masked off */
134132932Sdonn 					goto zero;
1342*32944Sdonn 				r->tn.lval = i;
1343*32944Sdonn 				if( tlen(l) < SZINT/SZCHAR ){
1344*32944Sdonn 					/* sign extend */
1345*32944Sdonn 					if( r->tn.lval & (mask & ~(mask >> 1)) )
1346*32944Sdonn 						r->tn.lval |= ~mask;
1347*32944Sdonn 					else
1348*32944Sdonn 						r->tn.lval &= mask;
1349*32944Sdonn 					}
135032938Sdonn 				break;
135132932Sdonn 				}
135232932Sdonn 			else if( r->tn.lval == mask &&
135332932Sdonn 				 tlen(l) < SZINT/SZCHAR ) {
1354*32944Sdonn 				/* use movz instead of bic */
135532932Sdonn 				r->in.op = SCONV;
135632932Sdonn 				r->in.left = l;
135732932Sdonn 				r->in.right = 0;
135832932Sdonn 				r->in.type = ENUNSIGN(l->in.type);
135932932Sdonn 				r->in.su = l->in.su > 1 ? l->in.su : 1;
136032932Sdonn 				ncopy(p, r);
136132932Sdonn 				p->in.left = r;
136232932Sdonn 				p->in.type = INT;
136332931Sdonn 				break;
136432931Sdonn 				}
136532931Sdonn 			/* complement constant */
13669702Slinton 			r->tn.lval = ~r->tn.lval;
13679702Slinton 			}
13689702Slinton 		else if( r->in.op==COMPL ) { /* ~~A => A */
13699702Slinton 			r->in.op = FREE;
13709702Slinton 			p->in.right = r->in.left;
13719702Slinton 			}
13729702Slinton 		else { /* insert complement node */
137316181Sralph 			p->in.right = l = talloc();
137416181Sralph 			l->in.op = COMPL;
137516181Sralph 			l->in.rall = NOPREF;
137616181Sralph 			l->in.type = r->in.type;
137716181Sralph 			l->in.left = r;
137816181Sralph 			l->in.right = NULL;
13799702Slinton 			}
13809702Slinton 		break;
13819702Slinton 
138216181Sralph 	case SCONV:
138319933Smckusick 		l = p->in.left;
138417742Sralph #if defined(FORT) || defined(SPRECC)
138516573Sralph 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
138619933Smckusick 		    l->in.type == FLOAT || l->in.type == DOUBLE )
138719933Smckusick 			return;
138816573Sralph #else
138919933Smckusick 		if( mixtypes(p, l) ) return;
139016573Sralph #endif
139132938Sdonn 		if( l->in.op == PCONV )
139225751Sdonn 			return;
139332938Sdonn 		if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
139432938Sdonn 		    l->in.type != INT && l->in.type != UNSIGNED )
139532938Sdonn 			return;
139625751Sdonn 
139719933Smckusick 		/* Only trust it to get it right if the size is the same */
139819933Smckusick 		if( tlen(p) != tlen(l) )
139919933Smckusick 			return;
140016181Sralph 
140116181Sralph 		/* clobber conversion */
140219933Smckusick 		if( l->in.op != FLD )
140316181Sralph 			l->in.type = p->in.type;
140416181Sralph 		ncopy( p, l );
140516181Sralph 		l->in.op = FREE;
140619933Smckusick 
140716181Sralph 		break;
140816181Sralph 
140924418Smckusick 	case ASSIGN:
141024418Smckusick 		/*
141124418Smckusick 		 * Conversions are equivalent to assignments;
141224418Smckusick 		 * when the two operations are combined,
141324418Smckusick 		 * we can sometimes zap the conversion.
141424418Smckusick 		 */
141524418Smckusick 		r = p->in.right;
141624418Smckusick 		l = p->in.left;
141724418Smckusick 		if ( r->in.op == SCONV &&
141824418Smckusick 		     !mixtypes(l, r) &&
141932922Sdonn 		     l->in.op != FLD &&
142024418Smckusick 		     tlen(l) == tlen(r) ) {
142124418Smckusick 				p->in.right = r->in.left;
142224418Smckusick 				r->in.op = FREE;
142324418Smckusick 			}
142424418Smckusick 		break;
142524418Smckusick 
142632929Sdonn 	case ULE:
142732929Sdonn 	case ULT:
142832929Sdonn 	case UGE:
142932929Sdonn 	case UGT:
143032931Sdonn 		p->in.op -= (UGE-GE);
143132931Sdonn 		if( degenerate(p) )
143232931Sdonn 			break;
143332931Sdonn 		p->in.op += (UGE-GE);
143432931Sdonn 		break;
143532931Sdonn 
143632929Sdonn 	case EQ:
143732929Sdonn 	case NE:
143832929Sdonn 	case LE:
143932929Sdonn 	case LT:
144032929Sdonn 	case GE:
144132929Sdonn 	case GT:
144232938Sdonn 		if( p->in.left->in.op == SCONV &&
144332938Sdonn 		    p->in.right->in.op == SCONV ) {
144432938Sdonn 			l = p->in.left;
144532938Sdonn 			r = p->in.right;
144632938Sdonn 			if( l->in.type == DOUBLE &&
144732938Sdonn 			    l->in.left->in.type == FLOAT &&
144832938Sdonn 			    r->in.left->in.type == FLOAT ) {
144932938Sdonn 				/* nuke the conversions */
145032938Sdonn 				p->in.left = l->in.left;
145132938Sdonn 				p->in.right = r->in.left;
145232938Sdonn 				l->in.op = FREE;
145332938Sdonn 				r->in.op = FREE;
145432938Sdonn 				}
145532938Sdonn 			/* more? */
145632938Sdonn 			}
145732931Sdonn 		(void) degenerate(p);
145832931Sdonn 		break;
145932931Sdonn 
146032931Sdonn 	case DIV:
146132931Sdonn 		if( p->in.right->in.op == ICON &&
146232931Sdonn 		    p->in.right->tn.name[0] == '\0' &&
146332931Sdonn 		    ISUNSIGNED(p->in.right->in.type) &&
146432931Sdonn 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
146532931Sdonn 			/* easy to do here, harder to do in zzzcode() */
146632931Sdonn 			p->in.op = UGE;
146732929Sdonn 			break;
146832931Sdonn 			}
146932931Sdonn 	case MOD:
147032931Sdonn 	case ASG DIV:
147132931Sdonn 	case ASG MOD:
147232931Sdonn 		/*
147332931Sdonn 		 * optimize DIV and MOD
147432931Sdonn 		 *
147532931Sdonn 		 * basically we spot UCHAR and USHORT and try to do them
147632931Sdonn 		 * as signed ints...  apparently div+mul+sub is always
147732931Sdonn 		 * faster than ediv for finding MOD on the VAX, when
147832931Sdonn 		 * full unsigned MOD isn't needed.
147932931Sdonn 		 *
148032931Sdonn 		 * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub
148132931Sdonn 		 * are faster for unsigned dividend and a constant divisor
148232931Sdonn 		 * in the right range (.5 to 1 of dividend's range for the
148332931Sdonn 		 * first, .333+ to .5 for the second).  full unsigned is
148432931Sdonn 		 * already done cmp+sub in the appropriate case; the
148532931Sdonn 		 * other cases are less common and require more ambition.
148632931Sdonn 		 */
148732931Sdonn 		if( degenerate(p) )
148832929Sdonn 			break;
148932931Sdonn 		l = p->in.left;
149032931Sdonn 		r = p->in.right;
149132931Sdonn 		if( !ISUNSIGNED(r->in.type) ||
149232931Sdonn 		    tlen(l) >= SZINT/SZCHAR ||
149332931Sdonn 		    !(tlen(r) < SZINT/SZCHAR ||
149432931Sdonn 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
149532929Sdonn 			break;
149632931Sdonn 		if( r->in.op == ICON )
149732931Sdonn 			r->tn.type = INT;
149832931Sdonn 		else {
149932931Sdonn 			NODE *t = talloc();
150032931Sdonn 			t->in.left = r;
150132931Sdonn 			r = t;
150232931Sdonn 			r->in.op = SCONV;
150332931Sdonn 			r->in.type = INT;
150432931Sdonn 			r->in.right = 0;
150532931Sdonn 			p->in.right = r;
150632931Sdonn 			}
150732931Sdonn 		if( o == DIV || o == MOD ) {
150832931Sdonn 			NODE *t = talloc();
150932931Sdonn 			t->in.left = l;
151032931Sdonn 			l = t;
151132931Sdonn 			l->in.op = SCONV;
151232931Sdonn 			l->in.type = INT;
151332931Sdonn 			l->in.right = 0;
151432931Sdonn 			p->in.left = l;
151532931Sdonn 			}
151632931Sdonn 		/* handle asgops in table */
151732931Sdonn 		break;
151832931Sdonn 
151932931Sdonn 	case RS:
152032931Sdonn 	case ASG RS:
152132931Sdonn 	case LS:
152232931Sdonn 	case ASG LS:
152332931Sdonn 		/* pick up degenerate shifts */
152432931Sdonn 		l = p->in.left;
152532931Sdonn 		r = p->in.right;
152632931Sdonn 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
152732929Sdonn 			break;
152832929Sdonn 		i = r->tn.lval;
152932931Sdonn 		if( i < 0 )
153032931Sdonn 			/* front end 'fixes' this? */
153132931Sdonn 			if( o == LS || o == ASG LS )
153232931Sdonn 				o += (RS-LS);
153332931Sdonn 			else
153432931Sdonn 				o += (LS-RS);
153532931Sdonn 		if( (o == RS || o == ASG RS) &&
153632931Sdonn 		    !ISUNSIGNED(l->in.type) )
153732931Sdonn 			/* can't optimize signed right shifts */
153832929Sdonn 			break;
153932935Sdonn 		if( o == LS ) {
154032935Sdonn 			if( i < SZINT )
154132935Sdonn 				break;
154232935Sdonn 			}
154332935Sdonn 		else {
154432935Sdonn 			if( i < tlen(l) * SZCHAR )
154532935Sdonn 				break;
154632935Sdonn 			}
154732931Sdonn 	zero:
154832931Sdonn 		if( !asgop( o ) )
154932931Sdonn 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
155032931Sdonn 				/* no side effects */
155132932Sdonn 				tfree(l);
155232931Sdonn 				ncopy(p, r);
155332931Sdonn 				r->in.op = FREE;
155432931Sdonn 				p->tn.lval = 0;
155532931Sdonn 				}
155632931Sdonn 			else {
155732931Sdonn 				p->in.op = COMOP;
155832932Sdonn 				r->tn.lval = 0;
155932931Sdonn 				}
156032931Sdonn 		else {
156132931Sdonn 			p->in.op = ASSIGN;
156232931Sdonn 			r->tn.lval = 0;
156332929Sdonn 			}
156432931Sdonn 		break;
156532931Sdonn 		}
156632931Sdonn 	}
156732931Sdonn 
156832931Sdonn degenerate(p) register NODE *p; {
156932931Sdonn 	int o;
157032931Sdonn 	int result, i;
157132931Sdonn 	int lower, upper;
157232931Sdonn 	register NODE *l, *r;
157332931Sdonn 
157432931Sdonn 	/*
157532931Sdonn 	 * try to keep degenerate comparisons with constants
157632931Sdonn 	 * out of the table.
157732931Sdonn 	 */
157832931Sdonn 	r = p->in.right;
157932931Sdonn 	l = p->in.left;
158032931Sdonn 	if( r->in.op != ICON ||
158132931Sdonn 	    r->tn.name[0] != '\0' ||
158232931Sdonn 	    tlen(l) >= tlen(r) )
158332931Sdonn 		return (0);
158432931Sdonn 	switch( l->in.type ) {
158532931Sdonn 	case CHAR:
158632931Sdonn 		lower = -(1 << SZCHAR - 1);
158732931Sdonn 		upper = (1 << SZCHAR - 1) - 1;
158832931Sdonn 		break;
158932931Sdonn 	case UCHAR:
159032931Sdonn 		lower = 0;
159132931Sdonn 		upper = (1 << SZCHAR) - 1;
159232931Sdonn 		break;
159332931Sdonn 	case SHORT:
159432931Sdonn 		lower = -(1 << SZSHORT - 1);
159532931Sdonn 		upper = (1 << SZSHORT - 1) - 1;
159632931Sdonn 		break;
159732931Sdonn 	case USHORT:
159832931Sdonn 		lower = 0;
159932931Sdonn 		upper = (1 << SZSHORT) - 1;
160032931Sdonn 		break;
160132931Sdonn 	default:
160232932Sdonn 		cerror("unsupported type in degenerate()");
160332931Sdonn 		}
160432931Sdonn 	i = r->tn.lval;
160532931Sdonn 	switch( o = p->in.op ) {
160632931Sdonn 	case DIV:
160732931Sdonn 	case ASG DIV:
160832931Sdonn 	case MOD:
160932931Sdonn 	case ASG MOD:
161032931Sdonn 		/* DIV and MOD work like EQ */
161132931Sdonn 	case EQ:
161232931Sdonn 	case NE:
161332931Sdonn 		if( lower == 0 && (unsigned) i > upper )
161432931Sdonn 			result = o == NE;
161532931Sdonn 		else if( i < lower || i > upper )
161632931Sdonn 			result = o == NE;
161732931Sdonn 		else
161832931Sdonn 			return (0);
161932931Sdonn 		break;
162032931Sdonn 	case LT:
162132931Sdonn 	case GE:
162232931Sdonn 		if( lower == 0 && (unsigned) i > upper )
162332931Sdonn 			result = o == LT;
162432931Sdonn 		else if( i <= lower )
162532931Sdonn 			result = o != LT;
162632931Sdonn 		else if( i > upper )
162732931Sdonn 			result = o == LT;
162832931Sdonn 		else
162932931Sdonn 			return (0);
163032931Sdonn 		break;
163132931Sdonn 	case LE:
163232931Sdonn 	case GT:
163332931Sdonn 		if( lower == 0 && (unsigned) i >= upper )
163432931Sdonn 			result = o == LE;
163532931Sdonn 		else if( i < lower )
163632931Sdonn 			result = o != LE;
163732931Sdonn 		else if( i >= upper )
163832931Sdonn 			result = o == LE;
163932931Sdonn 		else
164032931Sdonn 			return (0);
164132931Sdonn 		break;
164232931Sdonn 	default:
164332931Sdonn 		cerror("unknown op in degenerate()");
164432931Sdonn 		}
164532931Sdonn 
164632931Sdonn 	if( o == MOD || o == ASG MOD ) {
164732931Sdonn 		r->in.op = FREE;
164832931Sdonn 		ncopy(p, l);
164932931Sdonn 		l->in.op = FREE;
165032931Sdonn 		}
165132931Sdonn 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
165232931Sdonn 		/* no side effects */
165332932Sdonn 		tfree(l);
165432931Sdonn 		ncopy(p, r);
165532931Sdonn 		r->in.op = FREE;
165632931Sdonn 		p->tn.lval = result;
165732931Sdonn 		}
165832931Sdonn 	else {
165932931Sdonn 		if( o == ASG DIV )
166032931Sdonn 			p->in.op = ASSIGN;
166132929Sdonn 		else {
166232929Sdonn 			p->in.op = COMOP;
166332929Sdonn 			r->tn.type = INT;
166432929Sdonn 			}
166532931Sdonn 		r->tn.lval = result;
16669702Slinton 		}
166732931Sdonn 	if( logop(o) )
166832931Sdonn 		p->in.type = INT;
166932931Sdonn 
167032931Sdonn 	return (1);
16719702Slinton 	}
16729702Slinton 
16739702Slinton /* added by jwf */
16749702Slinton struct functbl {
16759702Slinton 	int fop;
16769702Slinton 	TWORD ftype;
16779702Slinton 	char *func;
16789702Slinton 	} opfunc[] = {
16799702Slinton 	DIV,		TANY,	"udiv",
16809702Slinton 	MOD,		TANY,	"urem",
168117715Sralph 	ASG DIV,	TANY,	"audiv",
168217715Sralph 	ASG MOD,	TANY,	"aurem",
16839702Slinton 	0,	0,	0 };
16849702Slinton 
16859702Slinton hardops(p)  register NODE *p; {
16869702Slinton 	/* change hard to do operators into function calls.  */
16879702Slinton 	register NODE *q;
16889702Slinton 	register struct functbl *f;
16899702Slinton 	register o;
169017742Sralph 	NODE *old,*temp;
16919702Slinton 
16929702Slinton 	o = p->in.op;
169317742Sralph 	if( ! (optype(o)==BITYPE &&
169417742Sralph 	       (ISUNSIGNED(p->in.left->in.type) ||
169517742Sralph 		ISUNSIGNED(p->in.right->in.type))) )
169617742Sralph 		return;
16979702Slinton 
16989702Slinton 	for( f=opfunc; f->fop; f++ ) {
16999702Slinton 		if( o==f->fop ) goto convert;
17009702Slinton 		}
17019702Slinton 	return;
17029702Slinton 
17039702Slinton 	convert:
170432931Sdonn 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
170532928Sdonn 		/* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */
170632928Sdonn 		/* save a subroutine call -- use at most 5 instructions */
170732928Sdonn 		return;
170832931Sdonn 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
170932931Sdonn 		/* optim2() will modify the op into an ordinary int op */
171032931Sdonn 		return;
17119702Slinton 	if( asgop( o ) ) {
171217742Sralph 		old = NIL;
171317715Sralph 		switch( p->in.left->in.op ){
171417742Sralph 		case FLD:
171517742Sralph 			q = p->in.left->in.left;
171617742Sralph 			/*
171717742Sralph 			 * rewrite (lval.fld /= rval); as
171817742Sralph 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
171917742Sralph 			 * else the compiler will evaluate lval twice.
172017742Sralph 			 */
172117742Sralph 			if( q->in.op == UNARY MUL ){
172217742Sralph 				/* first allocate a temp storage */
172317742Sralph 				temp = talloc();
172417742Sralph 				temp->in.op = OREG;
172517742Sralph 				temp->tn.rval = TMPREG;
172617742Sralph 				temp->tn.lval = BITOOR(freetemp(1));
172717742Sralph 				temp->in.type = INCREF(p->in.type);
172817742Sralph #ifdef FLEXNAMES
172917742Sralph 				temp->in.name = "";
173017742Sralph #else
173117742Sralph 				temp->in.name[0] = '\0';
173217742Sralph #endif
173317742Sralph 				old = q->in.left;
173417742Sralph 				q->in.left = temp;
173517742Sralph 			}
173617742Sralph 			/* fall thru ... */
173717742Sralph 
173817715Sralph 		case REG:
173917715Sralph 		case NAME:
174017715Sralph 		case OREG:
174117715Sralph 			/* change ASG OP to a simple OP */
174217715Sralph 			q = talloc();
174317715Sralph 			q->in.op = NOASG p->in.op;
174417715Sralph 			q->in.rall = NOPREF;
174517715Sralph 			q->in.type = p->in.type;
174617715Sralph 			q->in.left = tcopy(p->in.left);
174717715Sralph 			q->in.right = p->in.right;
174817715Sralph 			p->in.op = ASSIGN;
174917715Sralph 			p->in.right = q;
175017715Sralph 			p = q;
175117715Sralph 			f -= 2; /* Note: this depends on the table order */
175217742Sralph 			/* on the right side only - replace *temp with
175317742Sralph 			 *(temp = &lval), build the assignment node */
175417742Sralph 			if( old ){
175517742Sralph 				temp = q->in.left->in.left; /* the "*" node */
175617742Sralph 				q = talloc();
175717742Sralph 				q->in.op = ASSIGN;
175817742Sralph 				q->in.left = temp->in.left;
175917742Sralph 				q->in.right = old;
176017742Sralph 				q->in.type = old->in.type;
176117742Sralph #ifdef FLEXNAMES
176217742Sralph 				q->in.name = "";
176317742Sralph #else
176417742Sralph 				q->in.name[0] = '\0';
176517742Sralph #endif
176617742Sralph 				temp->in.left = q;
176717742Sralph 			}
176817715Sralph 			break;
17699702Slinton 
177017715Sralph 		case UNARY MUL:
177117715Sralph 			/* avoid doing side effects twice */
177217715Sralph 			q = p->in.left;
177317715Sralph 			p->in.left = q->in.left;
177417715Sralph 			q->in.op = FREE;
177517715Sralph 			break;
177617715Sralph 
177717715Sralph 		default:
177817715Sralph 			cerror( "hardops: can't compute & LHS" );
177917715Sralph 			}
178017742Sralph 		}
178117715Sralph 
17829702Slinton 	/* build comma op for args to function */
17839702Slinton 	q = talloc();
17849702Slinton 	q->in.op = CM;
17859702Slinton 	q->in.rall = NOPREF;
17869702Slinton 	q->in.type = INT;
17879702Slinton 	q->in.left = p->in.left;
17889702Slinton 	q->in.right = p->in.right;
17899702Slinton 	p->in.op = CALL;
17909702Slinton 	p->in.right = q;
17919702Slinton 
17929702Slinton 	/* put function name in left node of call */
17939702Slinton 	p->in.left = q = talloc();
17949702Slinton 	q->in.op = ICON;
17959702Slinton 	q->in.rall = NOPREF;
17969702Slinton 	q->in.type = INCREF( FTN + p->in.type );
17979702Slinton #ifndef FLEXNAMES
17989702Slinton 	strcpy( q->in.name, f->func );
17999702Slinton #else
18009702Slinton 	q->in.name = f->func;
18019702Slinton #endif
18029702Slinton 	q->tn.lval = 0;
18039702Slinton 	q->tn.rval = 0;
18049702Slinton 
18059702Slinton 	}
18069702Slinton 
180717742Sralph zappost(p) NODE *p; {
180817742Sralph 	/* look for ++ and -- operators and remove them */
180917742Sralph 
181032935Sdonn 	register int o, ty;
181117742Sralph 	register NODE *q;
181217742Sralph 	o = p->in.op;
181317742Sralph 	ty = optype( o );
181417742Sralph 
181517742Sralph 	switch( o ){
181617742Sralph 
181717742Sralph 	case INCR:
181817742Sralph 	case DECR:
181917742Sralph 			q = p->in.left;
182017742Sralph 			p->in.right->in.op = FREE;  /* zap constant */
182117742Sralph 			ncopy( p, q );
182217742Sralph 			q->in.op = FREE;
182317742Sralph 			return;
182417742Sralph 
182517742Sralph 		}
182617742Sralph 
182717742Sralph 	if( ty == BITYPE ) zappost( p->in.right );
182817742Sralph 	if( ty != LTYPE ) zappost( p->in.left );
182917742Sralph }
183017742Sralph 
183117742Sralph fixpre(p) NODE *p; {
183217742Sralph 
183332935Sdonn 	register int o, ty;
183417742Sralph 	o = p->in.op;
183517742Sralph 	ty = optype( o );
183617742Sralph 
183717742Sralph 	switch( o ){
183817742Sralph 
183917742Sralph 	case ASG PLUS:
184017742Sralph 			p->in.op = PLUS;
184117742Sralph 			break;
184217742Sralph 	case ASG MINUS:
184317742Sralph 			p->in.op = MINUS;
184417742Sralph 			break;
184517742Sralph 		}
184617742Sralph 
184717742Sralph 	if( ty == BITYPE ) fixpre( p->in.right );
184817742Sralph 	if( ty != LTYPE ) fixpre( p->in.left );
184917742Sralph }
185017742Sralph 
185132935Sdonn /*ARGSUSED*/
185232935Sdonn NODE * addroreg(l) NODE *l;
185332935Sdonn 				/* OREG was built in clocal()
185432935Sdonn 				 * for an auto or formal parameter
185532935Sdonn 				 * now its address is being taken
185632935Sdonn 				 * local code must unwind it
185732935Sdonn 				 * back to PLUS/MINUS REG ICON
185832935Sdonn 				 * according to local conventions
185932935Sdonn 				 */
186032935Sdonn {
186132935Sdonn 	cerror("address of OREG taken");
186232935Sdonn 	/*NOTREACHED*/
186332935Sdonn }
186432935Sdonn 
186532935Sdonn 
186632935Sdonn 
186732935Sdonn # ifndef ONEPASS
186832935Sdonn main( argc, argv ) char *argv[]; {
186932935Sdonn 	return( mainp2( argc, argv ) );
187032935Sdonn 	}
187132935Sdonn # endif
187232935Sdonn 
187324418Smckusick strip(p) register NODE *p; {
187424418Smckusick 	NODE *q;
187524418Smckusick 
187624418Smckusick 	/* strip nodes off the top when no side effects occur */
187724418Smckusick 	for( ; ; ) {
187824418Smckusick 		switch( p->in.op ) {
187924418Smckusick 		case SCONV:			/* remove lint tidbits */
188024418Smckusick 			q = p->in.left;
188124418Smckusick 			ncopy( p, q );
188224418Smckusick 			q->in.op = FREE;
188324418Smckusick 			break;
188424418Smckusick 		/* could probably add a few more here */
188524418Smckusick 		default:
188624418Smckusick 			return;
188724418Smckusick 			}
188824418Smckusick 		}
188924418Smckusick 	}
189024418Smckusick 
18919702Slinton myreader(p) register NODE *p; {
189224418Smckusick 	strip( p );		/* strip off operations with no side effects */
189317742Sralph 	canon( p );		/* expands r-vals for fields */
18949702Slinton 	walkf( p, hardops );	/* convert ops to function calls */
18959702Slinton 	walkf( p, optim2 );
18969702Slinton 	}
1897