xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 30360)
125828Ssam #ifndef lint
2*30360Ssam static char sccsid[] = "@(#)local2.c	1.8 (Berkeley) 01/09/87";
325828Ssam #endif
425828Ssam 
526076Ssam # include "pass2.h"
626076Ssam # include <ctype.h>
726162Ssam 
826162Ssam # define putstr(s)	fputs((s), stdout)
929672Ssam # define ISCHAR(p)	(p->in.type == UCHAR || p->in.type == CHAR)
1026162Ssam 
1125828Ssam # ifdef FORT
1225828Ssam int ftlab1, ftlab2;
1325828Ssam # endif
1425828Ssam /* a lot of the machine dependent parts of the second pass */
1525828Ssam 
1625828Ssam # define BITMASK(n) ((1L<<n)-1)
1725828Ssam 
1825828Ssam # ifndef ONEPASS
1925828Ssam where(c){
2025828Ssam 	fprintf( stderr, "%s, line %d: ", filename, lineno );
2125828Ssam 	}
2225828Ssam # endif
2325828Ssam 
2425828Ssam lineid( l, fn ) char *fn; {
2525828Ssam 	/* identify line l and file fn */
2625828Ssam 	printf( "#	line %d, file %s\n", l, fn );
2725828Ssam 	}
2825828Ssam 
2925828Ssam int ent_mask;
3025828Ssam 
3125828Ssam eobl2(){
3225828Ssam 	register OFFSZ spoff;	/* offset from stack pointer */
3325828Ssam #ifndef FORT
3425828Ssam 	extern int ftlab1, ftlab2;
3525828Ssam #endif
3625828Ssam 
3725828Ssam 	spoff = maxoff;
3825828Ssam 	spoff /= SZCHAR;
3925828Ssam 	SETOFF(spoff,4);
4025828Ssam #ifdef FORT
4125828Ssam #ifndef FLEXNAMES
4225828Ssam 	printf( "	.set	.F%d,%d\n", ftnno, spoff );
4325828Ssam #else
4425828Ssam 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
4525828Ssam 	printf( "	.set	LF%d,%d\n", ftnno, spoff );
4625828Ssam #endif
4725828Ssam 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
4825828Ssam #else
4925828Ssam 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
5025828Ssam 	printf( "L%d:\n", ftlab1);
5125828Ssam 	if( maxoff > AUTOINIT )
5225828Ssam 		printf( "	subl3	$%d,fp,sp\n", spoff);
5325828Ssam 	printf( "	jbr 	L%d\n", ftlab2);
5425828Ssam #endif
5525828Ssam 	ent_mask = 0;
5625828Ssam 	maxargs = -1;
5725828Ssam 	}
5825828Ssam 
5925828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = {
6025828Ssam 
6125828Ssam 	PLUS,	"add",
6225828Ssam 	MINUS,	"sub",
6325828Ssam 	MUL,	"mul",
6425828Ssam 	DIV,	"div",
6525828Ssam 	MOD,	"div",
6625828Ssam 	OR,	"or",
6725828Ssam 	ER,	"xor",
6825828Ssam 	AND,	"and",
6925828Ssam 	-1,	""    };
7025828Ssam 
7125828Ssam hopcode( f, o ){
7225828Ssam 	/* output the appropriate string from the above table */
7325828Ssam 
7425828Ssam 	register struct hoptab *q;
7525828Ssam 
7625828Ssam 	if(asgop(o))
7725828Ssam 		o = NOASG o;
7825828Ssam 	for( q = ioptab;  q->opmask>=0; ++q ){
7925828Ssam 		if( q->opmask == o ){
8025828Ssam 			if(f == 'E')
8125828Ssam 				printf( "e%s", q->opstring);
8225828Ssam 			else
8325828Ssam 				printf( "%s%c", q->opstring, tolower(f));
8425828Ssam 			return;
8525828Ssam 			}
8625828Ssam 		}
8725828Ssam 	cerror( "no hoptab for %s", opst[o] );
8825828Ssam 	}
8925828Ssam 
9025828Ssam char *
9125828Ssam rnames[] = {  /* keyed to register number tokens */
9225828Ssam 
9325828Ssam 	"r0", "r1",
9425828Ssam 	"r2", "r3", "r4", "r5",
9525828Ssam 	"r6", "r7", "r8", "r9", "r10", "r11",
9625828Ssam 	"r12", "fp", "sp", "pc",
9725828Ssam 	};
9825828Ssam 
9925828Ssam /* output register name and update entry mask */
10025828Ssam char *
10125828Ssam rname(r)
10225828Ssam 	register int r;
10325828Ssam {
10425828Ssam 
10525828Ssam 	ent_mask |= 1<<r;
10625828Ssam 	return(rnames[r]);
10725828Ssam }
10825828Ssam 
10925828Ssam int rstatus[] = {
11025828Ssam 	SAREG|STAREG, SAREG|STAREG,
11125828Ssam 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
11225828Ssam 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
11325828Ssam 	SAREG, SAREG, SAREG, SAREG,
11425828Ssam 	};
11525828Ssam 
11625828Ssam tlen(p) NODE *p;
11725828Ssam {
11825828Ssam 	switch(p->in.type) {
11925828Ssam 		case CHAR:
12025828Ssam 		case UCHAR:
12125828Ssam 			return(1);
12225828Ssam 
12325828Ssam 		case SHORT:
12425828Ssam 		case USHORT:
12525828Ssam 			return(2);
12625828Ssam 
12725828Ssam 		case DOUBLE:
12825828Ssam 			return(8);
12925828Ssam 
13025828Ssam 		default:
13125828Ssam 			return(4);
13225828Ssam 		}
13325828Ssam }
13425828Ssam 
135*30360Ssam anyfloat(p, q)
136*30360Ssam 	NODE *p, *q;
137*30360Ssam {
138*30360Ssam 	register TWORD tp, tq;
139*30360Ssam 
140*30360Ssam 	tp = p->in.type;
141*30360Ssam 	tq = q->in.type;
142*30360Ssam 	return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
143*30360Ssam }
144*30360Ssam 
14525828Ssam prtype(n) NODE *n;
14625828Ssam {
14725828Ssam 	switch (n->in.type)
14825828Ssam 		{
14925828Ssam 
15025828Ssam 		case DOUBLE:
15126162Ssam 			putchar('d');
15225828Ssam 			return;
15325828Ssam 
15425828Ssam 		case FLOAT:
15526162Ssam 			putchar('f');
15625828Ssam 			return;
15725828Ssam 
15825828Ssam 		case INT:
15925828Ssam 		case UNSIGNED:
16026162Ssam 			putchar('l');
16125828Ssam 			return;
16225828Ssam 
16325828Ssam 		case SHORT:
16425828Ssam 		case USHORT:
16526162Ssam 			putchar('w');
16625828Ssam 			return;
16725828Ssam 
16825828Ssam 		case CHAR:
16925828Ssam 		case UCHAR:
17026162Ssam 			putchar('b');
17125828Ssam 			return;
17225828Ssam 
17325828Ssam 		default:
17425828Ssam 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
17525828Ssam 			else {
17626162Ssam 				putchar('l');
17725828Ssam 				return;
17825828Ssam 				}
17925828Ssam 		}
18025828Ssam }
18125828Ssam 
18225828Ssam zzzcode( p, c ) register NODE *p; {
18325828Ssam 	register int m;
18425828Ssam 	int val;
18525828Ssam 	switch( c ){
18625828Ssam 
18725828Ssam 	case 'N':  /* logical ops, turned into 0-1 */
18825828Ssam 		/* use register given by register 1 */
18925828Ssam 		cbgen( 0, m=getlab(), 'I' );
19025828Ssam 		deflab( p->bn.label );
19125828Ssam 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
19225828Ssam 		deflab( m );
19325828Ssam 		return;
19425828Ssam 
19525828Ssam 	case 'P':
19625828Ssam 		cbgen( p->in.op, p->bn.label, c );
19725828Ssam 		return;
19825828Ssam 
19925828Ssam 	case 'A':	/* assignment and load (integer only) */
20025828Ssam 		{
20125828Ssam 		register NODE *l, *r;
20225828Ssam 
20325828Ssam 		if (xdebug) eprint(p, 0, &val, &val);
20425828Ssam 		r = getlr(p, 'R');
20525828Ssam 		if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) {
20625828Ssam 			l = resc;
20725828Ssam 			l->in.type = INT;
20825828Ssam 		} else
20925828Ssam 			l = getlr(p, 'L');
21025828Ssam 		if(r->in.type==FLOAT || r->in.type==DOUBLE
21125828Ssam 		 || l->in.type==FLOAT || l->in.type==DOUBLE)
21225828Ssam 			cerror("float in ZA");
21325828Ssam 		if (r->in.op == ICON)
21425828Ssam 			if(r->in.name[0] == '\0') {
21525828Ssam 				if (r->tn.lval == 0) {
21626162Ssam 					putstr("clr");
21725828Ssam 					prtype(l);
21826162Ssam 					putchar('\t');
21925828Ssam 					adrput(l);
22025828Ssam 					return;
22125828Ssam 				}
22225828Ssam 				if (r->tn.lval < 0 && r->tn.lval >= -63) {
22326162Ssam 					putstr("mneg");
22425828Ssam 					prtype(l);
22525828Ssam 					r->tn.lval = -r->tn.lval;
22625828Ssam 					goto ops;
22725828Ssam 				}
22825828Ssam #ifdef MOVAFASTER
22925828Ssam 			} else {
23026162Ssam 				putstr("movab\t");
23125828Ssam 				acon(r);
23226162Ssam 				putchar(',');
23325828Ssam 				adrput(l);
23425828Ssam 				return;
23525828Ssam #endif MOVAFASTER
23625828Ssam 			}
23725828Ssam 
23825828Ssam 		if (l->in.op == REG) {
23925828Ssam 			if( tlen(l) < tlen(r) ) {
24026162Ssam 				putstr(!ISUNSIGNED(l->in.type)?
24126162Ssam 					"cvt": "movz");
24225828Ssam 				prtype(l);
24326162Ssam 				putchar('l');
24425828Ssam 				goto ops;
24525828Ssam 			} else
24625828Ssam 				l->in.type = INT;
24725828Ssam 		}
24825828Ssam 		if (tlen(l) == tlen(r)) {
24926162Ssam 			putstr("mov");
25025828Ssam 			prtype(l);
25125828Ssam 			goto ops;
25225828Ssam 		} else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
25326162Ssam 			putstr("movz");
25425828Ssam 		else
25526162Ssam 			putstr("cvt");
25625828Ssam 		prtype(r);
25725828Ssam 		prtype(l);
25825828Ssam 	ops:
25926162Ssam 		putchar('\t');
26025828Ssam 		adrput(r);
26126162Ssam 		putchar(',');
26225828Ssam 		adrput(l);
26325828Ssam 		return;
26425828Ssam 		}
26525828Ssam 
26625828Ssam 	case 'B':	/* get oreg value in temp register for shift */
26725828Ssam 		{
26825828Ssam 		register NODE *r;
26925828Ssam 		if (xdebug) eprint(p, 0, &val, &val);
27025828Ssam 		r = p->in.right;
27125828Ssam 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
27226162Ssam 			putstr("movl");
27325828Ssam 		else {
27426162Ssam 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
27525828Ssam 			prtype(r);
27626162Ssam 			putchar('l');
27725828Ssam 			}
27825828Ssam 		return;
27925828Ssam 		}
28025828Ssam 
28125828Ssam 	case 'C':	/* num bytes pushed on arg stack */
28225828Ssam 		{
28325828Ssam 		extern int gc_numbytes;
28425828Ssam 		extern int xdebug;
28525828Ssam 
28625828Ssam 		if (xdebug) printf("->%d<-",gc_numbytes);
28725828Ssam 
28825828Ssam 		printf("call%c	$%d",
28925828Ssam 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
29025828Ssam 		 gc_numbytes+4);
29125828Ssam 		/* dont change to double (here's the only place to catch it) */
29225828Ssam 		if(p->in.type == FLOAT)
29325828Ssam 			rtyflg = 1;
29425828Ssam 		return;
29525828Ssam 		}
29625828Ssam 
29725828Ssam 	case 'D':	/* INCR and DECR */
29825828Ssam 		zzzcode(p->in.left, 'A');
29926162Ssam 		putstr("\n	");
30025828Ssam 
30125828Ssam 	case 'E':	/* INCR and DECR, FOREFF */
30225828Ssam  		if (p->in.right->tn.lval == 1)
30325828Ssam 			{
30426162Ssam 			putstr(p->in.op == INCR ? "inc" : "dec");
30525828Ssam 			prtype(p->in.left);
30626162Ssam 			putchar('\t');
30725828Ssam 			adrput(p->in.left);
30825828Ssam 			return;
30925828Ssam 			}
31026162Ssam 		putstr(p->in.op == INCR ? "add" : "sub");
31125828Ssam 		prtype(p->in.left);
31226162Ssam 		putstr("2	");
31325828Ssam 		adrput(p->in.right);
31426162Ssam 		putchar(',');
31525828Ssam 		adrput(p->in.left);
31625828Ssam 		return;
31725828Ssam 
31825828Ssam 	case 'F':	/* masked constant for fields */
31925947Ssam 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
32025828Ssam 		return;
32125828Ssam 
32225828Ssam 	case 'H':	/* opcode for shift */
32325828Ssam 		if(p->in.op == LS || p->in.op == ASG LS)
32426162Ssam 			putstr("shll");
32525828Ssam 		else if(ISUNSIGNED(p->in.left->in.type))
32626162Ssam 			putstr("shrl");
32725828Ssam 		else
32826162Ssam 			putstr("shar");
32925828Ssam 		return;
33025828Ssam 
33125828Ssam 	case 'L':	/* type of left operand */
33225828Ssam 	case 'R':	/* type of right operand */
33325828Ssam 		{
33425828Ssam 		register NODE *n;
33525828Ssam 		extern int xdebug;
33625828Ssam 
33725828Ssam 		n = getlr ( p, c);
33825828Ssam 		if (xdebug) printf("->%d<-", n->in.type);
33925828Ssam 
34025828Ssam 		prtype(n);
34125828Ssam 		return;
34225828Ssam 		}
34325828Ssam 
344*30360Ssam 	case 'M': {  /* initiate ediv for mod and unsigned div */
34525828Ssam 		register char *r;
34625828Ssam 		m = getlr(p, '1')->tn.rval;
34725828Ssam 		r = rname(m);
34825828Ssam 		printf("\tclrl\t%s\n\tmovl\t", r);
34925828Ssam 		adrput(p->in.left);
35025828Ssam 		printf(",%s\n", rname(m+1));
35125828Ssam 		if(!ISUNSIGNED(p->in.type)) { 	/* should be MOD */
35225828Ssam 			m = getlab();
35325828Ssam 			printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
35425828Ssam 			deflab(m);
35525828Ssam 		}
35625828Ssam 		return;
357*30360Ssam 	}
35825828Ssam 
359*30360Ssam 	case 'T': {	/* rounded structure length for arguments */
360*30360Ssam 		int size = p->stn.stsize;
36125828Ssam 		SETOFF( size, 4);
36225828Ssam 		printf("movab	-%d(sp),sp", size);
36325828Ssam 		return;
364*30360Ssam 	}
36525828Ssam 
36625828Ssam 	case 'S':  /* structure assignment */
36725977Ssam 		stasg(p);
36825977Ssam 		break;
36925828Ssam 
37029672Ssam 	case 'X':	/* multiplication for short and char */
37129672Ssam 		if (ISUNSIGNED(p->in.left->in.type))
37229672Ssam 			printf("\tmovz");
37329672Ssam 		else
37429672Ssam 			printf("\tcvt");
37529672Ssam 		zzzcode(p, 'L');
37629672Ssam 		printf("l\t");
37729672Ssam 		adrput(p->in.left);
37829672Ssam 		printf(",");
37929672Ssam 		adrput(&resc[0]);
38029672Ssam 		printf("\n");
38129672Ssam 		if (ISUNSIGNED(p->in.right->in.type))
38229672Ssam 			printf("\tmovz");
38329672Ssam 		else
38429672Ssam 			printf("\tcvt");
38529672Ssam 		zzzcode(p, 'R');
38629672Ssam 		printf("l\t");
38729672Ssam 		adrput(p->in.right);
38829672Ssam 		printf(",");
38929672Ssam 		adrput(&resc[1]);
39029672Ssam 		printf("\n");
39129672Ssam 		return;
39229672Ssam 
393*30360Ssam 	case 'U':		/* SCONV */
394*30360Ssam 	case 'V':		/* SCONV with FORCC */
395*30360Ssam 		sconv(p, c == 'V');
396*30360Ssam 		break;
397*30360Ssam 
398*30360Ssam 	case 'Z':
399*30360Ssam 		p = p->in.right;
400*30360Ssam 		switch (p->in.type) {
401*30360Ssam 		case SHORT: {
402*30360Ssam 			short w = p->tn.lval;
403*30360Ssam 			p->tn.lval = w;
404*30360Ssam 			break;
405*30360Ssam 		}
406*30360Ssam 		case CHAR: {
407*30360Ssam 			char c = p->tn.lval;
408*30360Ssam 			p->tn.lval = c;
409*30360Ssam 			break;
410*30360Ssam 		}
411*30360Ssam 		}
412*30360Ssam 		printf("$%d", p->tn.lval);
413*30360Ssam 		break;
414*30360Ssam 
41525977Ssam 	default:
41625977Ssam 		cerror( "illegal zzzcode" );
41725977Ssam 	}
418*30360Ssam }
41925828Ssam 
42025977Ssam #define	MOVB(dst, src, off) { \
42126162Ssam 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
42225977Ssam 	upput(dst, off); putchar('\n'); \
42325977Ssam }
42425977Ssam #define	MOVW(dst, src, off) { \
42526162Ssam 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
42625977Ssam 	upput(dst, off); putchar('\n'); \
42725977Ssam }
42825977Ssam #define	MOVL(dst, src, off) { \
42926162Ssam 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
43025977Ssam 	upput(dst, off); putchar('\n'); \
43125977Ssam }
43225977Ssam /*
43325977Ssam  * Generate code for a structure assignment.
43425977Ssam  */
43525977Ssam stasg(p)
43625977Ssam 	register NODE *p;
43725977Ssam {
43825977Ssam 	register NODE *l, *r;
43925977Ssam 	register int size;
44025828Ssam 
44125977Ssam 	switch (p->in.op) {
44225977Ssam 	case STASG:			/* regular assignment */
44325977Ssam 		l = p->in.left;
44425977Ssam 		r = p->in.right;
44525977Ssam 		break;
44625977Ssam 	case STARG:			/* place arg on the stack */
44725977Ssam 		l = getlr(p, '3');
44825977Ssam 		r = p->in.left;
44925977Ssam 		break;
45025977Ssam 	default:
45125977Ssam 		cerror("STASG bad");
45225977Ssam 		/*NOTREACHED*/
45325977Ssam 	}
45425977Ssam 	/*
45525977Ssam 	 * Pun source for use in code generation.
45625977Ssam 	 */
45725977Ssam 	switch (r->in.op) {
45825977Ssam 	case ICON:
45925977Ssam 		r->in.op = NAME;
46025977Ssam 		break;
46125977Ssam 	case REG:
46225977Ssam 		r->in.op = OREG;
46325977Ssam 		break;
46425977Ssam 	default:
46525977Ssam 		cerror( "STASG-r" );
46625977Ssam 		/*NOTREACHED*/
46725977Ssam 	}
46825977Ssam 	size = p->stn.stsize;
46925977Ssam 	if (size <= 0 || size > 65535)
47025977Ssam 		cerror("structure size out of range");
47125977Ssam 	/*
47225977Ssam 	 * Generate optimized code based on structure size
47325977Ssam 	 * and alignment properties....
47425977Ssam 	 */
47525977Ssam 	switch (size) {
47625828Ssam 
47725977Ssam 	case 1:
47826162Ssam 		putstr("\tmovb\t");
47925977Ssam 	optimized:
48025977Ssam 		adrput(r);
48126162Ssam 		putchar(',');
48225977Ssam 		adrput(l);
48326162Ssam 		putchar('\n');
48425977Ssam 		break;
48525828Ssam 
48625977Ssam 	case 2:
48725977Ssam 		if (p->stn.stalign != 2) {
48825977Ssam 			MOVB(l, r, SZCHAR);
48926162Ssam 			putstr("\tmovb\t");
49025977Ssam 		} else
49126162Ssam 			putstr("\tmovw\t");
49225977Ssam 		goto optimized;
49325977Ssam 
49425977Ssam 	case 4:
49525977Ssam 		if (p->stn.stalign != 4) {
49625977Ssam 			if (p->stn.stalign != 2) {
49725977Ssam 				MOVB(l, r, 3*SZCHAR);
49825977Ssam 				MOVB(l, r, 2*SZCHAR);
49925977Ssam 				MOVB(l, r, 1*SZCHAR);
50026162Ssam 				putstr("\tmovb\t");
50125947Ssam 			} else {
50225977Ssam 				MOVW(l, r, SZSHORT);
50326162Ssam 				putstr("\tmovw\t");
50425828Ssam 			}
50525977Ssam 		} else
50626162Ssam 			putstr("\tmovl\t");
50725977Ssam 		goto optimized;
50825828Ssam 
50925977Ssam 	case 6:
51025977Ssam 		if (p->stn.stalign != 2)
51125977Ssam 			goto movblk;
51225977Ssam 		MOVW(l, r, 2*SZSHORT);
51325977Ssam 		MOVW(l, r, 1*SZSHORT);
51426162Ssam 		putstr("\tmovw\t");
51525977Ssam 		goto optimized;
51625977Ssam 
51725977Ssam 	case 8:
51825977Ssam 		if (p->stn.stalign == 4) {
51925977Ssam 			MOVL(l, r, SZLONG);
52026162Ssam 			putstr("\tmovl\t");
52125977Ssam 			goto optimized;
52225977Ssam 		}
52325977Ssam 		/* fall thru...*/
52425977Ssam 
52525977Ssam 	default:
52625977Ssam 	movblk:
52725977Ssam 		/*
52825977Ssam 		 * Can we ever get a register conflict with R1 here?
52925977Ssam 		 */
53026162Ssam 		putstr("\tmovab\t");
53125977Ssam 		adrput(l);
53226162Ssam 		putstr(",r1\n\tmovab\t");
53325977Ssam 		adrput(r);
53425977Ssam 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
53525977Ssam 		rname(R2);
53625828Ssam 		break;
53725977Ssam 	}
53825977Ssam 	/*
53925977Ssam 	 * Reverse above pun for reclaim.
54025977Ssam 	 */
54125977Ssam 	if (r->in.op == NAME)
54225977Ssam 		r->in.op = ICON;
54325977Ssam 	else if (r->in.op == OREG)
54425977Ssam 		r->in.op = REG;
54525977Ssam }
54625828Ssam 
54725977Ssam /*
54825977Ssam  * Output the address of the second item in the
54925977Ssam  * pair pointed to by p.
55025977Ssam  */
55125977Ssam upput(p, size)
55225977Ssam 	register NODE *p;
55325977Ssam {
55425977Ssam 	CONSZ save;
55525977Ssam 
55625977Ssam 	if (p->in.op == FLD)
55725977Ssam 		p = p->in.left;
55825977Ssam 	switch (p->in.op) {
55925977Ssam 
56025977Ssam 	case NAME:
56125977Ssam 	case OREG:
56225977Ssam 		save = p->tn.lval;
56325977Ssam 		p->tn.lval += size/SZCHAR;
56425977Ssam 		adrput(p);
56525977Ssam 		p->tn.lval = save;
56625977Ssam 		break;
56725977Ssam 
56825977Ssam 	case REG:
56925977Ssam 		if (size == SZLONG) {
57026162Ssam 			putstr(rname(p->tn.rval+1));
57125977Ssam 			break;
57225977Ssam 		}
57325977Ssam 		/* fall thru... */
57425977Ssam 
57525828Ssam 	default:
57625977Ssam 		cerror("illegal upper address op %s size %d",
57725977Ssam 		    opst[p->tn.op], size);
57825977Ssam 		/*NOTREACHED*/
57925828Ssam 	}
58025977Ssam }
58125828Ssam 
582*30360Ssam /*
583*30360Ssam  * Generate code for storage conversions.
584*30360Ssam  */
585*30360Ssam sconv(p, forcc)
586*30360Ssam 	NODE *p;
587*30360Ssam {
588*30360Ssam 	register NODE *l, *r;
589*30360Ssam 	register wfrom, wto;
590*30360Ssam 	int oltype;
591*30360Ssam 
592*30360Ssam 	l = getlr(p, '1');
593*30360Ssam 	oltype = l->in.type, l->in.type = r->in.type;
594*30360Ssam 	r = getlr(p, 'L');
595*30360Ssam 	wfrom = tlen(r), wto = tlen(l);
596*30360Ssam 	if (wfrom == wto)		/* e.g. int -> unsigned */
597*30360Ssam 		goto done;
598*30360Ssam 	/*
599*30360Ssam 	 * Conversion in registers requires care
600*30360Ssam 	 * as cvt and movz instruction don't work
601*30360Ssam 	 * as expected (they end up as plain mov's).
602*30360Ssam 	 */
603*30360Ssam 	if (l->in.op == REG && r->in.op == REG) {
604*30360Ssam 		if (ISUNSIGNED(r->in.type)) {		/* unsigned, mask */
605*30360Ssam 			if (r->tn.lval != l->tn.lval) {
606*30360Ssam 				printf("\tandl3\t$%d,", (1<<(wto*SZCHAR))-1);
607*30360Ssam 				adrput(r);
608*30360Ssam 				putchar(',');
609*30360Ssam 			} else
610*30360Ssam 				printf("\tandl2\t$%d,", (1<<(wto*SZCHAR))-1);
611*30360Ssam 			adrput(l);
612*30360Ssam 		} else {				/* effect sign-extend */
613*30360Ssam 			int shift = (sizeof (int)-wto)*SZCHAR;
614*30360Ssam 			printf("\tshll\t$%d,", shift);
615*30360Ssam 			adrput(r); putchar(','); adrput(l);
616*30360Ssam 			printf("\n\tshar\t$%d,", shift);
617*30360Ssam 			adrput(l); putchar(','); adrput(l);
618*30360Ssam 			if (wfrom != sizeof (int)) {
619*30360Ssam 				/*
620*30360Ssam 				 * Must mask if result is shorter than
621*30360Ssam 				 * the width of a register (to account
622*30360Ssam 				 * for register treatment).
623*30360Ssam 				 */
624*30360Ssam 				printf("\n\tandl2\t$%d,",(1<<(wfrom*SZCHAR))-1);
625*30360Ssam 				adrput(l);
626*30360Ssam 			} else
627*30360Ssam 				forcc = 0;
628*30360Ssam 		}
629*30360Ssam 		/*
630*30360Ssam 		 * If condition codes are required and the last thing
631*30360Ssam 		 * we did was mask the result, then we must generate a
632*30360Ssam 		 * test of the appropriate type.
633*30360Ssam 		 */
634*30360Ssam 		if (forcc) {
635*30360Ssam 			printf("\n\tcmp");
636*30360Ssam 			prtype(l);
637*30360Ssam 			putchar('\t');
638*30360Ssam 			printf("$0,");
639*30360Ssam 			adrput(l);
640*30360Ssam 		}
641*30360Ssam 	} else {
642*30360Ssam 		/*
643*30360Ssam 		 * Conversion with at least one parameter in memory.
644*30360Ssam 		 */
645*30360Ssam 		if (wfrom < wto) {		/* expanding datum */
646*30360Ssam 			if (ISUNSIGNED(r->in.type)) {
647*30360Ssam 				printf("\tmovz");
648*30360Ssam 				prtype(r);
649*30360Ssam 				/*
650*30360Ssam 				 * If target is a register, generate
651*30360Ssam 				 * movz?l so optimizer can compress
652*30360Ssam 				 * argument pushes.
653*30360Ssam 				 */
654*30360Ssam 				if (l->in.op == REG)
655*30360Ssam 					putchar('l');
656*30360Ssam 				else
657*30360Ssam 					prtype(l);
658*30360Ssam 			} else {
659*30360Ssam 				printf("\tcvt");
660*30360Ssam 				prtype(r), prtype(l);
661*30360Ssam 			}
662*30360Ssam 			putchar('\t');
663*30360Ssam 			adrput(r);
664*30360Ssam 		} else {			/* shrinking dataum */
665*30360Ssam 			int off = wfrom - wto;
666*30360Ssam 			if (l->in.op == REG) {
667*30360Ssam 				printf("\tmovz");
668*30360Ssam 				prtype(l);
669*30360Ssam 				putchar('l');
670*30360Ssam 			} else {
671*30360Ssam 				printf("\tcvt");
672*30360Ssam 				prtype(l), prtype(r);
673*30360Ssam 			}
674*30360Ssam 			putchar('\t');
675*30360Ssam 			switch (r->in.op) {
676*30360Ssam 			case NAME: case OREG:
677*30360Ssam 				r->tn.lval += off;
678*30360Ssam 				adrput(r);
679*30360Ssam 				r->tn.lval -= off;
680*30360Ssam 				break;
681*30360Ssam 			case REG: case ICON: case UNARY MUL:
682*30360Ssam 				adrput(r);
683*30360Ssam 				break;
684*30360Ssam 			default:
685*30360Ssam 				cerror("sconv: bad shrink op");
686*30360Ssam 				/*NOTREACHED*/
687*30360Ssam 			}
688*30360Ssam 		}
689*30360Ssam 		putchar(',');
690*30360Ssam 		adrput(l);
691*30360Ssam 	}
692*30360Ssam 	putchar('\n');
693*30360Ssam done:
694*30360Ssam 	l->in.type = oltype;
695*30360Ssam }
696*30360Ssam 
69725828Ssam rmove( rt, rs, t ) TWORD t;{
69825828Ssam 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
69925828Ssam 	if(t==DOUBLE)
70025828Ssam 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
70125828Ssam 	}
70225828Ssam 
70325828Ssam struct respref
70425828Ssam respref[] = {
70525828Ssam 	INTAREG|INTBREG,	INTAREG|INTBREG,
70625828Ssam 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
70725828Ssam 	INTEMP,	INTEMP,
70825828Ssam 	FORARG,	FORARG,
70925828Ssam 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
71025828Ssam 	0,	0 };
71125828Ssam 
71225828Ssam setregs(){ /* set up temporary registers */
71325828Ssam 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
71425828Ssam 	}
71525828Ssam 
71626076Ssam #ifndef szty
71725828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
71825828Ssam 	return(t==DOUBLE ? 2 : 1 );
71925828Ssam 	}
72026076Ssam #endif
72125828Ssam 
72225828Ssam rewfld( p ) NODE *p; {
72325828Ssam 	return(1);
72425828Ssam 	}
72525828Ssam 
72625828Ssam callreg(p) NODE *p; {
72725828Ssam 	return( R0 );
72825828Ssam 	}
72925828Ssam 
73025828Ssam base( p ) register NODE *p; {
73125828Ssam 	register int o = p->in.op;
73225828Ssam 
73325828Ssam 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
73425828Ssam 	if( o==REG ) return( p->tn.rval );
73525828Ssam     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
73625828Ssam 		return( p->in.left->tn.rval );
73725828Ssam     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
73825828Ssam 		return( p->tn.rval + 0200*1 );
73925828Ssam 	return( -1 );
74025828Ssam 	}
74125828Ssam 
74225828Ssam offset( p, tyl ) register NODE *p; int tyl; {
74325828Ssam 
74425828Ssam 	if(tyl > 8) return( -1 );
74525828Ssam 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
74625828Ssam 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
74725828Ssam 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
74825828Ssam 	      && (1<<p->in.right->tn.lval)==tyl))
74925828Ssam 		return( p->in.left->tn.rval );
75025828Ssam 	return( -1 );
75125828Ssam 	}
75225828Ssam 
75325828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
75425828Ssam 	register NODE *t;
75525828Ssam 	register int i;
75625828Ssam 	NODE *f;
75725828Ssam 
75825828Ssam 	p->in.op = OREG;
75925828Ssam 	f = p->in.left; 	/* have to free this subtree later */
76025828Ssam 
76125828Ssam 	/* init base */
76225828Ssam 	switch (q->in.op) {
76325828Ssam 		case ICON:
76425828Ssam 		case REG:
76525828Ssam 		case OREG:
76625828Ssam 			t = q;
76725828Ssam 			break;
76825828Ssam 
76925828Ssam 		case MINUS:
77025828Ssam 			q->in.right->tn.lval = -q->in.right->tn.lval;
77125828Ssam 		case PLUS:
77225828Ssam 			t = q->in.right;
77325828Ssam 			break;
77425828Ssam 
77525828Ssam 		case UNARY MUL:
77625828Ssam 			t = q->in.left->in.left;
77725828Ssam 			break;
77825828Ssam 
77925828Ssam 		default:
78025828Ssam 			cerror("illegal makeor2");
78125828Ssam 	}
78225828Ssam 
78325828Ssam 	p->tn.lval = t->tn.lval;
78425828Ssam #ifndef FLEXNAMES
78525828Ssam 	for(i=0; i<NCHNAM; ++i)
78625828Ssam 		p->in.name[i] = t->in.name[i];
78725828Ssam #else
78825828Ssam 	p->in.name = t->in.name;
78925828Ssam #endif
79025828Ssam 
79125828Ssam 	/* init offset */
79225828Ssam 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
79325828Ssam 
79425828Ssam 	tfree(f);
79525828Ssam 	return;
79625828Ssam 	}
79725828Ssam 
79825828Ssam canaddr( p ) NODE *p; {
79925828Ssam 	register int o = p->in.op;
80025828Ssam 
80125828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
80225828Ssam 	return(0);
80325828Ssam 	}
80425828Ssam 
80526076Ssam #ifndef shltype
80625828Ssam shltype( o, p ) register NODE *p; {
80725828Ssam 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
80825828Ssam 	}
80926076Ssam #endif
81025828Ssam 
81125828Ssam flshape( p ) NODE *p; {
81225828Ssam 	register int o = p->in.op;
81325828Ssam 
81425828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
81525828Ssam 	return(0);
81625828Ssam 	}
81725828Ssam 
81825828Ssam shtemp( p ) register NODE *p; {
81925828Ssam 	if( p->in.op == STARG ) p = p->in.left;
82025828Ssam 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
82125828Ssam 	}
82225828Ssam 
82325828Ssam shumul( p ) register NODE *p; {
82425828Ssam 	register int o;
82525828Ssam 	extern int xdebug;
82625828Ssam 
82725828Ssam 	if (xdebug) {
82825828Ssam 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
82925828Ssam 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
83025828Ssam 		}
83125828Ssam 
83225828Ssam 	o = p->in.op;
83325828Ssam 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
83425828Ssam 	 && p->in.type != PTR+DOUBLE)
83525828Ssam 		return( STARNM );
83625828Ssam 
83725828Ssam 	return( 0 );
83825828Ssam 	}
83925828Ssam 
84025828Ssam special( p, shape ) register NODE *p; {
84125828Ssam 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
84225828Ssam 	else return(0);
84325828Ssam }
84425828Ssam 
84525828Ssam adrcon( val ) CONSZ val; {
84625947Ssam 	printf(ACONFMT, val);
84725828Ssam 	}
84825828Ssam 
84925828Ssam conput( p ) register NODE *p; {
85025828Ssam 	switch( p->in.op ){
85125828Ssam 
85225828Ssam 	case ICON:
85325828Ssam 		acon( p );
85425828Ssam 		return;
85525828Ssam 
85625828Ssam 	case REG:
85726162Ssam 		putstr(rname(p->tn.rval));
85825828Ssam 		return;
85925828Ssam 
86025828Ssam 	default:
86125828Ssam 		cerror( "illegal conput" );
86225828Ssam 		}
86325828Ssam 	}
86425828Ssam 
86525828Ssam insput( p ) NODE *p; {
86625828Ssam 	cerror( "insput" );
86725828Ssam 	}
86825828Ssam 
86925828Ssam adrput( p ) register NODE *p; {
87025828Ssam 	register int r;
87125828Ssam 	/* output an address, with offsets, from p */
87225828Ssam 
87325828Ssam 	if( p->in.op == FLD ){
87425828Ssam 		p = p->in.left;
87525828Ssam 		}
87625828Ssam 	switch( p->in.op ){
87725828Ssam 
87825828Ssam 	case NAME:
87925828Ssam 		acon( p );
88025828Ssam 		return;
88125828Ssam 
88225828Ssam 	case ICON:
88325828Ssam 		/* addressable value of the constant */
88426162Ssam 		putchar('$');
88525828Ssam 		acon( p );
88625828Ssam 		return;
88725828Ssam 
88825828Ssam 	case REG:
88926162Ssam 		putstr(rname(p->tn.rval));
89025828Ssam 		if(p->in.type == DOUBLE)	/* for entry mask */
89125828Ssam 			(void) rname(p->tn.rval+1);
89225828Ssam 		return;
89325828Ssam 
89425828Ssam 	case OREG:
89525828Ssam 		r = p->tn.rval;
89625828Ssam 		if( R2TEST(r) ){ /* double indexing */
89725828Ssam 			register int flags;
89825828Ssam 
89925828Ssam 			flags = R2UPK3(r);
90026162Ssam 			if( flags & 1 ) putchar('*');
90125828Ssam 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
90225828Ssam 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
90325828Ssam 			printf( "[%s]", rname(R2UPK2(r)) );
90425828Ssam 			return;
90525828Ssam 			}
90625828Ssam 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
90725828Ssam 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
90825828Ssam 			printf( CONFMT, p->tn.lval );
90926162Ssam 			putstr( "(fp)" );
91025828Ssam 			return;
91125828Ssam 			}
91225828Ssam 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
91325828Ssam 		printf( "(%s)", rname(p->tn.rval) );
91425828Ssam 		return;
91525828Ssam 
91625828Ssam 	case UNARY MUL:
91725828Ssam 		/* STARNM or STARREG found */
91825828Ssam 		if( tshape(p, STARNM) ) {
91926162Ssam 			putchar( '*' );
92025828Ssam 			adrput( p->in.left);
92125828Ssam 			}
92225828Ssam 		return;
92325828Ssam 
92425828Ssam 	default:
92525828Ssam 		cerror( "illegal address" );
92625828Ssam 		return;
92725828Ssam 
92825828Ssam 		}
92925828Ssam 
93025828Ssam 	}
93125828Ssam 
93225828Ssam acon( p ) register NODE *p; { /* print out a constant */
93325828Ssam 
93425828Ssam 	if( p->in.name[0] == '\0' ){
93525828Ssam 		printf( CONFMT, p->tn.lval);
93626162Ssam 		return;
93726162Ssam 	} else {
93825828Ssam #ifndef FLEXNAMES
93925828Ssam 		printf( "%.8s", p->in.name );
94025828Ssam #else
94126162Ssam 		putstr(p->in.name);
94225828Ssam #endif
94326162Ssam 		if (p->tn.lval != 0) {
94426162Ssam 			putchar('+');
94526162Ssam 			printf(CONFMT, p->tn.lval);
94625828Ssam 		}
94725828Ssam 	}
94826162Ssam 	}
94925828Ssam 
95025828Ssam genscall( p, cookie ) register NODE *p; {
95125828Ssam 	/* structure valued call */
95225828Ssam 	return( gencall( p, cookie ) );
95325828Ssam 	}
95425828Ssam 
95525828Ssam genfcall( p, cookie ) register NODE *p; {
95625828Ssam 	register NODE *p1;
95725828Ssam 	register int m;
95825828Ssam 	static char *funcops[6] = {
95925828Ssam 		"sin", "cos", "sqrt", "exp", "log", "atan"
96025828Ssam 	};
96125828Ssam 
96225828Ssam 	/* generate function opcodes */
96325828Ssam 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
96425828Ssam 	 (p1 = p->in.left)->in.op==ICON &&
96525828Ssam 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
96625828Ssam #ifdef FLEXNAMES
96725828Ssam 		p1->in.name++;
96825828Ssam #else
96925828Ssam 		strcpy(p1->in.name, p1->in.name[1]);
97025828Ssam #endif
97125828Ssam 		for(m=0; m<6; m++)
97225828Ssam 			if(!strcmp(p1->in.name, funcops[m]))
97325828Ssam 				break;
97425828Ssam 		if(m >= 6)
97525828Ssam 			uerror("no opcode for fortarn function %s", p1->in.name);
97625828Ssam 	} else
97725828Ssam 		uerror("illegal type of fortarn function");
97825828Ssam 	p1 = p->in.right;
97925828Ssam 	p->in.op = FORTCALL;
98025828Ssam 	if(!canaddr(p1))
98125828Ssam 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
98225828Ssam 	m = match( p, INTAREG|INTBREG );
98325828Ssam 	return(m != MDONE);
98425828Ssam }
98525828Ssam 
98625828Ssam /* tbl */
98725828Ssam int gc_numbytes;
98825828Ssam /* tbl */
98925828Ssam 
99025828Ssam gencall( p, cookie ) register NODE *p; {
99125828Ssam 	/* generate the call given by p */
99225828Ssam 	register NODE *p1, *ptemp;
99325828Ssam 	register int temp, temp1;
99425828Ssam 	register int m;
99525828Ssam 
99625828Ssam 	if( p->in.right ) temp = argsize( p->in.right );
99725828Ssam 	else temp = 0;
99825828Ssam 
99925828Ssam 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
100025828Ssam 		/* set aside room for structure return */
100125828Ssam 
100225828Ssam 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
100325828Ssam 		else temp1 = temp;
100425828Ssam 		}
100525828Ssam 
100625828Ssam 	if( temp > maxargs ) maxargs = temp;
100725828Ssam 	SETOFF(temp1,4);
100825828Ssam 
100925828Ssam 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
101025828Ssam 		ptemp = talloc();
101125828Ssam 		ptemp->in.op = OREG;
101225828Ssam 		ptemp->tn.lval = -1;
101325828Ssam 		ptemp->tn.rval = SP;
101425828Ssam #ifndef FLEXNAMES
101525828Ssam 		ptemp->in.name[0] = '\0';
101625828Ssam #else
101725828Ssam 		ptemp->in.name = "";
101825828Ssam #endif
101925828Ssam 		ptemp->in.rall = NOPREF;
102025828Ssam 		ptemp->in.su = 0;
102125828Ssam 		genargs( p->in.right, ptemp );
102225828Ssam 		ptemp->in.op = FREE;
102325828Ssam 		}
102425828Ssam 
102525828Ssam 	p1 = p->in.left;
102625828Ssam 	if( p1->in.op != ICON ){
102725828Ssam 		if( p1->in.op != REG ){
102825828Ssam 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
102925828Ssam 				if( p1->in.op != NAME ){
103025828Ssam 					order( p1, INAREG );
103125828Ssam 					}
103225828Ssam 				}
103325828Ssam 			}
103425828Ssam 		}
103525828Ssam 
103625828Ssam /* tbl
103725828Ssam 	setup gc_numbytes so reference to ZC works */
103825828Ssam 
103925828Ssam 	gc_numbytes = temp&(0x3ff);
104025828Ssam 
104125828Ssam 	p->in.op = UNARY CALL;
104225828Ssam 	m = match( p, INTAREG|INTBREG );
104325828Ssam 
104425828Ssam 	return(m != MDONE);
104525828Ssam 	}
104625828Ssam 
104725828Ssam /* tbl */
104825828Ssam char *
104925828Ssam ccbranches[] = {
105025828Ssam 	"eql",
105125828Ssam 	"neq",
105225828Ssam 	"leq",
105325828Ssam 	"lss",
105425828Ssam 	"geq",
105525828Ssam 	"gtr",
105625828Ssam 	"lequ",
105725828Ssam 	"lssu",
105825828Ssam 	"gequ",
105925828Ssam 	"gtru",
106025828Ssam 	};
106125828Ssam /* tbl */
106225828Ssam 
106325828Ssam cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
106425828Ssam 
106525828Ssam 		if(o != 0 && (o < EQ || o > UGT ))
106625828Ssam 			cerror( "bad conditional branch: %s", opst[o] );
106725828Ssam 		printf( "	j%s	L%d\n",
106825828Ssam 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
106925828Ssam 	}
107025828Ssam 
107125828Ssam nextcook( p, cookie ) NODE *p; {
107225828Ssam 	/* we have failed to match p with cookie; try another */
107325828Ssam 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
107425828Ssam 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
107525828Ssam 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
107625828Ssam 	return( FORREW );
107725828Ssam 	}
107825828Ssam 
107925828Ssam lastchance( p, cook ) NODE *p; {
108025828Ssam 	/* forget it! */
108125828Ssam 	return(0);
108225828Ssam 	}
108325828Ssam 
108425828Ssam optim2( p ) register NODE *p; {
108525828Ssam # ifdef ONEPASS
108625828Ssam 	/* do local tree transformations and optimizations */
108725828Ssam # define RV(p) p->in.right->tn.lval
108826076Ssam # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
1089*30360Ssam 	register int o, i;
1090*30360Ssam 	register NODE *l, *r;
109125828Ssam 
1092*30360Ssam 	switch (o = p->in.op) {
1093*30360Ssam 
1094*30360Ssam 	case DIV: case ASG DIV:
1095*30360Ssam 	case MOD: case ASG MOD:
1096*30360Ssam 		/*
1097*30360Ssam 		 * Change unsigned mods and divs to
1098*30360Ssam 		 * logicals (mul is done in mip & c2)
1099*30360Ssam 		 */
1100*30360Ssam 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1101*30360Ssam 		    (i = ispow2(RV(p))) >= 0) {
1102*30360Ssam 			if (o == DIV || o == ASG DIV) {
1103*30360Ssam 				p->in.op = RS;
1104*30360Ssam 				RV(p) = i;
1105*30360Ssam 			} else {
1106*30360Ssam 				p->in.op = AND;
1107*30360Ssam 				RV(p)--;
1108*30360Ssam 			}
1109*30360Ssam 			if (asgop(o))
1110*30360Ssam 				p->in.op = ASG p->in.op;
111125828Ssam 		}
1112*30360Ssam 		return;
1113*30360Ssam 
1114*30360Ssam 	case SCONV:
1115*30360Ssam 		l = p->in.left;
1116*30360Ssam 		/* clobber conversions w/o side effects */
1117*30360Ssam 		if (!anyfloat(p, l) && l->in.op != PCONV &&
1118*30360Ssam 		    tlen(p) == tlen(l)) {
1119*30360Ssam 			if (l->in.op != FLD)
1120*30360Ssam 				l->in.type = p->in.type;
1121*30360Ssam 			ncopy(p, l);
1122*30360Ssam 			l->in.op = FREE;
1123*30360Ssam 		}
1124*30360Ssam 		return;
1125*30360Ssam 
1126*30360Ssam 	case ASSIGN:
1127*30360Ssam 		/*
1128*30360Ssam 		 * Try to zap storage conversions of non-float items.
1129*30360Ssam 		 */
1130*30360Ssam 		r = p->in.right;
1131*30360Ssam 		if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
1132*30360Ssam 			int wdest, wconv, wsrc;
1133*30360Ssam 			wdest = tlen(p->in.left);
1134*30360Ssam 			wconv = tlen(r);
1135*30360Ssam 			/*
1136*30360Ssam 			 * If size doesn't change across assignment or
1137*30360Ssam 			 * conversion expands src before shrinking again
1138*30360Ssam 			 * due to the assignment, delete conversion so
1139*30360Ssam 			 * code generator can create optimal code.
1140*30360Ssam 			 */
1141*30360Ssam 			if (wdest == wconv ||
1142*30360Ssam 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1143*30360Ssam 				p->in.right = r->in.left;
1144*30360Ssam 				r->in.op = FREE;
1145*30360Ssam 			}
1146*30360Ssam 		}
1147*30360Ssam 		return;
114825828Ssam 	}
114925828Ssam # endif
115025828Ssam }
115125828Ssam 
115225828Ssam struct functbl {
115325828Ssam 	int fop;
115425828Ssam 	char *func;
115525828Ssam } opfunc[] = {
115625828Ssam 	DIV,		"udiv",
115725828Ssam 	ASG DIV,	"udiv",
115825828Ssam 	0
115925828Ssam };
116025828Ssam 
116125828Ssam hardops(p)  register NODE *p; {
116225828Ssam 	/* change hard to do operators into function calls.  */
116325828Ssam 	register NODE *q;
116425828Ssam 	register struct functbl *f;
116525828Ssam 	register int o;
116625828Ssam 	register TWORD t, t1, t2;
116725828Ssam 
116825828Ssam 	o = p->in.op;
116925828Ssam 
117025828Ssam 	for( f=opfunc; f->fop; f++ ) {
117125828Ssam 		if( o==f->fop ) goto convert;
117225828Ssam 	}
117325828Ssam 	return;
117425828Ssam 
117525828Ssam 	convert:
117625828Ssam 	t = p->in.type;
117725828Ssam 	t1 = p->in.left->in.type;
117825828Ssam 	t2 = p->in.right->in.type;
117925828Ssam 
118029672Ssam 	if (!((ISUNSIGNED(t1) && !(ISUNSIGNED(t2))) ||
118129672Ssam 	     ( t2 == UNSIGNED))) return;
118229672Ssam 
118325828Ssam 	/* need to rewrite tree for ASG OP */
118425828Ssam 	/* must change ASG OP to a simple OP */
118525828Ssam 	if( asgop( o ) ) {
118625828Ssam 		q = talloc();
118725828Ssam 		q->in.op = NOASG ( o );
118825828Ssam 		q->in.rall = NOPREF;
118925828Ssam 		q->in.type = p->in.type;
119025828Ssam 		q->in.left = tcopy(p->in.left);
119125828Ssam 		q->in.right = p->in.right;
119225828Ssam 		p->in.op = ASSIGN;
119325828Ssam 		p->in.right = q;
119425828Ssam 		zappost(q->in.left); /* remove post-INCR(DECR) from new node */
119525828Ssam 		fixpre(q->in.left);	/* change pre-INCR(DECR) to +/-	*/
119625828Ssam 		p = q;
119725828Ssam 
119825828Ssam 	}
119925828Ssam 	/* turn logicals to compare 0 */
120025828Ssam 	else if( logop( o ) ) {
120125828Ssam 		ncopy(q = talloc(), p);
120225828Ssam 		p->in.left = q;
120325828Ssam 		p->in.right = q = talloc();
120425828Ssam 		q->in.op = ICON;
120525828Ssam 		q->in.type = INT;
120625828Ssam #ifndef FLEXNAMES
120725828Ssam 		q->in.name[0] = '\0';
120825828Ssam #else
120925828Ssam 		q->in.name = "";
121025828Ssam #endif
121125828Ssam 		q->tn.lval = 0;
121225828Ssam 		q->tn.rval = 0;
121325828Ssam 		p = p->in.left;
121425828Ssam 	}
121525828Ssam 
121625828Ssam 	/* build comma op for args to function */
121725828Ssam 	t1 = p->in.left->in.type;
121825828Ssam 	t2 = 0;
121925828Ssam 	if ( optype(p->in.op) == BITYPE) {
122025828Ssam 		q = talloc();
122125828Ssam 		q->in.op = CM;
122225828Ssam 		q->in.rall = NOPREF;
122325828Ssam 		q->in.type = INT;
122425828Ssam 		q->in.left = p->in.left;
122525828Ssam 		q->in.right = p->in.right;
122625828Ssam 		t2 = p->in.right->in.type;
122725828Ssam 	} else
122825828Ssam 		q = p->in.left;
122925828Ssam 
123025828Ssam 	p->in.op = CALL;
123125828Ssam 	p->in.right = q;
123225828Ssam 
123325828Ssam 	/* put function name in left node of call */
123425828Ssam 	p->in.left = q = talloc();
123525828Ssam 	q->in.op = ICON;
123625828Ssam 	q->in.rall = NOPREF;
123725828Ssam 	q->in.type = INCREF( FTN + p->in.type );
123825828Ssam #ifndef FLEXNAMES
123925828Ssam 		strcpy( q->in.name, f->func );
124025828Ssam #else
124125828Ssam 		q->in.name = f->func;
124225828Ssam #endif
124325828Ssam 	q->tn.lval = 0;
124425828Ssam 	q->tn.rval = 0;
124525828Ssam 
124625828Ssam 	}
124725828Ssam 
124825828Ssam zappost(p) NODE *p; {
124925828Ssam 	/* look for ++ and -- operators and remove them */
125025828Ssam 
125125828Ssam 	register int o, ty;
125225828Ssam 	register NODE *q;
125325828Ssam 	o = p->in.op;
125425828Ssam 	ty = optype( o );
125525828Ssam 
125625828Ssam 	switch( o ){
125725828Ssam 
125825828Ssam 	case INCR:
125925828Ssam 	case DECR:
126025828Ssam 			q = p->in.left;
126125828Ssam 			p->in.right->in.op = FREE;  /* zap constant */
126225828Ssam 			ncopy( p, q );
126325828Ssam 			q->in.op = FREE;
126425828Ssam 			return;
126525828Ssam 
126625828Ssam 		}
126725828Ssam 
126825828Ssam 	if( ty == BITYPE ) zappost( p->in.right );
126925828Ssam 	if( ty != LTYPE ) zappost( p->in.left );
127025828Ssam }
127125828Ssam 
127225828Ssam fixpre(p) NODE *p; {
127325828Ssam 
127425828Ssam 	register int o, ty;
127525828Ssam 	o = p->in.op;
127625828Ssam 	ty = optype( o );
127725828Ssam 
127825828Ssam 	switch( o ){
127925828Ssam 
128025828Ssam 	case ASG PLUS:
128125828Ssam 			p->in.op = PLUS;
128225828Ssam 			break;
128325828Ssam 	case ASG MINUS:
128425828Ssam 			p->in.op = MINUS;
128525828Ssam 			break;
128625828Ssam 		}
128725828Ssam 
128825828Ssam 	if( ty == BITYPE ) fixpre( p->in.right );
128925828Ssam 	if( ty != LTYPE ) fixpre( p->in.left );
129025828Ssam }
129125828Ssam 
129225828Ssam NODE * addroreg(l) NODE *l;
129325828Ssam 				/* OREG was built in clocal()
129425828Ssam 				 * for an auto or formal parameter
129525828Ssam 				 * now its address is being taken
129625828Ssam 				 * local code must unwind it
129725828Ssam 				 * back to PLUS/MINUS REG ICON
129825828Ssam 				 * according to local conventions
129925828Ssam 				 */
130025828Ssam {
130125828Ssam 	cerror("address of OREG taken");
130225828Ssam }
130325828Ssam 
130425828Ssam # ifndef ONEPASS
130525828Ssam main( argc, argv ) char *argv[]; {
130625828Ssam 	return( mainp2( argc, argv ) );
130725828Ssam 	}
130825828Ssam # endif
130925828Ssam 
1310*30360Ssam strip(p) register NODE *p; {
1311*30360Ssam 	NODE *q;
1312*30360Ssam 
1313*30360Ssam 	/* strip nodes off the top when no side effects occur */
1314*30360Ssam 	for( ; ; ) {
1315*30360Ssam 		switch( p->in.op ) {
1316*30360Ssam 		case SCONV:			/* remove lint tidbits */
1317*30360Ssam 			q = p->in.left;
1318*30360Ssam 			ncopy( p, q );
1319*30360Ssam 			q->in.op = FREE;
1320*30360Ssam 			break;
1321*30360Ssam 		/* could probably add a few more here */
1322*30360Ssam 		default:
1323*30360Ssam 			return;
1324*30360Ssam 			}
1325*30360Ssam 		}
1326*30360Ssam 	}
1327*30360Ssam 
132825828Ssam myreader(p) register NODE *p; {
1329*30360Ssam 	strip( p );		/* strip off operations with no side effects */
133025828Ssam 	walkf( p, hardops );	/* convert ops to function calls */
133125828Ssam 	canon( p );		/* expands r-vals for fileds */
133225828Ssam 	walkf( p, optim2 );
133325828Ssam 	}
1334