xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32929)
117742Sralph # ifndef lint
2*32929Sdonn static char *sccsid ="@(#)local2.c	1.23 (Berkeley) 12/11/87";
317742Sralph # endif
417742Sralph 
518556Sralph # include "pass2.h"
69702Slinton # include "ctype.h"
79702Slinton # ifdef FORT
89702Slinton int ftlab1, ftlab2;
99702Slinton # endif
109702Slinton /* a lot of the machine dependent parts of the second pass */
119702Slinton 
1224418Smckusick # define putstr(s)	fputs((s), stdout)
1324418Smckusick 
149702Slinton # define BITMASK(n) ((1L<<n)-1)
159702Slinton 
1632924Sdonn /*ARGSUSED*/
179702Slinton where(c){
189702Slinton 	fprintf( stderr, "%s, line %d: ", filename, lineno );
199702Slinton 	}
209702Slinton 
219702Slinton lineid( l, fn ) char *fn; {
229702Slinton 	/* identify line l and file fn */
239702Slinton 	printf( "#	line %d, file %s\n", l, fn );
249702Slinton 	}
259702Slinton 
269702Slinton 
279702Slinton eobl2(){
289702Slinton 	OFFSZ spoff;	/* offset from stack pointer */
299702Slinton #ifdef FORT
309702Slinton 	spoff = maxoff;
319702Slinton 	if( spoff >= AUTOINIT ) spoff -= AUTOINIT;
329702Slinton 	spoff /= SZCHAR;
339702Slinton 	SETOFF(spoff,4);
349702Slinton #ifndef FLEXNAMES
359702Slinton 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
369702Slinton #else
379702Slinton 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
389702Slinton 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
399702Slinton #endif
409702Slinton #else
419702Slinton 	extern int ftlab1, ftlab2;
429702Slinton 
439702Slinton 	spoff = maxoff;
449702Slinton 	if( spoff >= AUTOINIT ) spoff -= AUTOINIT;
459702Slinton 	spoff /= SZCHAR;
469702Slinton 	SETOFF(spoff,4);
479702Slinton 	printf( "L%d:\n", ftlab1);
489702Slinton 	if( spoff!=0 )
499702Slinton 		if( spoff < 64 )
509702Slinton 			printf( "	subl2	$%ld,sp\n", spoff);
519702Slinton 		else
529702Slinton 			printf( "	movab	-%ld(sp),sp\n", spoff);
539702Slinton 	printf( "	jbr 	L%d\n", ftlab2);
549702Slinton #endif
559702Slinton 	maxargs = -1;
569702Slinton 	}
579702Slinton 
589702Slinton struct hoptab { int opmask; char * opstring; } ioptab[] = {
599702Slinton 
609702Slinton 	ASG PLUS, "add",
619702Slinton 	ASG MINUS, "sub",
629702Slinton 	ASG MUL, "mul",
639702Slinton 	ASG DIV, "div",
649702Slinton 	ASG OR, "bis",
659702Slinton 	ASG ER,	"xor",
669702Slinton 	ASG AND, "bic",
679702Slinton 	PLUS,	"add",
689702Slinton 	MINUS,	"sub",
699702Slinton 	MUL,	"mul",
709702Slinton 	DIV,	"div",
719702Slinton 	OR,	"bis",
729702Slinton 	ER,	"xor",
739702Slinton 	AND,	"bic",
749702Slinton 	-1, ""    };
759702Slinton 
769702Slinton hopcode( f, o ){
779702Slinton 	/* output the appropriate string from the above table */
789702Slinton 
799702Slinton 	register struct hoptab *q;
809702Slinton 
819702Slinton 	for( q = ioptab;  q->opmask>=0; ++q ){
829702Slinton 		if( q->opmask == o ){
8324418Smckusick 			putstr( q->opstring );
849702Slinton /* tbl
8524418Smckusick 			if( f == 'F' ) putchar( 'e' );
8624418Smckusick 			else if( f == 'D' ) putchar( 'd' );
879702Slinton    tbl */
889702Slinton /* tbl */
899702Slinton 			switch( f ) {
909702Slinton 				case 'L':
919702Slinton 				case 'W':
929702Slinton 				case 'B':
939702Slinton 				case 'D':
949702Slinton 				case 'F':
9524418Smckusick 					putchar(tolower(f));
969702Slinton 					break;
979702Slinton 
989702Slinton 				}
999702Slinton /* tbl */
1009702Slinton 			return;
1019702Slinton 			}
1029702Slinton 		}
1039702Slinton 	cerror( "no hoptab for %s", opst[o] );
1049702Slinton 	}
1059702Slinton 
1069702Slinton char *
1079702Slinton rnames[] = {  /* keyed to register number tokens */
1089702Slinton 
1099702Slinton 	"r0", "r1",
1109702Slinton 	"r2", "r3", "r4", "r5",
1119702Slinton 	"r6", "r7", "r8", "r9", "r10", "r11",
1129702Slinton 	"ap", "fp", "sp", "pc",
1139702Slinton 
1149702Slinton 	};
1159702Slinton 
1169702Slinton int rstatus[] = {
1179702Slinton 	SAREG|STAREG, SAREG|STAREG,
1189702Slinton 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
1199702Slinton 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
1209702Slinton 	SAREG, SAREG, SAREG, SAREG,
1219702Slinton 
1229702Slinton 	};
1239702Slinton 
1249702Slinton tlen(p) NODE *p;
1259702Slinton {
1269702Slinton 	switch(p->in.type) {
1279702Slinton 		case CHAR:
1289702Slinton 		case UCHAR:
1299702Slinton 			return(1);
1309702Slinton 
1319702Slinton 		case SHORT:
1329702Slinton 		case USHORT:
1339702Slinton 			return(2);
1349702Slinton 
1359702Slinton 		case DOUBLE:
1369702Slinton 			return(8);
1379702Slinton 
1389702Slinton 		default:
1399702Slinton 			return(4);
1409702Slinton 		}
1419702Slinton }
1429702Slinton 
1439702Slinton mixtypes(p, q) NODE *p, *q;
1449702Slinton {
14516181Sralph 	register TWORD tp, tq;
1469702Slinton 
1479702Slinton 	tp = p->in.type;
1489702Slinton 	tq = q->in.type;
1499702Slinton 
1509702Slinton 	return( (tp==FLOAT || tp==DOUBLE) !=
1519702Slinton 		(tq==FLOAT || tq==DOUBLE) );
1529702Slinton }
1539702Slinton 
1549702Slinton prtype(n) NODE *n;
1559702Slinton {
1569702Slinton 	switch (n->in.type)
1579702Slinton 		{
1589702Slinton 		case DOUBLE:
15924418Smckusick 			putchar('d');
1609702Slinton 			return;
1619702Slinton 
1629702Slinton 		case FLOAT:
16324418Smckusick 			putchar('f');
1649702Slinton 			return;
1659702Slinton 
1669702Slinton 		case LONG:
1679702Slinton 		case ULONG:
1689702Slinton 		case INT:
1699702Slinton 		case UNSIGNED:
17024418Smckusick 			putchar('l');
1719702Slinton 			return;
1729702Slinton 
1739702Slinton 		case SHORT:
1749702Slinton 		case USHORT:
17524418Smckusick 			putchar('w');
1769702Slinton 			return;
1779702Slinton 
1789702Slinton 		case CHAR:
1799702Slinton 		case UCHAR:
18024418Smckusick 			putchar('b');
1819702Slinton 			return;
1829702Slinton 
1839702Slinton 		default:
1849702Slinton 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
1859702Slinton 			else {
18624418Smckusick 				putchar('l');
1879702Slinton 				return;
1889702Slinton 				}
1899702Slinton 		}
1909702Slinton }
1919702Slinton 
1929702Slinton zzzcode( p, c ) register NODE *p; {
1939702Slinton 	register m;
19432924Sdonn 	int val;
1959702Slinton 	switch( c ){
1969702Slinton 
1979702Slinton 	case 'N':  /* logical ops, turned into 0-1 */
1989702Slinton 		/* use register given by register 1 */
1999702Slinton 		cbgen( 0, m=getlab(), 'I' );
2009702Slinton 		deflab( p->bn.label );
2019702Slinton 		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->tn.rval] );
2029702Slinton 		deflab( m );
2039702Slinton 		return;
2049702Slinton 
2059702Slinton 	case 'I':
2069702Slinton 	case 'P':
2079702Slinton 		cbgen( p->in.op, p->bn.label, c );
2089702Slinton 		return;
2099702Slinton 
2109702Slinton 	case 'A':
2119702Slinton 		{
2129702Slinton 		register NODE *l, *r;
2139702Slinton 
2149702Slinton 		if (xdebug) eprint(p, 0, &val, &val);
2159702Slinton 		r = getlr(p, 'R');
21616181Sralph 		if (p->in.op == ASSIGN)
21716181Sralph 			l = getlr(p, 'L');
21817208Sralph 		else if (p->in.op == SCONV) {
2199702Slinton 			l = resc;
22017742Sralph #if defined(FORT) || defined(SPRECC)
22116181Sralph 			l->in.type = r->in.type;
22216181Sralph #else
22316181Sralph 			l->in.type = r->in.type==FLOAT ? DOUBLE : r->in.type;
22416181Sralph #endif
22516181Sralph 			r = getlr(p, 'L');
22616181Sralph 			}
22717208Sralph 		else {		/* OPLTYPE */
22816181Sralph 			l = resc;
22917742Sralph #if defined(FORT) || defined(SPRECC)
23016181Sralph 			l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT);
23116181Sralph #else
2329702Slinton 			l->in.type = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT);
23316181Sralph #endif
2349702Slinton 			}
2359702Slinton 		if (r->in.op == ICON)
23617208Sralph 			if (r->in.name[0] == '\0') {
23717208Sralph 				if (r->tn.lval == 0) {
23824418Smckusick 					putstr("clr");
2399702Slinton 					prtype(l);
24024418Smckusick 					putchar('\t');
2419702Slinton 					adrput(l);
2429702Slinton 					return;
2439702Slinton 					}
24417208Sralph 				if (r->tn.lval < 0 && r->tn.lval >= -63) {
24524418Smckusick 					putstr("mneg");
2469702Slinton 					prtype(l);
2479702Slinton 					r->tn.lval = -r->tn.lval;
2489702Slinton 					goto ops;
2499702Slinton 					}
25017208Sralph 				if (r->tn.lval < 0)
25117208Sralph 					r->in.type = r->tn.lval >= -128 ? CHAR
2529702Slinton 						: (r->tn.lval >= -32768 ? SHORT
25317208Sralph 						: INT);
25417208Sralph 				else if (l->in.type == FLOAT ||
25517208Sralph 				    l->in.type == DOUBLE)
25617208Sralph 					r->in.type = r->tn.lval <= 63 ? INT
25717208Sralph 						: (r->tn.lval <= 127 ? CHAR
25817208Sralph 						: (r->tn.lval <= 32767 ? SHORT
25917208Sralph 						: INT));
26017208Sralph 				else
26117208Sralph 					r->in.type = r->tn.lval <= 63 ? INT
26217208Sralph 						: (r->tn.lval <= 127 ? CHAR
2639702Slinton 						: (r->tn.lval <= 255 ? UCHAR
2649702Slinton 						: (r->tn.lval <= 32767 ? SHORT
2659702Slinton 						: (r->tn.lval <= 65535 ? USHORT
26617208Sralph 						: INT))));
2679702Slinton 				}
26817208Sralph 			else {
26924418Smckusick 				putstr("moval");
27024418Smckusick 				putchar('\t');
27116181Sralph 				acon(r);
27224418Smckusick 				putchar(',');
27316181Sralph 				adrput(l);
27416181Sralph 				return;
27516181Sralph 				}
2769702Slinton 
27723536Sbloom 		if (p->in.op == SCONV &&
27823536Sbloom 		    !(l->in.type == FLOAT || l->in.type == DOUBLE) &&
27923536Sbloom 		    !mixtypes(l, r)) {
28023536Sbloom 			/*
28123536Sbloom 			 * Because registers must always contain objects
28223536Sbloom 			 * of the same width as INTs, we may have to
28323536Sbloom 			 * perform two conversions to get an INT.  Can
28423536Sbloom 			 * the conversions be collapsed into one?
28523536Sbloom 			 */
28623536Sbloom 			if (m = collapsible(l, r))
28723536Sbloom 				r->in.type = m;
28823536Sbloom 			else {
28923536Sbloom 				/*
29023536Sbloom 				 * Two steps are required.
29123536Sbloom 				 */
29223536Sbloom 				NODE *x = &resc[1];
29323536Sbloom 
29423536Sbloom 				*x = *l;
29523536Sbloom 				if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type))
29624418Smckusick 					putstr("movz");
2979702Slinton 				else
29824418Smckusick 					putstr("cvt");
29923536Sbloom 				prtype(r);
30023536Sbloom 				prtype(x);
30124418Smckusick 				putchar('\t');
30223536Sbloom 				adrput(r);
30324418Smckusick 				putchar(',');
30423536Sbloom 				adrput(x);
30524418Smckusick 				putchar('\n');
30624418Smckusick 				putchar('\t');
30723536Sbloom 				r = x;
3089702Slinton 				}
30923536Sbloom 			l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT);
3109702Slinton 			}
31123536Sbloom 
31225751Sdonn 		if ((r->in.type == UNSIGNED || r->in.type == ULONG) &&
31325751Sdonn 		    mixtypes(l, r)) {
31425751Sdonn 			int label1, label2;
31525751Sdonn 
31625751Sdonn 			label1 = getlab();
31725751Sdonn 			label2 = getlab();
31825751Sdonn 
31925751Sdonn 			putstr("movl\t");
32025751Sdonn 			adrput(r);
32125751Sdonn 			putchar(',');
32225751Sdonn 			adrput(l);
32327269Sdonn 			putstr("\n\tjbsc\t$31,");
32425751Sdonn 			adrput(l);
32525751Sdonn 			printf(",L%d\n\tcvtl", label1);
32625751Sdonn 			prtype(l);
32725751Sdonn 			putchar('\t');
32825751Sdonn 			adrput(l);
32925751Sdonn 			putchar(',');
33025751Sdonn 			adrput(l);
33125751Sdonn 			printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1);
33225751Sdonn 			prtype(l);
33325751Sdonn 			putchar('\t');
33425751Sdonn 			adrput(l);
33525751Sdonn 			putchar(',');
33625751Sdonn 			adrput(l);
33725751Sdonn 			putstr("\n\tadd");
33825751Sdonn 			prtype(l);
33925751Sdonn 			putstr("2\t$0");
34025751Sdonn 			prtype(l);
34125751Sdonn 			putstr("2.147483648e9,");
34225751Sdonn 			adrput(l);
34325751Sdonn 			printf("\nL%d:", label2);
34425751Sdonn 
34525751Sdonn 			return;
34625751Sdonn 			}
34725751Sdonn 
34817208Sralph 		if (!mixtypes(l,r)) {
34917208Sralph 			if (tlen(l) == tlen(r)) {
35024418Smckusick 				putstr("mov");
35117742Sralph #ifdef FORT
35217742Sralph 				if (Oflag)
35317742Sralph 					prtype(l);
35417742Sralph 				else {
35517742Sralph 					if (l->in.type == DOUBLE)
35624418Smckusick 						putchar('q');
35717742Sralph 					else if(l->in.type == FLOAT)
35824418Smckusick 						putchar('l');
35917742Sralph 					else
36017742Sralph 						prtype(l);
36117742Sralph 					}
36217742Sralph #else
3639702Slinton 				prtype(l);
36417742Sralph #endif FORT
3659702Slinton 				goto ops;
3669702Slinton 				}
3679702Slinton 			else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
36824418Smckusick 				putstr("movz");
3699702Slinton 			else
37024418Smckusick 				putstr("cvt");
3719702Slinton 			}
3729702Slinton 		else
37324418Smckusick 			putstr("cvt");
3749702Slinton 		prtype(r);
3759702Slinton 		prtype(l);
3769702Slinton 	ops:
37724418Smckusick 		putchar('\t');
3789702Slinton 		adrput(r);
37924418Smckusick 		putchar(',');
3809702Slinton 		adrput(l);
3819702Slinton 		return;
3829702Slinton 		}
3839702Slinton 
38425751Sdonn 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
38525751Sdonn 		{
38625751Sdonn 		register NODE *l, *r, *s;
38725751Sdonn 		int rt;
38825751Sdonn 
38925751Sdonn 		l = p->in.left;
39025751Sdonn 		r = p->in.right;
39125751Sdonn 		s = talloc();
39225751Sdonn 		rt = r->in.type;
39325751Sdonn 
39425751Sdonn 		s->in.op = SCONV;
39525751Sdonn 		s->in.left = l;
39625751Sdonn 		s->in.type = rt;
39725751Sdonn 		zzzcode(s, 'A');
39825751Sdonn 		putstr("\n\t");
39925751Sdonn 
40025751Sdonn 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
40125751Sdonn 		putstr("2\t");
40225751Sdonn 		adrput(r);
40325751Sdonn 		putchar(',');
40425751Sdonn 		adrput(resc);
40525751Sdonn 		putstr("\n\t");
40625751Sdonn 
40725751Sdonn 		s->in.op = ASSIGN;
40825751Sdonn 		s->in.left = l;
40925751Sdonn 		s->in.right = resc;
41025751Sdonn 		s->in.type = l->in.type;
41125751Sdonn 		zzzcode(s, 'A');
41225751Sdonn 
41325751Sdonn 		s->in.op = FREE;
41425751Sdonn 		return;
41525751Sdonn 		}
41625751Sdonn 
41732928Sdonn 	case 'J':	/* unsigned DIV/MOD with constant divisors */
41832928Sdonn 		{
41932928Sdonn 		register int ck = INAREG;
42032928Sdonn 		int label1, label2;
42132928Sdonn 
42232928Sdonn 		/* case constant <= 1 is handled by optim() in pass 1 */
42332928Sdonn 		/* case constant < 0x80000000 is handled in table */
42432928Sdonn 		switch( p->in.op ) {
42532928Sdonn 		/* case DIV: handled in hardops() */
42632928Sdonn 		case MOD:
42732928Sdonn 			if( p->in.left->in.op == REG &&
42832928Sdonn 			    p->in.left->tn.rval == resc->tn.rval )
42932928Sdonn 				goto asgmod;
43032928Sdonn 			label1 = getlab();
43132928Sdonn 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
43232928Sdonn 			printf("\tjlssu\tL%d\n", label1);
43332928Sdonn 			expand(p, ck, "\tsubl2\tAR,A1\n");
43432928Sdonn 			printf("L%d:", label1);
43532928Sdonn 			break;
43632928Sdonn 		case ASG DIV:
43732928Sdonn 			label1 = getlab();
43832928Sdonn 			label2 = getlab();
43932928Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
44032928Sdonn 			printf("\tjgequ\tL%d\n", label1);
44132928Sdonn 			expand(p, ck, "\tmovl\t$1,AL\n");
44232928Sdonn 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
44332928Sdonn 			expand(p, ck, "\tclrl\tAL\n");
44432928Sdonn 			printf("L%d:", label2);
44532928Sdonn 			break;
44632928Sdonn 		case ASG MOD:
44732928Sdonn 		asgmod:
44832928Sdonn 			label1 = getlab();
44932928Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
45032928Sdonn 			printf("\tjlssu\tL%d\n", label1);
45132928Sdonn 			expand(p, ck, "\tsubl2\tAR,AL\n");
45232928Sdonn 			printf("L%d:", label1);
45332928Sdonn 			break;
45432928Sdonn 			}
45532928Sdonn 		return;
45632928Sdonn 		}
45732928Sdonn 
4589702Slinton 	case 'B':	/* get oreg value in temp register for left shift */
4599702Slinton 		{
4609702Slinton 		register NODE *r;
4619702Slinton 		if (xdebug) eprint(p, 0, &val, &val);
4629702Slinton 		r = p->in.right;
4639702Slinton 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
46424418Smckusick 			putstr("movl");
4659702Slinton 		else {
46624418Smckusick 			putstr("cvt");
4679702Slinton 			prtype(r);
46824418Smckusick 			putchar('l');
4699702Slinton 			}
4709702Slinton 		return;
4719702Slinton 		}
4729702Slinton 
4739702Slinton 	case 'C':	/* num words pushed on arg stack */
4749702Slinton 		{
4759702Slinton 		extern int gc_numbytes;
4769702Slinton 		extern int xdebug;
4779702Slinton 
4789702Slinton 		if (xdebug) printf("->%d<-",gc_numbytes);
4799702Slinton 
4809702Slinton 		printf("$%d", gc_numbytes/(SZLONG/SZCHAR) );
4819702Slinton 		return;
4829702Slinton 		}
4839702Slinton 
4849702Slinton 	case 'D':	/* INCR and DECR */
4859702Slinton 		zzzcode(p->in.left, 'A');
48624418Smckusick 		putchar('\n');
48724418Smckusick 		putchar('\t');
4889702Slinton 
4899702Slinton 	case 'E':	/* INCR and DECR, FOREFF */
4909702Slinton 		if (p->in.right->tn.lval == 1)
4919702Slinton 			{
49224418Smckusick 			putstr( p->in.op == INCR ? "inc" : "dec" );
4939702Slinton 			prtype(p->in.left);
49424418Smckusick 			putchar('\t');
4959702Slinton 			adrput(p->in.left);
4969702Slinton 			return;
4979702Slinton 			}
49824418Smckusick 		putstr( p->in.op == INCR ? "add" : "sub" );
4999702Slinton 		prtype(p->in.left);
50024418Smckusick 		putchar('2');
50124418Smckusick 		putchar('\t');
5029702Slinton 		adrput(p->in.right);
50324418Smckusick 		putchar(',');
5049702Slinton 		adrput(p->in.left);
5059702Slinton 		return;
5069702Slinton 
5079702Slinton 	case 'F':	/* register type of right operand */
5089702Slinton 		{
5099702Slinton 		register NODE *n;
5109702Slinton 		extern int xdebug;
5119702Slinton 		register int ty;
5129702Slinton 
5139702Slinton 		n = getlr( p, 'R' );
5149702Slinton 		ty = n->in.type;
5159702Slinton 
5169702Slinton 		if (xdebug) printf("->%d<-", ty);
5179702Slinton 
51824418Smckusick 		if ( ty==DOUBLE) putchar('d');
51924418Smckusick 		else if ( ty==FLOAT ) putchar('f');
52024418Smckusick 		else putchar('l');
5219702Slinton 		return;
5229702Slinton 		}
5239702Slinton 
5249702Slinton 	case 'L':	/* type of left operand */
5259702Slinton 	case 'R':	/* type of right operand */
5269702Slinton 		{
5279702Slinton 		register NODE *n;
5289702Slinton 		extern int xdebug;
5299702Slinton 
53016181Sralph 		n = getlr( p, c );
5319702Slinton 		if (xdebug) printf("->%d<-", n->in.type);
5329702Slinton 
5339702Slinton 		prtype(n);
5349702Slinton 		return;
5359702Slinton 		}
5369702Slinton 
5379702Slinton 	case 'Z':	/* complement mask for bit instr */
5389702Slinton 		printf("$%ld", ~p->in.right->tn.lval);
5399702Slinton 		return;
5409702Slinton 
5419702Slinton 	case 'U':	/* 32 - n, for unsigned right shifts */
5429702Slinton 		printf("$%d", 32 - p->in.right->tn.lval );
5439702Slinton 		return;
5449702Slinton 
5459702Slinton 	case 'T':	/* rounded structure length for arguments */
5469702Slinton 		{
5479702Slinton 		int size;
5489702Slinton 
5499702Slinton 		size = p->stn.stsize;
5509702Slinton 		SETOFF( size, 4);
5519702Slinton 		printf("$%d", size);
5529702Slinton 		return;
5539702Slinton 		}
5549702Slinton 
5559702Slinton 	case 'S':  /* structure assignment */
5569702Slinton 		{
5579702Slinton 			register NODE *l, *r;
5589702Slinton 			register size;
5599702Slinton 
5609702Slinton 			if( p->in.op == STASG ){
5619702Slinton 				l = p->in.left;
5629702Slinton 				r = p->in.right;
5639702Slinton 
5649702Slinton 				}
5659702Slinton 			else if( p->in.op == STARG ){  /* store an arg into a temporary */
5669702Slinton 				r = p->in.left;
5679702Slinton 				}
5689702Slinton 			else cerror( "STASG bad" );
5699702Slinton 
5709702Slinton 			if( r->in.op == ICON ) r->in.op = NAME;
5719702Slinton 			else if( r->in.op == REG ) r->in.op = OREG;
5729702Slinton 			else if( r->in.op != OREG ) cerror( "STASG-r" );
5739702Slinton 
5749702Slinton 			size = p->stn.stsize;
5759702Slinton 
5769702Slinton 			if( size <= 0 || size > 65535 )
5779702Slinton 				cerror("structure size <0=0 or >65535");
5789702Slinton 
5799702Slinton 			switch(size) {
5809702Slinton 				case 1:
58124418Smckusick 					putstr("	movb	");
5829702Slinton 					break;
5839702Slinton 				case 2:
58424418Smckusick 					putstr("	movw	");
5859702Slinton 					break;
5869702Slinton 				case 4:
58724418Smckusick 					putstr("	movl	");
5889702Slinton 					break;
5899702Slinton 				case 8:
59024418Smckusick 					putstr("	movq	");
5919702Slinton 					break;
5929702Slinton 				default:
5939702Slinton 					printf("	movc3	$%d,", size);
5949702Slinton 					break;
5959702Slinton 			}
5969702Slinton 			adrput(r);
59716418Sralph 			if( p->in.op == STASG ){
59824418Smckusick 				putchar(',');
59916418Sralph 				adrput(l);
60024418Smckusick 				putchar('\n');
60116418Sralph 				}
60216418Sralph 			else
60324418Smckusick 				putstr(",(sp)\n");
6049702Slinton 
6059702Slinton 			if( r->in.op == NAME ) r->in.op = ICON;
6069702Slinton 			else if( r->in.op == OREG ) r->in.op = REG;
6079702Slinton 
6089702Slinton 			}
6099702Slinton 		break;
6109702Slinton 
6119702Slinton 	default:
6129702Slinton 		cerror( "illegal zzzcode" );
6139702Slinton 		}
6149702Slinton 	}
6159702Slinton 
61623536Sbloom /*
61723536Sbloom  * collapsible(dest, src) -- if a conversion with a register destination
61823536Sbloom  *	can be accomplished in one instruction, return the type of src
61923536Sbloom  *	that will do the job correctly; otherwise return 0.  Note that
62023536Sbloom  *	a register must always end up having type INT or UNSIGNED.
62123536Sbloom  */
62223536Sbloom int
62323536Sbloom collapsible(dest, src)
62423536Sbloom NODE *dest, *src;
62523536Sbloom {
62623536Sbloom 	int st = src->in.type;
62723536Sbloom 	int dt = dest->in.type;
62823536Sbloom 	int newt = 0;
62923536Sbloom 
63023536Sbloom 	/*
63123536Sbloom 	 * Are there side effects of evaluating src?
63223536Sbloom 	 * If the derived type will not be the same size as src,
63324418Smckusick 	 * we may have to use two steps.
63423536Sbloom 	 */
63524418Smckusick 	if (tlen(src) > tlen(dest)) {
63624418Smckusick 		if (tshape(src, STARREG))
63724418Smckusick 			return (0);
63824418Smckusick 		if (src->in.op == OREG && R2TEST(src->tn.rval))
63924418Smckusick 			return (0);
64024418Smckusick 		}
64123536Sbloom 
64223536Sbloom 	/*
64323536Sbloom 	 * Can we get an object of dest's type by punning src?
64423536Sbloom 	 * Praises be to great Cthulhu for little-endian machines...
64523536Sbloom 	 */
64623536Sbloom 	if (st == CHAR && dt == USHORT)
64723536Sbloom 		/*
64823536Sbloom 		 * Special case -- we must sign-extend to 16 bits.
64923536Sbloom 		 */
65023536Sbloom 		return (0);
65123536Sbloom 
65223536Sbloom 	if (tlen(src) < tlen(dest))
65323536Sbloom 		newt = st;
65423536Sbloom 	else
65523536Sbloom 		newt = dt;
65623536Sbloom 
65723536Sbloom 	return (newt);
65823536Sbloom 	}
65923536Sbloom 
66017742Sralph rmove( rt, rs, t ) TWORD t; {
6619702Slinton 	printf( "	%s	%s,%s\n",
66217742Sralph #ifdef FORT
66317742Sralph 		!Oflag ? (t==DOUBLE ? "movq" : "movl") :
66417742Sralph #endif
6659702Slinton 		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
6669702Slinton 		rnames[rs], rnames[rt] );
6679702Slinton 	}
6689702Slinton 
6699702Slinton struct respref
6709702Slinton respref[] = {
6719702Slinton 	INTAREG|INTBREG,	INTAREG|INTBREG,
6729702Slinton 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
6739702Slinton 	INTEMP,	INTEMP,
6749702Slinton 	FORARG,	FORARG,
6759702Slinton 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
6769702Slinton 	0,	0 };
6779702Slinton 
6789702Slinton setregs(){ /* set up temporary registers */
6799702Slinton 	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
6809702Slinton 	;
6819702Slinton 	}
6829702Slinton 
68332924Sdonn /*ARGSUSED*/
6849702Slinton rewfld( p ) NODE *p; {
6859702Slinton 	return(1);
6869702Slinton 	}
6879702Slinton 
68832924Sdonn /*ARGSUSED*/
6899702Slinton callreg(p) NODE *p; {
6909702Slinton 	return( R0 );
6919702Slinton 	}
6929702Slinton 
6939702Slinton base( p ) register NODE *p; {
6949702Slinton 	register int o = p->in.op;
6959702Slinton 
6969702Slinton 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
6979702Slinton 	if( o==REG ) return( p->tn.rval );
6989702Slinton     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
6999702Slinton 		return( p->in.left->tn.rval );
7009702Slinton     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
7019702Slinton 		return( p->tn.rval + 0200*1 );
7029702Slinton 	if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 );
7039702Slinton 	if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 );
7049702Slinton 	if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG
7059702Slinton 	  && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
7069702Slinton 		return( p->in.left->in.left->tn.rval + 0200*(1+2) );
7079702Slinton 	return( -1 );
7089702Slinton 	}
7099702Slinton 
7109702Slinton offset( p, tyl ) register NODE *p; int tyl; {
7119702Slinton 
71224418Smckusick 	if( tyl==1 &&
71324418Smckusick 	    p->in.op==REG &&
71424418Smckusick 	    (p->in.type==INT || p->in.type==UNSIGNED) )
71524418Smckusick 		return( p->tn.rval );
71624418Smckusick 	if( p->in.op==LS &&
71724418Smckusick 	    p->in.left->in.op==REG &&
71824418Smckusick 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
71924418Smckusick 	    p->in.right->in.op==ICON &&
72024418Smckusick 	    p->in.right->in.name[0]=='\0' &&
72124418Smckusick 	    (1<<p->in.right->tn.lval)==tyl)
7229702Slinton 		return( p->in.left->tn.rval );
72324418Smckusick 	if( tyl==2 &&
72424418Smckusick 	    p->in.op==PLUS &&
72524418Smckusick 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
72624418Smckusick 	    p->in.left->in.op==REG &&
72724418Smckusick 	    p->in.right->in.op==REG &&
72824418Smckusick 	    p->in.left->tn.rval==p->in.right->tn.rval )
72924418Smckusick 		return( p->in.left->tn.rval );
7309702Slinton 	return( -1 );
7319702Slinton 	}
7329702Slinton 
7339702Slinton makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
7349702Slinton 	register NODE *t;
7359702Slinton 	NODE *f;
7369702Slinton 
7379702Slinton 	p->in.op = OREG;
7389702Slinton 	f = p->in.left; 	/* have to free this subtree later */
7399702Slinton 
7409702Slinton 	/* init base */
7419702Slinton 	switch (q->in.op) {
7429702Slinton 		case ICON:
7439702Slinton 		case REG:
7449702Slinton 		case OREG:
7459702Slinton 			t = q;
7469702Slinton 			break;
7479702Slinton 
7489702Slinton 		case MINUS:
7499702Slinton 			q->in.right->tn.lval = -q->in.right->tn.lval;
7509702Slinton 		case PLUS:
7519702Slinton 			t = q->in.right;
7529702Slinton 			break;
7539702Slinton 
7549702Slinton 		case INCR:
7559702Slinton 		case ASG MINUS:
7569702Slinton 			t = q->in.left;
7579702Slinton 			break;
7589702Slinton 
7599702Slinton 		case UNARY MUL:
7609702Slinton 			t = q->in.left->in.left;
7619702Slinton 			break;
7629702Slinton 
7639702Slinton 		default:
7649702Slinton 			cerror("illegal makeor2");
7659702Slinton 	}
7669702Slinton 
7679702Slinton 	p->tn.lval = t->tn.lval;
7689702Slinton #ifndef FLEXNAMES
76932924Sdonn 	{
77032924Sdonn 		register int i;
77132924Sdonn 		for(i=0; i<NCHNAM; ++i)
77232924Sdonn 			p->in.name[i] = t->in.name[i];
77332924Sdonn 	}
7749702Slinton #else
7759702Slinton 	p->in.name = t->in.name;
7769702Slinton #endif
7779702Slinton 
7789702Slinton 	/* init offset */
7799702Slinton 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
7809702Slinton 
7819702Slinton 	tfree(f);
7829702Slinton 	return;
7839702Slinton 	}
7849702Slinton 
7859702Slinton canaddr( p ) NODE *p; {
7869702Slinton 	register int o = p->in.op;
7879702Slinton 
7889702Slinton 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
7899702Slinton 	return(0);
7909702Slinton 	}
7919702Slinton 
7929702Slinton flshape( p ) register NODE *p; {
7939702Slinton 	return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON ||
7949702Slinton 		(p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
7959702Slinton 	}
7969702Slinton 
79732926Sdonn /* INTEMP shapes must not contain any temporary registers */
7989702Slinton shtemp( p ) register NODE *p; {
79932926Sdonn 	int r;
80032926Sdonn 
8019702Slinton 	if( p->in.op == STARG ) p = p->in.left;
80232926Sdonn 
80332926Sdonn 	switch (p->in.op) {
80432926Sdonn 	case REG:
80532926Sdonn 		return( !istreg(p->tn.rval) );
80632926Sdonn 	case OREG:
80732926Sdonn 		r = p->tn.rval;
80832926Sdonn 		if( R2TEST(r) ) {
80932926Sdonn 			if( istreg(R2UPK1(r)) )
81032926Sdonn 				return(0);
81132926Sdonn 			r = R2UPK2(r);
81232926Sdonn 			}
81332926Sdonn 		return( !istreg(r) );
81432926Sdonn 	case UNARY MUL:
81532926Sdonn 		p = p->in.left;
81632926Sdonn 		return( p->in.op != UNARY MUL && shtemp(p) );
81732926Sdonn 		}
81832926Sdonn 
81932926Sdonn 	if( optype( p->in.op ) != LTYPE ) return(0);
82032926Sdonn 	return(1);
8219702Slinton 	}
8229702Slinton 
8239702Slinton shumul( p ) register NODE *p; {
8249702Slinton 	register o;
8259702Slinton 	extern int xdebug;
8269702Slinton 
8279702Slinton 	if (xdebug) {
8289702Slinton 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
8299702Slinton 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
8309702Slinton 		}
8319702Slinton 
8329702Slinton 
8339702Slinton 	o = p->in.op;
8349702Slinton 	if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
8359702Slinton 
8369702Slinton 	if( ( o == INCR || o == ASG MINUS ) &&
8379702Slinton 	    ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) &&
8389702Slinton 	    p->in.right->in.name[0] == '\0' )
8399702Slinton 		{
84017659Sralph 		switch (p->in.type)
8419702Slinton 			{
8429702Slinton 			case CHAR|PTR:
8439702Slinton 			case UCHAR|PTR:
8449702Slinton 				o = 1;
8459702Slinton 				break;
8469702Slinton 
8479702Slinton 			case SHORT|PTR:
8489702Slinton 			case USHORT|PTR:
8499702Slinton 				o = 2;
8509702Slinton 				break;
8519702Slinton 
8529702Slinton 			case INT|PTR:
8539702Slinton 			case UNSIGNED|PTR:
8549702Slinton 			case LONG|PTR:
8559702Slinton 			case ULONG|PTR:
8569702Slinton 			case FLOAT|PTR:
8579702Slinton 				o = 4;
8589702Slinton 				break;
8599702Slinton 
8609702Slinton 			case DOUBLE|PTR:
8619702Slinton 				o = 8;
8629702Slinton 				break;
8639702Slinton 
8649702Slinton 			default:
86517742Sralph 				if ( ISPTR(p->in.type) &&
86617742Sralph 				     ISPTR(DECREF(p->in.type)) ) {
8679702Slinton 					o = 4;
8689702Slinton 					break;
8699702Slinton 					}
8709702Slinton 				else return(0);
8719702Slinton 			}
8729702Slinton 		return( p->in.right->tn.lval == o ? STARREG : 0);
8739702Slinton 		}
8749702Slinton 
8759702Slinton 	return( 0 );
8769702Slinton 	}
8779702Slinton 
8789702Slinton adrcon( val ) CONSZ val; {
87924418Smckusick 	putchar( '$' );
8809702Slinton 	printf( CONFMT, val );
8819702Slinton 	}
8829702Slinton 
8839702Slinton conput( p ) register NODE *p; {
8849702Slinton 	switch( p->in.op ){
8859702Slinton 
8869702Slinton 	case ICON:
8879702Slinton 		acon( p );
8889702Slinton 		return;
8899702Slinton 
8909702Slinton 	case REG:
89124418Smckusick 		putstr( rnames[p->tn.rval] );
8929702Slinton 		return;
8939702Slinton 
8949702Slinton 	default:
8959702Slinton 		cerror( "illegal conput" );
8969702Slinton 		}
8979702Slinton 	}
8989702Slinton 
89932923Sdonn /*ARGSUSED*/
90032924Sdonn insput( p ) NODE *p; {
9019702Slinton 	cerror( "insput" );
9029702Slinton 	}
9039702Slinton 
90432928Sdonn upput( p, size ) NODE *p; int size; {
90532928Sdonn 	if( size == SZLONG && p->in.op == REG ) {
90632928Sdonn 		putstr( rnames[p->tn.rval + 1] );
90732928Sdonn 		return;
90832928Sdonn 		}
9099702Slinton 	cerror( "upput" );
9109702Slinton 	}
9119702Slinton 
9129702Slinton adrput( p ) register NODE *p; {
9139702Slinton 	register int r;
9149702Slinton 	/* output an address, with offsets, from p */
9159702Slinton 
9169702Slinton 	if( p->in.op == FLD ){
9179702Slinton 		p = p->in.left;
9189702Slinton 		}
9199702Slinton 	switch( p->in.op ){
9209702Slinton 
9219702Slinton 	case NAME:
9229702Slinton 		acon( p );
9239702Slinton 		return;
9249702Slinton 
9259702Slinton 	case ICON:
9269702Slinton 		/* addressable value of the constant */
92724418Smckusick 		putchar( '$' );
9289702Slinton 		acon( p );
9299702Slinton 		return;
9309702Slinton 
9319702Slinton 	case REG:
93224418Smckusick 		putstr( rnames[p->tn.rval] );
9339702Slinton 		return;
9349702Slinton 
9359702Slinton 	case OREG:
9369702Slinton 		r = p->tn.rval;
9379702Slinton 		if( R2TEST(r) ){ /* double indexing */
9389702Slinton 			register int flags;
9399702Slinton 
9409702Slinton 			flags = R2UPK3(r);
94124418Smckusick 			if( flags & 1 ) putchar('*');
94224418Smckusick 			if( flags & 4 ) putchar('-');
9439702Slinton 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
9449702Slinton 			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
94524418Smckusick 			if( flags & 2 ) putchar('+');
9469702Slinton 			printf( "[%s]", rnames[R2UPK2(r)] );
9479702Slinton 			return;
9489702Slinton 			}
9499702Slinton 		if( r == AP ){  /* in the argument region */
95032925Sdonn 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
9519702Slinton 			printf( CONFMT, p->tn.lval );
95224418Smckusick 			putstr( "(ap)" );
9539702Slinton 			return;
9549702Slinton 			}
9559702Slinton 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
9569702Slinton 		printf( "(%s)", rnames[p->tn.rval] );
9579702Slinton 		return;
9589702Slinton 
9599702Slinton 	case UNARY MUL:
9609702Slinton 		/* STARNM or STARREG found */
9619702Slinton 		if( tshape(p, STARNM) ) {
96224418Smckusick 			putchar( '*' );
9639702Slinton 			adrput( p->in.left);
9649702Slinton 			}
9659702Slinton 		else {	/* STARREG - really auto inc or dec */
9669702Slinton 			register NODE *q;
9679702Slinton 
9689702Slinton /* tbl
9699702Slinton 			p = p->in.left;
9709702Slinton 			p->in.left->in.op = OREG;
9719702Slinton 			if( p->in.op == INCR ) {
9729702Slinton 				adrput( p->in.left );
97324418Smckusick 				putchar( '+' );
9749702Slinton 				}
9759702Slinton 			else {
97624418Smckusick 				putchar( '-' );
9779702Slinton 				adrput( p->in.left );
9789702Slinton 				}
9799702Slinton    tbl */
98017659Sralph 			q = p->in.left;
98117742Sralph 			if( q->in.right->tn.lval != tlen(p) )
98217742Sralph 				cerror("adrput: bad auto-increment/decrement");
98317659Sralph 			printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
98417659Sralph 				rnames[q->in.left->tn.rval],
98517659Sralph 				(q->in.op==INCR ? "+" : "") );
9869702Slinton 			p->in.op = OREG;
98717659Sralph 			p->tn.rval = q->in.left->tn.rval;
98817659Sralph 			p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0);
9899702Slinton #ifndef FLEXNAMES
9909702Slinton 			p->in.name[0] = '\0';
9919702Slinton #else
9929702Slinton 			p->in.name = "";
9939702Slinton #endif
9949702Slinton 			tfree(q);
9959702Slinton 		}
9969702Slinton 		return;
9979702Slinton 
9989702Slinton 	default:
9999702Slinton 		cerror( "illegal address" );
10009702Slinton 		return;
10019702Slinton 
10029702Slinton 		}
10039702Slinton 
10049702Slinton 	}
10059702Slinton 
10069702Slinton acon( p ) register NODE *p; { /* print out a constant */
10079702Slinton 
10089702Slinton 	if( p->in.name[0] == '\0' ){
10099702Slinton 		printf( CONFMT, p->tn.lval);
10109702Slinton 		}
10119702Slinton 	else if( p->tn.lval == 0 ) {
10129702Slinton #ifndef FLEXNAMES
10139702Slinton 		printf( "%.8s", p->in.name );
10149702Slinton #else
101524418Smckusick 		putstr( p->in.name );
10169702Slinton #endif
10179702Slinton 		}
10189702Slinton 	else {
10199702Slinton #ifndef FLEXNAMES
10209702Slinton 		printf( "%.8s+", p->in.name );
10219702Slinton #else
10229702Slinton 		printf( "%s+", p->in.name );
10239702Slinton #endif
10249702Slinton 		printf( CONFMT, p->tn.lval );
10259702Slinton 		}
10269702Slinton 	}
10279702Slinton 
10289702Slinton /*
10299702Slinton aacon( p ) register NODE *p; { /* print out a constant */
10309702Slinton /*
10319702Slinton 
10329702Slinton 	if( p->in.name[0] == '\0' ){
10339702Slinton 		printf( CONFMT, p->tn.lval);
10349702Slinton 		return( 0 );
10359702Slinton 		}
10369702Slinton 	else if( p->tn.lval == 0 ) {
10379702Slinton #ifndef FLEXNAMES
10389702Slinton 		printf( "$%.8s", p->in.name );
10399702Slinton #else
10409702Slinton 		printf( "$%s", p->in.name );
10419702Slinton #endif
10429702Slinton 		return( 1 );
10439702Slinton 		}
10449702Slinton 	else {
10459702Slinton 		printf( "$(" );
10469702Slinton 		printf( CONFMT, p->tn.lval );
10479702Slinton 		printf( "+" );
10489702Slinton #ifndef FLEXNAMES
10499702Slinton 		printf( "%.8s)", p->in.name );
10509702Slinton #else
10519702Slinton 		printf( "%s)", p->in.name );
10529702Slinton #endif
10539702Slinton 		return(1);
10549702Slinton 		}
10559702Slinton 	}
10569702Slinton  */
10579702Slinton 
10589702Slinton genscall( p, cookie ) register NODE *p; {
10599702Slinton 	/* structure valued call */
10609702Slinton 	return( gencall( p, cookie ) );
10619702Slinton 	}
10629702Slinton 
10639702Slinton /* tbl */
10649702Slinton int gc_numbytes;
10659702Slinton /* tbl */
10669702Slinton 
106732924Sdonn /*ARGSUSED*/
10689702Slinton gencall( p, cookie ) register NODE *p; {
10699702Slinton 	/* generate the call given by p */
107016418Sralph 	register NODE *p1;
10719702Slinton 	register temp, temp1;
10729702Slinton 	register m;
10739702Slinton 
10749702Slinton 	if( p->in.right ) temp = argsize( p->in.right );
10759702Slinton 	else temp = 0;
10769702Slinton 
10779702Slinton 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
10789702Slinton 		/* set aside room for structure return */
10799702Slinton 
10809702Slinton 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
10819702Slinton 		else temp1 = temp;
10829702Slinton 		}
10839702Slinton 
10849702Slinton 	if( temp > maxargs ) maxargs = temp;
10859702Slinton 	SETOFF(temp1,4);
10869702Slinton 
10879702Slinton 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
108816418Sralph 		genargs( p->in.right );
10899702Slinton 		}
10909702Slinton 
10919702Slinton 	p1 = p->in.left;
10929702Slinton 	if( p1->in.op != ICON ){
10939702Slinton 		if( p1->in.op != REG ){
10949702Slinton 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
10959702Slinton 				if( p1->in.op != NAME ){
10969702Slinton 					order( p1, INAREG );
10979702Slinton 					}
10989702Slinton 				}
10999702Slinton 			}
11009702Slinton 		}
11019702Slinton 
11029702Slinton /*
11039702Slinton 	if( p1->in.op == REG && p->tn.rval == R5 ){
11049702Slinton 		cerror( "call register overwrite" );
11059702Slinton 		}
11069702Slinton  */
11079702Slinton /* tbl
11089702Slinton 	setup gc_numbytes so reference to ZC works */
11099702Slinton 
11109702Slinton 	gc_numbytes = temp&(0x3ff);
11119702Slinton /* tbl */
11129702Slinton 
11139702Slinton 	p->in.op = UNARY CALL;
11149702Slinton 	m = match( p, INTAREG|INTBREG );
11159702Slinton 
11169702Slinton 	/* compensate for deficiency in 'ret' instruction ... wah,kre */
11179702Slinton 	/* (plus in assignment to gc_numbytes above, for neatness only) */
11189702Slinton 	if (temp >= 1024)
11199702Slinton 		printf("	addl2	$%d,sp\n", (temp&(~0x3ff)));
11209702Slinton 
11219702Slinton /* tbl
11229702Slinton 	switch( temp ) {
11239702Slinton 	case 0:
11249702Slinton 		break;
11259702Slinton 	case 2:
11269702Slinton 		printf( "	tst	(sp)+\n" );
11279702Slinton 		break;
11289702Slinton 	case 4:
11299702Slinton 		printf( "	cmp	(sp)+,(sp)+\n" );
11309702Slinton 		break;
11319702Slinton 	default:
11329702Slinton 		printf( "	add	$%d,sp\n", temp);
11339702Slinton 		}
11349702Slinton    tbl */
11359702Slinton 	return(m != MDONE);
11369702Slinton 	}
11379702Slinton 
11389702Slinton /* tbl */
11399702Slinton char *
11409702Slinton ccbranches[] = {
11419702Slinton 	"	jeql	L%d\n",
11429702Slinton 	"	jneq	L%d\n",
11439702Slinton 	"	jleq	L%d\n",
11449702Slinton 	"	jlss	L%d\n",
11459702Slinton 	"	jgeq	L%d\n",
11469702Slinton 	"	jgtr	L%d\n",
11479702Slinton 	"	jlequ	L%d\n",
11489702Slinton 	"	jlssu	L%d\n",
11499702Slinton 	"	jgequ	L%d\n",
11509702Slinton 	"	jgtru	L%d\n",
11519702Slinton 	};
11529702Slinton /* tbl */
11539702Slinton 
115432924Sdonn /*ARGSUSED*/
11559702Slinton cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
11569702Slinton 
11579702Slinton /* tbl */
11589702Slinton 	if( o == 0 ) printf( "	jbr	L%d\n", lab );
11599702Slinton /* tbl */
11609702Slinton 	else {
11619702Slinton 		if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
11629702Slinton 		printf( ccbranches[o-EQ], lab );
11639702Slinton 		}
11649702Slinton 	}
11659702Slinton 
11669702Slinton nextcook( p, cookie ) NODE *p; {
11679702Slinton 	/* we have failed to match p with cookie; try another */
11689702Slinton 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
11699702Slinton 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
11709702Slinton 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
11719702Slinton 	return( FORREW );
11729702Slinton 	}
11739702Slinton 
117432924Sdonn /*ARGSUSED*/
11759702Slinton lastchance( p, cook ) NODE *p; {
11769702Slinton 	/* forget it! */
11779702Slinton 	return(0);
11789702Slinton 	}
11799702Slinton 
11809702Slinton optim2( p ) register NODE *p; {
11819702Slinton 	/* do local tree transformations and optimizations */
11829702Slinton 
1183*32929Sdonn 	int o;
1184*32929Sdonn 	int result, i;
1185*32929Sdonn 	int lower, upper;
118616181Sralph 	register NODE *l, *r;
11879702Slinton 
1188*32929Sdonn 	switch( o = p->in.op ) {
11899702Slinton 
11909702Slinton 	case AND:
119119933Smckusick 		/* commute L and R to eliminate complements and constants */
119216181Sralph 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
119316181Sralph 		    l->in.op == COMPL ) {
11949702Slinton 			p->in.left = p->in.right;
119516181Sralph 			p->in.right = l;
11969702Slinton 			}
11979702Slinton 	case ASG AND:
11989702Slinton 		/* change meaning of AND to ~R&L - bic on pdp11 */
11999702Slinton 		r = p->in.right;
120019933Smckusick 		if( r->in.op==ICON && r->in.name[0]==0 ) { /* complement constant */
12019702Slinton 			r->tn.lval = ~r->tn.lval;
12029702Slinton 			}
12039702Slinton 		else if( r->in.op==COMPL ) { /* ~~A => A */
12049702Slinton 			r->in.op = FREE;
12059702Slinton 			p->in.right = r->in.left;
12069702Slinton 			}
12079702Slinton 		else { /* insert complement node */
120816181Sralph 			p->in.right = l = talloc();
120916181Sralph 			l->in.op = COMPL;
121016181Sralph 			l->in.rall = NOPREF;
121116181Sralph 			l->in.type = r->in.type;
121216181Sralph 			l->in.left = r;
121316181Sralph 			l->in.right = NULL;
12149702Slinton 			}
12159702Slinton 		break;
12169702Slinton 
121716181Sralph 	case SCONV:
121819933Smckusick 		l = p->in.left;
121917742Sralph #if defined(FORT) || defined(SPRECC)
122016573Sralph 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
122119933Smckusick 		    l->in.type == FLOAT || l->in.type == DOUBLE )
122219933Smckusick 			return;
122316573Sralph #else
122419933Smckusick 		if( mixtypes(p, l) ) return;
122516573Sralph #endif
122632924Sdonn 		if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
122725751Sdonn 			return;
122825751Sdonn 
122919933Smckusick 		/* Only trust it to get it right if the size is the same */
123019933Smckusick 		if( tlen(p) != tlen(l) )
123119933Smckusick 			return;
123216181Sralph 
123316181Sralph 		/* clobber conversion */
123419933Smckusick 		if( l->in.op != FLD )
123516181Sralph 			l->in.type = p->in.type;
123616181Sralph 		ncopy( p, l );
123716181Sralph 		l->in.op = FREE;
123819933Smckusick 
123916181Sralph 		break;
124016181Sralph 
124124418Smckusick 	case ASSIGN:
124224418Smckusick 		/*
124324418Smckusick 		 * Conversions are equivalent to assignments;
124424418Smckusick 		 * when the two operations are combined,
124524418Smckusick 		 * we can sometimes zap the conversion.
124624418Smckusick 		 */
124724418Smckusick 		r = p->in.right;
124824418Smckusick 		l = p->in.left;
124924418Smckusick 		if ( r->in.op == SCONV &&
125024418Smckusick 		     !mixtypes(l, r) &&
125132922Sdonn 		     l->in.op != FLD &&
125224418Smckusick 		     tlen(l) == tlen(r) ) {
125324418Smckusick 				p->in.right = r->in.left;
125424418Smckusick 				r->in.op = FREE;
125524418Smckusick 			}
125624418Smckusick 		break;
125724418Smckusick 
1258*32929Sdonn 	case ULE:
1259*32929Sdonn 	case ULT:
1260*32929Sdonn 	case UGE:
1261*32929Sdonn 	case UGT:
1262*32929Sdonn 		o -= (UGE-GE);
1263*32929Sdonn 	case EQ:
1264*32929Sdonn 	case NE:
1265*32929Sdonn 	case LE:
1266*32929Sdonn 	case LT:
1267*32929Sdonn 	case GE:
1268*32929Sdonn 	case GT:
1269*32929Sdonn 		r = p->in.right;
1270*32929Sdonn 		l = p->in.left;
1271*32929Sdonn 		if( r->in.op != ICON ||
1272*32929Sdonn 		    r->tn.name[0] != '\0' ||
1273*32929Sdonn 		    tlen(l) >= tlen(r) )
1274*32929Sdonn 			break;
1275*32929Sdonn 		switch( l->in.type ) {
1276*32929Sdonn 		case CHAR:
1277*32929Sdonn 			lower = -(1 << SZCHAR - 1);
1278*32929Sdonn 			upper = (1 << SZCHAR - 1) - 1;
1279*32929Sdonn 			break;
1280*32929Sdonn 		case UCHAR:
1281*32929Sdonn 			lower = 0;
1282*32929Sdonn 			upper = (1 << SZCHAR) - 1;
1283*32929Sdonn 			break;
1284*32929Sdonn 		case SHORT:
1285*32929Sdonn 			lower = -(1 << SZSHORT - 1);
1286*32929Sdonn 			upper = (1 << SZSHORT - 1) - 1;
1287*32929Sdonn 			break;
1288*32929Sdonn 		case USHORT:
1289*32929Sdonn 			lower = 0;
1290*32929Sdonn 			upper = (1 << SZSHORT) - 1;
1291*32929Sdonn 			break;
1292*32929Sdonn 		default:
1293*32929Sdonn 			cerror("unsupported OPLOG in optim2");
1294*32929Sdonn 			}
1295*32929Sdonn 		result = -1;
1296*32929Sdonn 		i = r->tn.lval;
1297*32929Sdonn 		switch( o ) {
1298*32929Sdonn 		case EQ:
1299*32929Sdonn 		case NE:
1300*32929Sdonn 			if( lower == 0 && (unsigned) i > upper )
1301*32929Sdonn 				result = o == NE;
1302*32929Sdonn 			else if( i < lower || i > upper )
1303*32929Sdonn 				result = o == NE;
1304*32929Sdonn 			break;
1305*32929Sdonn 		case LT:
1306*32929Sdonn 		case GE:
1307*32929Sdonn 			if( lower == 0 && (unsigned) i > upper )
1308*32929Sdonn 				result = o == LT;
1309*32929Sdonn 			else if( i <= lower )
1310*32929Sdonn 				result = o != LT;
1311*32929Sdonn 			else if( i > upper )
1312*32929Sdonn 				result = o == LT;
1313*32929Sdonn 			break;
1314*32929Sdonn 		case LE:
1315*32929Sdonn 		case GT:
1316*32929Sdonn 			if( lower == 0 && (unsigned) i >= upper )
1317*32929Sdonn 				result = o == LE;
1318*32929Sdonn 			else if( i < lower )
1319*32929Sdonn 				result = o != LE;
1320*32929Sdonn 			else if( i >= upper )
1321*32929Sdonn 				result = o == LE;
1322*32929Sdonn 			break;
1323*32929Sdonn 			}
1324*32929Sdonn 		if( result == -1 )
1325*32929Sdonn 			break;
1326*32929Sdonn 
1327*32929Sdonn 		if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1328*32929Sdonn 			l->in.op = FREE;
1329*32929Sdonn 			ncopy(p, r);
1330*32929Sdonn 			r->in.op = FREE;
1331*32929Sdonn 			p->tn.type = INT;
1332*32929Sdonn 			p->tn.lval = result;
1333*32929Sdonn 			}
1334*32929Sdonn 		else {
1335*32929Sdonn 			p->in.op = COMOP;
1336*32929Sdonn 			p->in.type = INT;
1337*32929Sdonn 			r->tn.type = INT;
1338*32929Sdonn 			r->tn.lval = result;
1339*32929Sdonn 			}
1340*32929Sdonn 		break;
13419702Slinton 		}
13429702Slinton 	}
13439702Slinton 
134432924Sdonn /*ARGSUSED*/
134517742Sralph NODE * addroreg(l) NODE *l;
13469702Slinton 				/* OREG was built in clocal()
13479702Slinton 				 * for an auto or formal parameter
13489702Slinton 				 * now its address is being taken
13499702Slinton 				 * local code must unwind it
13509702Slinton 				 * back to PLUS/MINUS REG ICON
13519702Slinton 				 * according to local conventions
13529702Slinton 				 */
13539702Slinton {
13549702Slinton 	cerror("address of OREG taken");
135517742Sralph 	/*NOTREACHED*/
13569702Slinton }
13579702Slinton 
13589702Slinton 
13599702Slinton 
13609702Slinton # ifndef ONEPASS
13619702Slinton main( argc, argv ) char *argv[]; {
13629702Slinton 	return( mainp2( argc, argv ) );
13639702Slinton 	}
13649702Slinton # endif
13659702Slinton 
13669702Slinton 
13679702Slinton /* added by jwf */
13689702Slinton struct functbl {
13699702Slinton 	int fop;
13709702Slinton 	TWORD ftype;
13719702Slinton 	char *func;
13729702Slinton 	} opfunc[] = {
13739702Slinton 	DIV,		TANY,	"udiv",
13749702Slinton 	MOD,		TANY,	"urem",
137517715Sralph 	ASG DIV,	TANY,	"audiv",
137617715Sralph 	ASG MOD,	TANY,	"aurem",
13779702Slinton 	0,	0,	0 };
13789702Slinton 
13799702Slinton hardops(p)  register NODE *p; {
13809702Slinton 	/* change hard to do operators into function calls.  */
13819702Slinton 	register NODE *q;
13829702Slinton 	register struct functbl *f;
13839702Slinton 	register o;
138417742Sralph 	NODE *old,*temp;
13859702Slinton 
13869702Slinton 	o = p->in.op;
138717742Sralph 	if( ! (optype(o)==BITYPE &&
138817742Sralph 	       (ISUNSIGNED(p->in.left->in.type) ||
138917742Sralph 		ISUNSIGNED(p->in.right->in.type))) )
139017742Sralph 		return;
13919702Slinton 
13929702Slinton 	for( f=opfunc; f->fop; f++ ) {
13939702Slinton 		if( o==f->fop ) goto convert;
13949702Slinton 		}
13959702Slinton 	return;
13969702Slinton 
13979702Slinton 	convert:
139832928Sdonn 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) {
139932928Sdonn 		/* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */
140032928Sdonn 		/* save a subroutine call -- use at most 5 instructions */
140132928Sdonn 		if( p->in.op == DIV &&
140232928Sdonn 		     (unsigned) p->in.right->tn.lval >= 0x80000000 )
140332928Sdonn 			/* easy to do here, harder to do in zzzcode() */
140432928Sdonn 			p->in.op = UGE;
140532928Sdonn 		return;
140632928Sdonn 		}
14079702Slinton 	if( asgop( o ) ) {
140817742Sralph 		old = NIL;
140917715Sralph 		switch( p->in.left->in.op ){
141017742Sralph 		case FLD:
141117742Sralph 			q = p->in.left->in.left;
141217742Sralph 			/*
141317742Sralph 			 * rewrite (lval.fld /= rval); as
141417742Sralph 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
141517742Sralph 			 * else the compiler will evaluate lval twice.
141617742Sralph 			 */
141717742Sralph 			if( q->in.op == UNARY MUL ){
141817742Sralph 				/* first allocate a temp storage */
141917742Sralph 				temp = talloc();
142017742Sralph 				temp->in.op = OREG;
142117742Sralph 				temp->tn.rval = TMPREG;
142217742Sralph 				temp->tn.lval = BITOOR(freetemp(1));
142317742Sralph 				temp->in.type = INCREF(p->in.type);
142417742Sralph #ifdef FLEXNAMES
142517742Sralph 				temp->in.name = "";
142617742Sralph #else
142717742Sralph 				temp->in.name[0] = '\0';
142817742Sralph #endif
142917742Sralph 				old = q->in.left;
143017742Sralph 				q->in.left = temp;
143117742Sralph 			}
143217742Sralph 			/* fall thru ... */
143317742Sralph 
143417715Sralph 		case REG:
143517715Sralph 		case NAME:
143617715Sralph 		case OREG:
143717715Sralph 			/* change ASG OP to a simple OP */
143817715Sralph 			q = talloc();
143917715Sralph 			q->in.op = NOASG p->in.op;
144017715Sralph 			q->in.rall = NOPREF;
144117715Sralph 			q->in.type = p->in.type;
144217715Sralph 			q->in.left = tcopy(p->in.left);
144317715Sralph 			q->in.right = p->in.right;
144417715Sralph 			p->in.op = ASSIGN;
144517715Sralph 			p->in.right = q;
144617715Sralph 			p = q;
144717715Sralph 			f -= 2; /* Note: this depends on the table order */
144817742Sralph 			/* on the right side only - replace *temp with
144917742Sralph 			 *(temp = &lval), build the assignment node */
145017742Sralph 			if( old ){
145117742Sralph 				temp = q->in.left->in.left; /* the "*" node */
145217742Sralph 				q = talloc();
145317742Sralph 				q->in.op = ASSIGN;
145417742Sralph 				q->in.left = temp->in.left;
145517742Sralph 				q->in.right = old;
145617742Sralph 				q->in.type = old->in.type;
145717742Sralph #ifdef FLEXNAMES
145817742Sralph 				q->in.name = "";
145917742Sralph #else
146017742Sralph 				q->in.name[0] = '\0';
146117742Sralph #endif
146217742Sralph 				temp->in.left = q;
146317742Sralph 			}
146417715Sralph 			break;
14659702Slinton 
146617715Sralph 		case UNARY MUL:
146717715Sralph 			/* avoid doing side effects twice */
146817715Sralph 			q = p->in.left;
146917715Sralph 			p->in.left = q->in.left;
147017715Sralph 			q->in.op = FREE;
147117715Sralph 			break;
147217715Sralph 
147317715Sralph 		default:
147417715Sralph 			cerror( "hardops: can't compute & LHS" );
147517715Sralph 			}
147617742Sralph 		}
147717715Sralph 
14789702Slinton 	/* build comma op for args to function */
14799702Slinton 	q = talloc();
14809702Slinton 	q->in.op = CM;
14819702Slinton 	q->in.rall = NOPREF;
14829702Slinton 	q->in.type = INT;
14839702Slinton 	q->in.left = p->in.left;
14849702Slinton 	q->in.right = p->in.right;
14859702Slinton 	p->in.op = CALL;
14869702Slinton 	p->in.right = q;
14879702Slinton 
14889702Slinton 	/* put function name in left node of call */
14899702Slinton 	p->in.left = q = talloc();
14909702Slinton 	q->in.op = ICON;
14919702Slinton 	q->in.rall = NOPREF;
14929702Slinton 	q->in.type = INCREF( FTN + p->in.type );
14939702Slinton #ifndef FLEXNAMES
14949702Slinton 	strcpy( q->in.name, f->func );
14959702Slinton #else
14969702Slinton 	q->in.name = f->func;
14979702Slinton #endif
14989702Slinton 	q->tn.lval = 0;
14999702Slinton 	q->tn.rval = 0;
15009702Slinton 
15019702Slinton 	}
15029702Slinton 
150317742Sralph zappost(p) NODE *p; {
150417742Sralph 	/* look for ++ and -- operators and remove them */
150517742Sralph 
150617742Sralph 	register o, ty;
150717742Sralph 	register NODE *q;
150817742Sralph 	o = p->in.op;
150917742Sralph 	ty = optype( o );
151017742Sralph 
151117742Sralph 	switch( o ){
151217742Sralph 
151317742Sralph 	case INCR:
151417742Sralph 	case DECR:
151517742Sralph 			q = p->in.left;
151617742Sralph 			p->in.right->in.op = FREE;  /* zap constant */
151717742Sralph 			ncopy( p, q );
151817742Sralph 			q->in.op = FREE;
151917742Sralph 			return;
152017742Sralph 
152117742Sralph 		}
152217742Sralph 
152317742Sralph 	if( ty == BITYPE ) zappost( p->in.right );
152417742Sralph 	if( ty != LTYPE ) zappost( p->in.left );
152517742Sralph }
152617742Sralph 
152717742Sralph fixpre(p) NODE *p; {
152817742Sralph 
152917742Sralph 	register o, ty;
153017742Sralph 	o = p->in.op;
153117742Sralph 	ty = optype( o );
153217742Sralph 
153317742Sralph 	switch( o ){
153417742Sralph 
153517742Sralph 	case ASG PLUS:
153617742Sralph 			p->in.op = PLUS;
153717742Sralph 			break;
153817742Sralph 	case ASG MINUS:
153917742Sralph 			p->in.op = MINUS;
154017742Sralph 			break;
154117742Sralph 		}
154217742Sralph 
154317742Sralph 	if( ty == BITYPE ) fixpre( p->in.right );
154417742Sralph 	if( ty != LTYPE ) fixpre( p->in.left );
154517742Sralph }
154617742Sralph 
154724418Smckusick strip(p) register NODE *p; {
154824418Smckusick 	NODE *q;
154924418Smckusick 
155024418Smckusick 	/* strip nodes off the top when no side effects occur */
155124418Smckusick 	for( ; ; ) {
155224418Smckusick 		switch( p->in.op ) {
155324418Smckusick 		case SCONV:			/* remove lint tidbits */
155424418Smckusick 			q = p->in.left;
155524418Smckusick 			ncopy( p, q );
155624418Smckusick 			q->in.op = FREE;
155724418Smckusick 			break;
155824418Smckusick 		/* could probably add a few more here */
155924418Smckusick 		default:
156024418Smckusick 			return;
156124418Smckusick 			}
156224418Smckusick 		}
156324418Smckusick 	}
156424418Smckusick 
15659702Slinton myreader(p) register NODE *p; {
156624418Smckusick 	strip( p );		/* strip off operations with no side effects */
156717742Sralph 	canon( p );		/* expands r-vals for fields */
15689702Slinton 	walkf( p, hardops );	/* convert ops to function calls */
15699702Slinton 	walkf( p, optim2 );
15709702Slinton 	/* jwf toff = 0;  /* stack offset swindle */
15719702Slinton 	}
1572