xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32879)
125828Ssam #ifndef lint
2*32879Sdonn static char sccsid[] = "@(#)local2.c	1.17 (Berkeley) 12/10/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 
13530360Ssam anyfloat(p, q)
13630360Ssam 	NODE *p, *q;
13730360Ssam {
13830360Ssam 	register TWORD tp, tq;
13930360Ssam 
14030360Ssam 	tp = p->in.type;
14130360Ssam 	tq = q->in.type;
14230360Ssam 	return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
14330360Ssam }
14430360Ssam 
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 
19932876Sdonn 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
20025828Ssam 		{
20132876Sdonn 		register NODE *l, *r, *s;
20232876Sdonn 		int lt, rt;
20325828Ssam 
20432876Sdonn 		l = p->in.left;
20532876Sdonn 		r = p->in.right;
20632876Sdonn 		s = talloc();
20732876Sdonn 		rt = r->in.type;
20832876Sdonn 		lt = l->in.type;
20925828Ssam 
21032876Sdonn 		if (lt != INT && lt != UNSIGNED) {
21132876Sdonn 			s->in.op = SCONV;
21232876Sdonn 			s->in.left = l;
21332876Sdonn 			s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
21432876Sdonn 			zzzcode(s, 'U');
21532876Sdonn 			putstr("\n\t");
21625828Ssam 		}
21732876Sdonn 
21832876Sdonn 		if (ISUNSIGNED(lt)) {
21932876Sdonn 			s->in.op = SCONV;
22032876Sdonn 			s->in.left = lt == UNSIGNED ? l : resc;
22132876Sdonn 			s->in.type = rt;
22232876Sdonn 			unsigned_to_float(s);
22332876Sdonn 		} else {
22432876Sdonn 			putstr("cvl");
22532876Sdonn 			prtype(r);
22632876Sdonn 			putchar('\t');
22732876Sdonn 			adrput(lt == INT ? l : resc);
22832876Sdonn 		}
22932876Sdonn 		putstr("\n\t");
23032876Sdonn 
23132876Sdonn 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
23226162Ssam 		putchar('\t');
23325828Ssam 		adrput(r);
23432876Sdonn 
23532876Sdonn 		if (ISUNSIGNED(lt)) {
23632876Sdonn 			putstr("\n\t");
23732876Sdonn 			s->in.op = SCONV;
23832876Sdonn 			s->in.left = r;		/* we need only the type */
23932876Sdonn 			s->in.type = UNSIGNED;
24032876Sdonn 			float_to_unsigned(s);
24132876Sdonn 		} else {
24232876Sdonn 			putstr("\n\tcv");
24332876Sdonn 			prtype(r);
24432876Sdonn 			putstr("l\t");
24532876Sdonn 			if (lt == INT)
24632876Sdonn 				adrput(l);
24732876Sdonn 			else
24832876Sdonn 				adrput(resc);
24932876Sdonn 		}
25032876Sdonn 		if (lt != INT) {
25132876Sdonn 			putstr("\n\t");
25232876Sdonn 			s->in.op = ASSIGN;
25332876Sdonn 			s->in.left = l;
25432876Sdonn 			s->in.right = resc;
25532876Sdonn 			s->in.type = lt;
25632876Sdonn 			zzzcode(s, 'U');
25732876Sdonn 		}
25832876Sdonn 
25932876Sdonn 		s->in.op = FREE;
26025828Ssam 		return;
26125828Ssam 		}
26225828Ssam 
26325828Ssam 	case 'B':	/* get oreg value in temp register for shift */
26425828Ssam 		{
26525828Ssam 		register NODE *r;
26625828Ssam 		if (xdebug) eprint(p, 0, &val, &val);
26725828Ssam 		r = p->in.right;
26825828Ssam 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
26926162Ssam 			putstr("movl");
27025828Ssam 		else {
27126162Ssam 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
27225828Ssam 			prtype(r);
27326162Ssam 			putchar('l');
27425828Ssam 			}
27525828Ssam 		return;
27625828Ssam 		}
27725828Ssam 
27825828Ssam 	case 'C':	/* num bytes pushed on arg stack */
27925828Ssam 		{
28025828Ssam 		extern int gc_numbytes;
28125828Ssam 		extern int xdebug;
28225828Ssam 
28325828Ssam 		if (xdebug) printf("->%d<-",gc_numbytes);
28425828Ssam 
28525828Ssam 		printf("call%c	$%d",
28625828Ssam 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
28725828Ssam 		 gc_numbytes+4);
28825828Ssam 		/* dont change to double (here's the only place to catch it) */
28925828Ssam 		if(p->in.type == FLOAT)
29025828Ssam 			rtyflg = 1;
29125828Ssam 		return;
29225828Ssam 		}
29325828Ssam 
29425828Ssam 	case 'D':	/* INCR and DECR */
29532876Sdonn 		zzzcode(p->in.left, 'U');
29626162Ssam 		putstr("\n	");
29725828Ssam 
29825828Ssam 	case 'E':	/* INCR and DECR, FOREFF */
29925828Ssam  		if (p->in.right->tn.lval == 1)
30025828Ssam 			{
30126162Ssam 			putstr(p->in.op == INCR ? "inc" : "dec");
30225828Ssam 			prtype(p->in.left);
30326162Ssam 			putchar('\t');
30425828Ssam 			adrput(p->in.left);
30525828Ssam 			return;
30625828Ssam 			}
30726162Ssam 		putstr(p->in.op == INCR ? "add" : "sub");
30825828Ssam 		prtype(p->in.left);
30926162Ssam 		putstr("2	");
31025828Ssam 		adrput(p->in.right);
31126162Ssam 		putchar(',');
31225828Ssam 		adrput(p->in.left);
31325828Ssam 		return;
31425828Ssam 
31525828Ssam 	case 'F':	/* masked constant for fields */
31625947Ssam 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
31725828Ssam 		return;
31825828Ssam 
31925828Ssam 	case 'H':	/* opcode for shift */
32025828Ssam 		if(p->in.op == LS || p->in.op == ASG LS)
32126162Ssam 			putstr("shll");
32225828Ssam 		else if(ISUNSIGNED(p->in.left->in.type))
32326162Ssam 			putstr("shrl");
32425828Ssam 		else
32526162Ssam 			putstr("shar");
32625828Ssam 		return;
32725828Ssam 
32825828Ssam 	case 'L':	/* type of left operand */
32925828Ssam 	case 'R':	/* type of right operand */
33025828Ssam 		{
33125828Ssam 		register NODE *n;
33225828Ssam 		extern int xdebug;
33325828Ssam 
33425828Ssam 		n = getlr ( p, c);
33525828Ssam 		if (xdebug) printf("->%d<-", n->in.type);
33625828Ssam 
33725828Ssam 		prtype(n);
33825828Ssam 		return;
33925828Ssam 		}
34025828Ssam 
34130360Ssam 	case 'M': {  /* initiate ediv for mod and unsigned div */
34225828Ssam 		register char *r;
34325828Ssam 		m = getlr(p, '1')->tn.rval;
34425828Ssam 		r = rname(m);
34525828Ssam 		printf("\tclrl\t%s\n\tmovl\t", r);
34625828Ssam 		adrput(p->in.left);
34725828Ssam 		printf(",%s\n", rname(m+1));
34825828Ssam 		if(!ISUNSIGNED(p->in.type)) { 	/* should be MOD */
34925828Ssam 			m = getlab();
35025828Ssam 			printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
35125828Ssam 			deflab(m);
35225828Ssam 		}
35325828Ssam 		return;
35430360Ssam 	}
35525828Ssam 
35630360Ssam 	case 'T': {	/* rounded structure length for arguments */
35730360Ssam 		int size = p->stn.stsize;
35825828Ssam 		SETOFF( size, 4);
35925828Ssam 		printf("movab	-%d(sp),sp", size);
36025828Ssam 		return;
36130360Ssam 	}
36225828Ssam 
36325828Ssam 	case 'S':  /* structure assignment */
36425977Ssam 		stasg(p);
36525977Ssam 		break;
36625828Ssam 
36729672Ssam 	case 'X':	/* multiplication for short and char */
36829672Ssam 		if (ISUNSIGNED(p->in.left->in.type))
36929672Ssam 			printf("\tmovz");
37029672Ssam 		else
37129672Ssam 			printf("\tcvt");
37229672Ssam 		zzzcode(p, 'L');
37329672Ssam 		printf("l\t");
37429672Ssam 		adrput(p->in.left);
37529672Ssam 		printf(",");
37629672Ssam 		adrput(&resc[0]);
37729672Ssam 		printf("\n");
37829672Ssam 		if (ISUNSIGNED(p->in.right->in.type))
37929672Ssam 			printf("\tmovz");
38029672Ssam 		else
38129672Ssam 			printf("\tcvt");
38229672Ssam 		zzzcode(p, 'R');
38329672Ssam 		printf("l\t");
38429672Ssam 		adrput(p->in.right);
38529672Ssam 		printf(",");
38629672Ssam 		adrput(&resc[1]);
38729672Ssam 		printf("\n");
38829672Ssam 		return;
38929672Ssam 
39030360Ssam 	case 'U':		/* SCONV */
39130360Ssam 	case 'V':		/* SCONV with FORCC */
39230360Ssam 		sconv(p, c == 'V');
39330360Ssam 		break;
39430360Ssam 
395*32879Sdonn 	case 'W': {		/* SCONV or ASSIGN float/double => unsigned */
396*32879Sdonn 		NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
397*32879Sdonn 
39832876Sdonn 		putstr("ld");
399*32879Sdonn 		prtype(src);
40032876Sdonn 		putchar('\t');
401*32879Sdonn 		adrput(src);
40232876Sdonn 		putstr("\n\t");
40332876Sdonn 		float_to_unsigned(p);
40432876Sdonn 		break;
405*32879Sdonn 	}
40632876Sdonn 
407*32879Sdonn 	case 'Y':		/* SCONV or ASSIGN unsigned => float/double */
40832876Sdonn 		unsigned_to_float(p);	/* stores into accumulator */
40932876Sdonn 		putstr("\n\tst");
41032876Sdonn 		prtype(p);
41132876Sdonn 		putchar('\t');
412*32879Sdonn 		if (p->in.op == SCONV)
413*32879Sdonn 			adrput(resc);
414*32879Sdonn 		else
415*32879Sdonn 			adrput(p->in.left);
416*32879Sdonn 		rtyflg = 1;
41732876Sdonn 		break;
41832876Sdonn 
41930360Ssam 	case 'Z':
42030360Ssam 		p = p->in.right;
42130360Ssam 		switch (p->in.type) {
42230360Ssam 		case SHORT: {
42330360Ssam 			short w = p->tn.lval;
42430360Ssam 			p->tn.lval = w;
42530360Ssam 			break;
42630360Ssam 		}
42730360Ssam 		case CHAR: {
42830360Ssam 			char c = p->tn.lval;
42930360Ssam 			p->tn.lval = c;
43030360Ssam 			break;
43130360Ssam 		}
43230360Ssam 		}
43330360Ssam 		printf("$%d", p->tn.lval);
43430360Ssam 		break;
43530360Ssam 
43625977Ssam 	default:
43725977Ssam 		cerror( "illegal zzzcode" );
43825977Ssam 	}
43930360Ssam }
44025828Ssam 
44125977Ssam #define	MOVB(dst, src, off) { \
44226162Ssam 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
44325977Ssam 	upput(dst, off); putchar('\n'); \
44425977Ssam }
44525977Ssam #define	MOVW(dst, src, off) { \
44626162Ssam 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
44725977Ssam 	upput(dst, off); putchar('\n'); \
44825977Ssam }
44925977Ssam #define	MOVL(dst, src, off) { \
45026162Ssam 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
45125977Ssam 	upput(dst, off); putchar('\n'); \
45225977Ssam }
45325977Ssam /*
45425977Ssam  * Generate code for a structure assignment.
45525977Ssam  */
45625977Ssam stasg(p)
45725977Ssam 	register NODE *p;
45825977Ssam {
45925977Ssam 	register NODE *l, *r;
46025977Ssam 	register int size;
46125828Ssam 
46225977Ssam 	switch (p->in.op) {
46325977Ssam 	case STASG:			/* regular assignment */
46425977Ssam 		l = p->in.left;
46525977Ssam 		r = p->in.right;
46625977Ssam 		break;
46725977Ssam 	case STARG:			/* place arg on the stack */
46825977Ssam 		l = getlr(p, '3');
46925977Ssam 		r = p->in.left;
47025977Ssam 		break;
47125977Ssam 	default:
47225977Ssam 		cerror("STASG bad");
47325977Ssam 		/*NOTREACHED*/
47425977Ssam 	}
47525977Ssam 	/*
47625977Ssam 	 * Pun source for use in code generation.
47725977Ssam 	 */
47825977Ssam 	switch (r->in.op) {
47925977Ssam 	case ICON:
48025977Ssam 		r->in.op = NAME;
48125977Ssam 		break;
48225977Ssam 	case REG:
48325977Ssam 		r->in.op = OREG;
48425977Ssam 		break;
48525977Ssam 	default:
48625977Ssam 		cerror( "STASG-r" );
48725977Ssam 		/*NOTREACHED*/
48825977Ssam 	}
48925977Ssam 	size = p->stn.stsize;
49025977Ssam 	if (size <= 0 || size > 65535)
49125977Ssam 		cerror("structure size out of range");
49225977Ssam 	/*
49325977Ssam 	 * Generate optimized code based on structure size
49425977Ssam 	 * and alignment properties....
49525977Ssam 	 */
49625977Ssam 	switch (size) {
49725828Ssam 
49825977Ssam 	case 1:
49926162Ssam 		putstr("\tmovb\t");
50025977Ssam 	optimized:
50125977Ssam 		adrput(r);
50226162Ssam 		putchar(',');
50325977Ssam 		adrput(l);
50426162Ssam 		putchar('\n');
50525977Ssam 		break;
50625828Ssam 
50725977Ssam 	case 2:
50825977Ssam 		if (p->stn.stalign != 2) {
50925977Ssam 			MOVB(l, r, SZCHAR);
51026162Ssam 			putstr("\tmovb\t");
51125977Ssam 		} else
51226162Ssam 			putstr("\tmovw\t");
51325977Ssam 		goto optimized;
51425977Ssam 
51525977Ssam 	case 4:
51625977Ssam 		if (p->stn.stalign != 4) {
51725977Ssam 			if (p->stn.stalign != 2) {
51825977Ssam 				MOVB(l, r, 3*SZCHAR);
51925977Ssam 				MOVB(l, r, 2*SZCHAR);
52025977Ssam 				MOVB(l, r, 1*SZCHAR);
52126162Ssam 				putstr("\tmovb\t");
52225947Ssam 			} else {
52325977Ssam 				MOVW(l, r, SZSHORT);
52426162Ssam 				putstr("\tmovw\t");
52525828Ssam 			}
52625977Ssam 		} else
52726162Ssam 			putstr("\tmovl\t");
52825977Ssam 		goto optimized;
52925828Ssam 
53025977Ssam 	case 6:
53125977Ssam 		if (p->stn.stalign != 2)
53225977Ssam 			goto movblk;
53325977Ssam 		MOVW(l, r, 2*SZSHORT);
53425977Ssam 		MOVW(l, r, 1*SZSHORT);
53526162Ssam 		putstr("\tmovw\t");
53625977Ssam 		goto optimized;
53725977Ssam 
53825977Ssam 	case 8:
53925977Ssam 		if (p->stn.stalign == 4) {
54025977Ssam 			MOVL(l, r, SZLONG);
54126162Ssam 			putstr("\tmovl\t");
54225977Ssam 			goto optimized;
54325977Ssam 		}
54425977Ssam 		/* fall thru...*/
54525977Ssam 
54625977Ssam 	default:
54725977Ssam 	movblk:
54825977Ssam 		/*
54925977Ssam 		 * Can we ever get a register conflict with R1 here?
55025977Ssam 		 */
55126162Ssam 		putstr("\tmovab\t");
55225977Ssam 		adrput(l);
55326162Ssam 		putstr(",r1\n\tmovab\t");
55425977Ssam 		adrput(r);
55525977Ssam 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
55625977Ssam 		rname(R2);
55725828Ssam 		break;
55825977Ssam 	}
55925977Ssam 	/*
56025977Ssam 	 * Reverse above pun for reclaim.
56125977Ssam 	 */
56225977Ssam 	if (r->in.op == NAME)
56325977Ssam 		r->in.op = ICON;
56425977Ssam 	else if (r->in.op == OREG)
56525977Ssam 		r->in.op = REG;
56625977Ssam }
56725828Ssam 
56825977Ssam /*
56925977Ssam  * Output the address of the second item in the
57025977Ssam  * pair pointed to by p.
57125977Ssam  */
57225977Ssam upput(p, size)
57325977Ssam 	register NODE *p;
57425977Ssam {
57525977Ssam 	CONSZ save;
57625977Ssam 
57725977Ssam 	if (p->in.op == FLD)
57825977Ssam 		p = p->in.left;
57925977Ssam 	switch (p->in.op) {
58025977Ssam 
58125977Ssam 	case NAME:
58225977Ssam 	case OREG:
58325977Ssam 		save = p->tn.lval;
58425977Ssam 		p->tn.lval += size/SZCHAR;
58525977Ssam 		adrput(p);
58625977Ssam 		p->tn.lval = save;
58725977Ssam 		break;
58825977Ssam 
58925977Ssam 	case REG:
59025977Ssam 		if (size == SZLONG) {
59126162Ssam 			putstr(rname(p->tn.rval+1));
59225977Ssam 			break;
59325977Ssam 		}
59425977Ssam 		/* fall thru... */
59525977Ssam 
59625828Ssam 	default:
59725977Ssam 		cerror("illegal upper address op %s size %d",
59825977Ssam 		    opst[p->tn.op], size);
59925977Ssam 		/*NOTREACHED*/
60025828Ssam 	}
60125977Ssam }
60225828Ssam 
60330360Ssam /*
60432876Sdonn  * Convert a float or double in the accumulator into an unsigned int.
60532876Sdonn  * Unlike the vax, the tahoe stores 0 into the destination
60632876Sdonn  *	on a conversion of > 2 ** 31, so we compensate.
60732876Sdonn  */
60832876Sdonn float_to_unsigned(p)
60932876Sdonn 	NODE *p;
61032876Sdonn {
61132876Sdonn 	register NODE *l = p->in.left;
61232876Sdonn 	int label1 = getlab();
61332876Sdonn 	int label2 = getlab();
61432876Sdonn 	int label3 = getlab();
615*32879Sdonn 	NODE *src, *dst;
61632876Sdonn 
617*32879Sdonn 	if (p->in.op == SCONV) {
618*32879Sdonn 		src = p->in.left;
619*32879Sdonn 		dst = resc;
620*32879Sdonn 	} else {
621*32879Sdonn 		src = p->in.right;
622*32879Sdonn 		dst = p->in.left;
623*32879Sdonn 	}
624*32879Sdonn 
62532876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
626*32879Sdonn 	if (src->in.type == DOUBLE)
627*32879Sdonn 		putstr(", 0x00000000 # .double");
628*32879Sdonn 	else
629*32879Sdonn 		putstr(" # .float");
630*32879Sdonn 	putstr(" 2147483648\n\t.text\n\tcmp");
631*32879Sdonn 	prtype(src);
63232876Sdonn 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
633*32879Sdonn 	prtype(src);
63432876Sdonn 	printf("\tL%d\n\tcv", label1);
635*32879Sdonn 	prtype(src);
63632876Sdonn 	putstr("l\t");
637*32879Sdonn 	adrput(dst);
63832876Sdonn 	putstr("\n\taddl2\t$-2147483648,");
639*32879Sdonn 	adrput(dst);
64032876Sdonn 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
641*32879Sdonn 	prtype(src);
64232876Sdonn 	putstr("l\t");
643*32879Sdonn 	adrput(dst);
64432876Sdonn 	printf("\nL%d:", label3);
64532876Sdonn }
64632876Sdonn 
64732876Sdonn /*
64832876Sdonn  * Convert an unsigned int into a float or double, leaving the result
64932876Sdonn  *	in the accumulator.
65032876Sdonn  */
65132876Sdonn unsigned_to_float(p)
65232876Sdonn 	register NODE *p;
65332876Sdonn {
65432876Sdonn 	int label1 = getlab();
65532876Sdonn 	int label2 = getlab();
656*32879Sdonn 	NODE *src, *dst;
65732876Sdonn 
658*32879Sdonn 	if (p->in.op == SCONV) {
659*32879Sdonn 		src = p->in.left;
660*32879Sdonn 		dst = resc;
661*32879Sdonn 	} else {
662*32879Sdonn 		src = p->in.right;
663*32879Sdonn 		dst = p->in.left;
664*32879Sdonn 	}
665*32879Sdonn 
66632876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
66732876Sdonn 	if (p->in.type == DOUBLE)
668*32879Sdonn 		putstr(", 0x00000000 # .double");
669*32879Sdonn 	else
670*32879Sdonn 		putstr(" # .float");
671*32879Sdonn 	putstr(" 4294967296\n\t.text\n\tmovl\t");
672*32879Sdonn 	adrput(src);
67332876Sdonn 	putchar(',');
674*32879Sdonn 	adrput(dst);
67532876Sdonn 	putstr("\n\tcvl");
67632876Sdonn 	prtype(p);
67732876Sdonn 	putchar('\t');
678*32879Sdonn 	adrput(dst);
679*32879Sdonn 	printf("\n\tjgeq\tL%d\n\tadd", label1);
680*32879Sdonn 	prtype(p);
681*32879Sdonn 	printf("\tL%d\nL%d:", label2, label1);
68232876Sdonn }
68332876Sdonn 
68432876Sdonn /*
68532875Sdonn  * Prlen() is a cheap prtype()...
68632875Sdonn  */
68732875Sdonn static char convtab[SZINT/SZCHAR + 1] = {
68832875Sdonn 	'?', 'b', 'w', '?', 'l'
68932875Sdonn };
69032875Sdonn #define	prlen(len)	putchar(convtab[len])
69132875Sdonn 
69232875Sdonn 
69332875Sdonn /*
69432873Sdonn  * Generate code for integral scalar conversions.
69532875Sdonn  * Some of this code is designed to work around a tahoe misfeature
69632875Sdonn  *	that causes sign- and zero- extension to be defeated in
69732875Sdonn  *	certain circumstances.
69832875Sdonn  * Basically if the source operand of a CVT or MOVZ instruction is
69932875Sdonn  *	shorter than the destination, and the source is a register
70032875Sdonn  *	or an immediate constant, sign- and zero- extension are
70132875Sdonn  *	ignored and the high bits of the source are copied.  (Note
70232875Sdonn  *	that zero-extension is not a problem for immediate
70332875Sdonn  *	constants.)
70432873Sdonn  */
70532873Sdonn sconv(p, forcc)
70632873Sdonn 	NODE *p;
70732873Sdonn 	int forcc;
70832873Sdonn {
70932873Sdonn 	register NODE *src, *dst;
71032873Sdonn 	register NODE *tmp;
71132873Sdonn 	register int srclen, dstlen;
71232873Sdonn 	int srctype, dsttype;
71332873Sdonn 	int val;
71430360Ssam 
71532873Sdonn 	if (p->in.op == ASSIGN) {
716*32879Sdonn 		src = p->in.right;
717*32879Sdonn 		dst = p->in.left;
71832873Sdonn 		dstlen = tlen(dst);
71932873Sdonn 		dsttype = dst->in.type;
720*32879Sdonn 	} else if (p->in.op == SCONV) {
721*32879Sdonn 		src = p->in.left;
722*32879Sdonn 		dst = resc;
72332873Sdonn 		dstlen = tlen(p);
72432873Sdonn 		dsttype = p->in.type;
725*32879Sdonn 	} else /* if (p->in.op == OPLEAF) */ {
726*32879Sdonn 		src = p;
727*32879Sdonn 		dst = resc;
728*32879Sdonn 		dstlen = SZINT/SZCHAR;
729*32879Sdonn 		dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
73032873Sdonn 	}
73132873Sdonn 
73232875Sdonn 	if (src->in.op == REG) {
73332875Sdonn 		srclen = SZINT/SZCHAR;
73432875Sdonn 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
73532875Sdonn 	} else {
73632875Sdonn 		srclen = tlen(src);
73732875Sdonn 		srctype = src->in.type;
73832875Sdonn 	}
73932873Sdonn 
74032875Sdonn 	if (src->in.op == ICON) {
74132875Sdonn 		if (src->tn.lval == 0) {
74232875Sdonn 			putstr("clr");
74332875Sdonn 			prtype(dst);
74432875Sdonn 			putchar('\t');
74532875Sdonn 			adrput(dst);
74632875Sdonn 			return;
74732875Sdonn 		}
74832875Sdonn 		if (dstlen < srclen) {
74932875Sdonn 			switch (dsttype) {
75032875Sdonn 			case CHAR:
75132875Sdonn 				src->tn.lval = (char) src->tn.lval;
75232875Sdonn 				break;
75332875Sdonn 			case UCHAR:
75432875Sdonn 				src->tn.lval = (unsigned char) src->tn.lval;
75532875Sdonn 				break;
75632875Sdonn 			case SHORT:
75732875Sdonn 				src->tn.lval = (short) src->tn.lval;
75832875Sdonn 				break;
75932875Sdonn 			case USHORT:
76032875Sdonn 				src->tn.lval = (unsigned short) src->tn.lval;
76132875Sdonn 				break;
76232875Sdonn 			}
76332875Sdonn 		}
76432875Sdonn 		if (dst->in.op == REG) {
76532875Sdonn 			dsttype = INT;
76632875Sdonn 			dstlen = SZINT/SZCHAR;
76732875Sdonn 		}
76832875Sdonn 		srctype = dsttype;
76932875Sdonn 		srclen = dstlen;
77032875Sdonn 	}
77132875Sdonn 
77232873Sdonn 	if (srclen < dstlen) {
77332873Sdonn 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
77432873Sdonn 			/* (unsigned short) c; => sign extend to 16 bits */
77532874Sdonn 			putstr("cvtbl\t");
77632873Sdonn 			adrput(src);
77732873Sdonn 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
77832873Sdonn 			adrput(dst);
77932873Sdonn 			putstr("\n\tmovab\t4(sp),sp");
78032873Sdonn 			if (forcc) {
78132873Sdonn 				/* inverted test */
78232873Sdonn 				putstr("\n\tcmpl\t$0,");
78332873Sdonn 				adrput(dst);
78432873Sdonn 			}
78532873Sdonn 			return;
78632873Sdonn 		}
78732873Sdonn 		genconv(ISUNSIGNED(srctype),
78832873Sdonn 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
78932873Sdonn 			src, dst);
79032873Sdonn 		return;
79132873Sdonn 	}
79232873Sdonn 
79332873Sdonn 	if (srclen > dstlen && dst->in.op == REG) {
79432875Sdonn 		/* if dst is a register, the result must look like an int */
79532873Sdonn 		if (src->in.op == REG) {
79632873Sdonn 			if (ISUNSIGNED(dsttype)) {
79732873Sdonn 				val = (1 << dstlen * SZCHAR) - 1;
79832873Sdonn 				if (src->tn.rval == dst->tn.rval)
79932873Sdonn 					/* conversion in place */
80032874Sdonn 					printf("andl2\t$%#x,", val);
80132873Sdonn 				else {
80232874Sdonn 					printf("andl3\t$%#x,", val);
80332873Sdonn 					adrput(src);
80432873Sdonn 					putchar(',');
80532873Sdonn 				}
80632873Sdonn 				adrput(dst);
80732873Sdonn 				return;
80832873Sdonn 			}
80932875Sdonn 			/*
81032875Sdonn 			 * Sign extension in register can also be
81132875Sdonn 			 * accomplished by shifts, but unfortunately
81232875Sdonn 			 * shifts are extremely slow, due to the lack
81332875Sdonn 			 * of a barrel shifter.
81432875Sdonn 			 */
81532875Sdonn 			putstr("pushl\t");
81632873Sdonn 			adrput(src);
81732875Sdonn 			putstr("\n\tcvt");
81832875Sdonn 			prlen(dstlen);
81932875Sdonn 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
82032873Sdonn 			adrput(dst);
82132875Sdonn 			putstr("\n\tmovab\t4(sp),sp");
82232875Sdonn 			if (forcc) {
82332875Sdonn 				/* inverted test */
82432875Sdonn 				putstr("\n\tcmpl\t$0,");
82532875Sdonn 				adrput(dst);
82632875Sdonn 			}
82732873Sdonn 			return;
82832873Sdonn 		}
82932873Sdonn 		tmp = talloc();
83032873Sdonn 		if ((src->in.op == UNARY MUL &&
83132873Sdonn 		    ((src->in.left->in.op == NAME ||
83232873Sdonn 		     (src->in.left->in.op == ICON)))) ||
83332873Sdonn 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
83432873Sdonn 			/* we can increment src's address & pun it */
83532873Sdonn 			*tmp = *src;
83632873Sdonn 			tmp->tn.lval += srclen - dstlen;
83732873Sdonn 		} else {
83832873Sdonn 			/* we must store src's address */
83932873Sdonn 			*tmp = *dst;
84032875Sdonn 			putstr("mova");
84132875Sdonn 			prlen(srclen);
84232875Sdonn 			putchar('\t');
84332873Sdonn 			adrput(src);
84432873Sdonn 			putchar(',');
84532873Sdonn 			adrput(tmp);
84632874Sdonn 			putstr("\n\t");
84732873Sdonn 			tmp->tn.op = OREG;
84832873Sdonn 			tmp->tn.lval = srclen - dstlen;
84932873Sdonn 		}
85032873Sdonn 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
85132873Sdonn 		tmp->in.op = FREE;
85232873Sdonn 		return;
85332873Sdonn 	}
85432873Sdonn 
85532873Sdonn 	genconv(ISUNSIGNED(dsttype),
85632873Sdonn 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
85732873Sdonn 		src, dst);
85832873Sdonn }
85932873Sdonn 
86032873Sdonn genconv(usrc, srclen, dstlen, src, dst)
86132875Sdonn 	int usrc;
86232875Sdonn 	register int srclen, dstlen;
86332873Sdonn 	NODE *src, *dst;
86432873Sdonn {
86532873Sdonn 	if (srclen != dstlen) {
86632873Sdonn 		if (usrc && srclen < dstlen)
86732874Sdonn 			putstr("movz");
86832873Sdonn 		else
86932874Sdonn 			putstr("cvt");
87032875Sdonn 		prlen(srclen);
87132873Sdonn 	} else
87232874Sdonn 		putstr("mov");
87332875Sdonn 	prlen(dstlen);
87432873Sdonn 	putchar('\t');
87532873Sdonn 	adrput(src);
87632873Sdonn 	putchar(',');
87732873Sdonn 	adrput(dst);
87832873Sdonn }
87932873Sdonn 
88025828Ssam rmove( rt, rs, t ) TWORD t;{
88125828Ssam 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
88225828Ssam 	if(t==DOUBLE)
88325828Ssam 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
88425828Ssam 	}
88525828Ssam 
88625828Ssam struct respref
88725828Ssam respref[] = {
88825828Ssam 	INTAREG|INTBREG,	INTAREG|INTBREG,
88925828Ssam 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
89025828Ssam 	INTEMP,	INTEMP,
89125828Ssam 	FORARG,	FORARG,
89225828Ssam 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
89325828Ssam 	0,	0 };
89425828Ssam 
89525828Ssam setregs(){ /* set up temporary registers */
89625828Ssam 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
89725828Ssam 	}
89825828Ssam 
89926076Ssam #ifndef szty
90025828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
90125828Ssam 	return(t==DOUBLE ? 2 : 1 );
90225828Ssam 	}
90326076Ssam #endif
90425828Ssam 
90525828Ssam rewfld( p ) NODE *p; {
90625828Ssam 	return(1);
90725828Ssam 	}
90825828Ssam 
90925828Ssam callreg(p) NODE *p; {
91025828Ssam 	return( R0 );
91125828Ssam 	}
91225828Ssam 
91325828Ssam base( p ) register NODE *p; {
91425828Ssam 	register int o = p->in.op;
91525828Ssam 
91625828Ssam 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
91725828Ssam 	if( o==REG ) return( p->tn.rval );
91825828Ssam     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
91925828Ssam 		return( p->in.left->tn.rval );
92025828Ssam     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
92125828Ssam 		return( p->tn.rval + 0200*1 );
92225828Ssam 	return( -1 );
92325828Ssam 	}
92425828Ssam 
92525828Ssam offset( p, tyl ) register NODE *p; int tyl; {
92625828Ssam 
92725828Ssam 	if(tyl > 8) return( -1 );
92825828Ssam 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
92925828Ssam 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
93025828Ssam 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
93125828Ssam 	      && (1<<p->in.right->tn.lval)==tyl))
93225828Ssam 		return( p->in.left->tn.rval );
93325828Ssam 	return( -1 );
93425828Ssam 	}
93525828Ssam 
93625828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
93725828Ssam 	register NODE *t;
93825828Ssam 	register int i;
93925828Ssam 	NODE *f;
94025828Ssam 
94125828Ssam 	p->in.op = OREG;
94225828Ssam 	f = p->in.left; 	/* have to free this subtree later */
94325828Ssam 
94425828Ssam 	/* init base */
94525828Ssam 	switch (q->in.op) {
94625828Ssam 		case ICON:
94725828Ssam 		case REG:
94825828Ssam 		case OREG:
94925828Ssam 			t = q;
95025828Ssam 			break;
95125828Ssam 
95225828Ssam 		case MINUS:
95325828Ssam 			q->in.right->tn.lval = -q->in.right->tn.lval;
95425828Ssam 		case PLUS:
95525828Ssam 			t = q->in.right;
95625828Ssam 			break;
95725828Ssam 
95825828Ssam 		case UNARY MUL:
95925828Ssam 			t = q->in.left->in.left;
96025828Ssam 			break;
96125828Ssam 
96225828Ssam 		default:
96325828Ssam 			cerror("illegal makeor2");
96425828Ssam 	}
96525828Ssam 
96625828Ssam 	p->tn.lval = t->tn.lval;
96725828Ssam #ifndef FLEXNAMES
96825828Ssam 	for(i=0; i<NCHNAM; ++i)
96925828Ssam 		p->in.name[i] = t->in.name[i];
97025828Ssam #else
97125828Ssam 	p->in.name = t->in.name;
97225828Ssam #endif
97325828Ssam 
97425828Ssam 	/* init offset */
97525828Ssam 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
97625828Ssam 
97725828Ssam 	tfree(f);
97825828Ssam 	return;
97925828Ssam 	}
98025828Ssam 
98125828Ssam canaddr( p ) NODE *p; {
98225828Ssam 	register int o = p->in.op;
98325828Ssam 
98425828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
98525828Ssam 	return(0);
98625828Ssam 	}
98725828Ssam 
98826076Ssam #ifndef shltype
98925828Ssam shltype( o, p ) register NODE *p; {
99025828Ssam 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
99125828Ssam 	}
99226076Ssam #endif
99325828Ssam 
99425828Ssam flshape( p ) NODE *p; {
99525828Ssam 	register int o = p->in.op;
99625828Ssam 
99725828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
99825828Ssam 	return(0);
99925828Ssam 	}
100025828Ssam 
100125828Ssam shtemp( p ) register NODE *p; {
100225828Ssam 	if( p->in.op == STARG ) p = p->in.left;
100325828Ssam 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
100425828Ssam 	}
100525828Ssam 
100625828Ssam shumul( p ) register NODE *p; {
100725828Ssam 	register int o;
100825828Ssam 	extern int xdebug;
100925828Ssam 
101025828Ssam 	if (xdebug) {
101125828Ssam 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
101225828Ssam 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
101325828Ssam 		}
101425828Ssam 
101525828Ssam 	o = p->in.op;
101625828Ssam 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
101725828Ssam 	 && p->in.type != PTR+DOUBLE)
101825828Ssam 		return( STARNM );
101925828Ssam 
102025828Ssam 	return( 0 );
102125828Ssam 	}
102225828Ssam 
102325828Ssam special( p, shape ) register NODE *p; {
102425828Ssam 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
102525828Ssam 	else return(0);
102625828Ssam }
102725828Ssam 
102825828Ssam adrcon( val ) CONSZ val; {
102925947Ssam 	printf(ACONFMT, val);
103025828Ssam 	}
103125828Ssam 
103225828Ssam conput( p ) register NODE *p; {
103325828Ssam 	switch( p->in.op ){
103425828Ssam 
103525828Ssam 	case ICON:
103625828Ssam 		acon( p );
103725828Ssam 		return;
103825828Ssam 
103925828Ssam 	case REG:
104026162Ssam 		putstr(rname(p->tn.rval));
104125828Ssam 		return;
104225828Ssam 
104325828Ssam 	default:
104425828Ssam 		cerror( "illegal conput" );
104525828Ssam 		}
104625828Ssam 	}
104725828Ssam 
104825828Ssam insput( p ) NODE *p; {
104925828Ssam 	cerror( "insput" );
105025828Ssam 	}
105125828Ssam 
105225828Ssam adrput( p ) register NODE *p; {
105325828Ssam 	register int r;
105425828Ssam 	/* output an address, with offsets, from p */
105525828Ssam 
105625828Ssam 	if( p->in.op == FLD ){
105725828Ssam 		p = p->in.left;
105825828Ssam 		}
105925828Ssam 	switch( p->in.op ){
106025828Ssam 
106125828Ssam 	case NAME:
106225828Ssam 		acon( p );
106325828Ssam 		return;
106425828Ssam 
106525828Ssam 	case ICON:
106625828Ssam 		/* addressable value of the constant */
106726162Ssam 		putchar('$');
106825828Ssam 		acon( p );
106925828Ssam 		return;
107025828Ssam 
107125828Ssam 	case REG:
107226162Ssam 		putstr(rname(p->tn.rval));
107325828Ssam 		if(p->in.type == DOUBLE)	/* for entry mask */
107425828Ssam 			(void) rname(p->tn.rval+1);
107525828Ssam 		return;
107625828Ssam 
107725828Ssam 	case OREG:
107825828Ssam 		r = p->tn.rval;
107925828Ssam 		if( R2TEST(r) ){ /* double indexing */
108025828Ssam 			register int flags;
108125828Ssam 
108225828Ssam 			flags = R2UPK3(r);
108326162Ssam 			if( flags & 1 ) putchar('*');
108425828Ssam 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
108525828Ssam 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
108625828Ssam 			printf( "[%s]", rname(R2UPK2(r)) );
108725828Ssam 			return;
108825828Ssam 			}
108925828Ssam 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
109025828Ssam 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
109125828Ssam 			printf( CONFMT, p->tn.lval );
109226162Ssam 			putstr( "(fp)" );
109325828Ssam 			return;
109425828Ssam 			}
109525828Ssam 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
109625828Ssam 		printf( "(%s)", rname(p->tn.rval) );
109725828Ssam 		return;
109825828Ssam 
109925828Ssam 	case UNARY MUL:
110025828Ssam 		/* STARNM or STARREG found */
110125828Ssam 		if( tshape(p, STARNM) ) {
110226162Ssam 			putchar( '*' );
110325828Ssam 			adrput( p->in.left);
110425828Ssam 			}
110525828Ssam 		return;
110625828Ssam 
110725828Ssam 	default:
110825828Ssam 		cerror( "illegal address" );
110925828Ssam 		return;
111025828Ssam 
111125828Ssam 		}
111225828Ssam 
111325828Ssam 	}
111425828Ssam 
111525828Ssam acon( p ) register NODE *p; { /* print out a constant */
111625828Ssam 
111725828Ssam 	if( p->in.name[0] == '\0' ){
111825828Ssam 		printf( CONFMT, p->tn.lval);
111926162Ssam 		return;
112026162Ssam 	} else {
112125828Ssam #ifndef FLEXNAMES
112225828Ssam 		printf( "%.8s", p->in.name );
112325828Ssam #else
112426162Ssam 		putstr(p->in.name);
112525828Ssam #endif
112626162Ssam 		if (p->tn.lval != 0) {
112726162Ssam 			putchar('+');
112826162Ssam 			printf(CONFMT, p->tn.lval);
112925828Ssam 		}
113025828Ssam 	}
113126162Ssam 	}
113225828Ssam 
113325828Ssam genscall( p, cookie ) register NODE *p; {
113425828Ssam 	/* structure valued call */
113525828Ssam 	return( gencall( p, cookie ) );
113625828Ssam 	}
113725828Ssam 
113825828Ssam genfcall( p, cookie ) register NODE *p; {
113925828Ssam 	register NODE *p1;
114025828Ssam 	register int m;
114125828Ssam 	static char *funcops[6] = {
114225828Ssam 		"sin", "cos", "sqrt", "exp", "log", "atan"
114325828Ssam 	};
114425828Ssam 
114525828Ssam 	/* generate function opcodes */
114625828Ssam 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
114725828Ssam 	 (p1 = p->in.left)->in.op==ICON &&
114825828Ssam 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
114925828Ssam #ifdef FLEXNAMES
115025828Ssam 		p1->in.name++;
115125828Ssam #else
115225828Ssam 		strcpy(p1->in.name, p1->in.name[1]);
115325828Ssam #endif
115425828Ssam 		for(m=0; m<6; m++)
115525828Ssam 			if(!strcmp(p1->in.name, funcops[m]))
115625828Ssam 				break;
115725828Ssam 		if(m >= 6)
115825828Ssam 			uerror("no opcode for fortarn function %s", p1->in.name);
115925828Ssam 	} else
116025828Ssam 		uerror("illegal type of fortarn function");
116125828Ssam 	p1 = p->in.right;
116225828Ssam 	p->in.op = FORTCALL;
116325828Ssam 	if(!canaddr(p1))
116425828Ssam 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
116525828Ssam 	m = match( p, INTAREG|INTBREG );
116625828Ssam 	return(m != MDONE);
116725828Ssam }
116825828Ssam 
116925828Ssam /* tbl */
117025828Ssam int gc_numbytes;
117125828Ssam /* tbl */
117225828Ssam 
117325828Ssam gencall( p, cookie ) register NODE *p; {
117425828Ssam 	/* generate the call given by p */
117525828Ssam 	register NODE *p1, *ptemp;
117625828Ssam 	register int temp, temp1;
117725828Ssam 	register int m;
117825828Ssam 
117925828Ssam 	if( p->in.right ) temp = argsize( p->in.right );
118025828Ssam 	else temp = 0;
118125828Ssam 
118225828Ssam 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
118325828Ssam 		/* set aside room for structure return */
118425828Ssam 
118525828Ssam 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
118625828Ssam 		else temp1 = temp;
118725828Ssam 		}
118825828Ssam 
118925828Ssam 	if( temp > maxargs ) maxargs = temp;
119025828Ssam 	SETOFF(temp1,4);
119125828Ssam 
119225828Ssam 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
119325828Ssam 		ptemp = talloc();
119425828Ssam 		ptemp->in.op = OREG;
119525828Ssam 		ptemp->tn.lval = -1;
119625828Ssam 		ptemp->tn.rval = SP;
119725828Ssam #ifndef FLEXNAMES
119825828Ssam 		ptemp->in.name[0] = '\0';
119925828Ssam #else
120025828Ssam 		ptemp->in.name = "";
120125828Ssam #endif
120225828Ssam 		ptemp->in.rall = NOPREF;
120325828Ssam 		ptemp->in.su = 0;
120425828Ssam 		genargs( p->in.right, ptemp );
120525828Ssam 		ptemp->in.op = FREE;
120625828Ssam 		}
120725828Ssam 
120825828Ssam 	p1 = p->in.left;
120925828Ssam 	if( p1->in.op != ICON ){
121025828Ssam 		if( p1->in.op != REG ){
121125828Ssam 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
121225828Ssam 				if( p1->in.op != NAME ){
121325828Ssam 					order( p1, INAREG );
121425828Ssam 					}
121525828Ssam 				}
121625828Ssam 			}
121725828Ssam 		}
121825828Ssam 
121925828Ssam /* tbl
122025828Ssam 	setup gc_numbytes so reference to ZC works */
122125828Ssam 
122225828Ssam 	gc_numbytes = temp&(0x3ff);
122325828Ssam 
122425828Ssam 	p->in.op = UNARY CALL;
122525828Ssam 	m = match( p, INTAREG|INTBREG );
122625828Ssam 
122725828Ssam 	return(m != MDONE);
122825828Ssam 	}
122925828Ssam 
123025828Ssam /* tbl */
123125828Ssam char *
123225828Ssam ccbranches[] = {
123325828Ssam 	"eql",
123425828Ssam 	"neq",
123525828Ssam 	"leq",
123625828Ssam 	"lss",
123725828Ssam 	"geq",
123825828Ssam 	"gtr",
123925828Ssam 	"lequ",
124025828Ssam 	"lssu",
124125828Ssam 	"gequ",
124225828Ssam 	"gtru",
124325828Ssam 	};
124425828Ssam /* tbl */
124525828Ssam 
124625828Ssam cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
124725828Ssam 
124825828Ssam 		if(o != 0 && (o < EQ || o > UGT ))
124925828Ssam 			cerror( "bad conditional branch: %s", opst[o] );
125025828Ssam 		printf( "	j%s	L%d\n",
125125828Ssam 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
125225828Ssam 	}
125325828Ssam 
125425828Ssam nextcook( p, cookie ) NODE *p; {
125525828Ssam 	/* we have failed to match p with cookie; try another */
125625828Ssam 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
125725828Ssam 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
125825828Ssam 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
125925828Ssam 	return( FORREW );
126025828Ssam 	}
126125828Ssam 
126225828Ssam lastchance( p, cook ) NODE *p; {
126325828Ssam 	/* forget it! */
126425828Ssam 	return(0);
126525828Ssam 	}
126625828Ssam 
126725828Ssam optim2( p ) register NODE *p; {
126825828Ssam # ifdef ONEPASS
126925828Ssam 	/* do local tree transformations and optimizations */
127025828Ssam # define RV(p) p->in.right->tn.lval
127126076Ssam # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
127230360Ssam 	register int o, i;
127330360Ssam 	register NODE *l, *r;
127425828Ssam 
127530360Ssam 	switch (o = p->in.op) {
127630360Ssam 
127730360Ssam 	case DIV: case ASG DIV:
127830360Ssam 	case MOD: case ASG MOD:
127930360Ssam 		/*
128030360Ssam 		 * Change unsigned mods and divs to
128130360Ssam 		 * logicals (mul is done in mip & c2)
128230360Ssam 		 */
128330360Ssam 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
128430360Ssam 		    (i = ispow2(RV(p))) >= 0) {
128530360Ssam 			if (o == DIV || o == ASG DIV) {
128630360Ssam 				p->in.op = RS;
128730360Ssam 				RV(p) = i;
128830360Ssam 			} else {
128930360Ssam 				p->in.op = AND;
129030360Ssam 				RV(p)--;
129130360Ssam 			}
129230360Ssam 			if (asgop(o))
129330360Ssam 				p->in.op = ASG p->in.op;
129425828Ssam 		}
129530360Ssam 		return;
129630360Ssam 
129730360Ssam 	case SCONV:
129830360Ssam 		l = p->in.left;
1299*32879Sdonn 		if (anyfloat(p, l)) {
1300*32879Sdonn 			/* save some labor later */
1301*32879Sdonn 			NODE *t = talloc();
1302*32879Sdonn 
1303*32879Sdonn 			if (p->in.type == UCHAR || p->in.type == USHORT) {
1304*32879Sdonn 				*t = *p;
1305*32879Sdonn 				t->in.type = UNSIGNED;
1306*32879Sdonn 				p->in.left = t;
1307*32879Sdonn 			} else if (l->in.type == UCHAR || l->in.type == USHORT) {
1308*32879Sdonn 				*t = *p;
1309*32879Sdonn 				t->in.type = INT;
1310*32879Sdonn 				p->in.left = t;
1311*32879Sdonn 			}
1312*32879Sdonn 		} else if (l->in.op != PCONV &&
131332878Sdonn 		    l->in.op != CALL && l->in.op != UNARY CALL &&
131430360Ssam 		    tlen(p) == tlen(l)) {
1315*32879Sdonn 			/* clobber conversions w/o side effects */
131630360Ssam 			if (l->in.op != FLD)
131730360Ssam 				l->in.type = p->in.type;
131830360Ssam 			ncopy(p, l);
131930360Ssam 			l->in.op = FREE;
132030360Ssam 		}
132130360Ssam 		return;
132230360Ssam 
132330360Ssam 	case ASSIGN:
132430360Ssam 		/*
132530360Ssam 		 * Try to zap storage conversions of non-float items.
132630360Ssam 		 */
132730360Ssam 		r = p->in.right;
132830360Ssam 		if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
132930360Ssam 			int wdest, wconv, wsrc;
133030360Ssam 			wdest = tlen(p->in.left);
133130360Ssam 			wconv = tlen(r);
133230360Ssam 			/*
133330360Ssam 			 * If size doesn't change across assignment or
133430360Ssam 			 * conversion expands src before shrinking again
133530360Ssam 			 * due to the assignment, delete conversion so
133630360Ssam 			 * code generator can create optimal code.
133730360Ssam 			 */
133830360Ssam 			if (wdest == wconv ||
133930360Ssam 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
134030360Ssam 				p->in.right = r->in.left;
134130360Ssam 				r->in.op = FREE;
134230360Ssam 			}
1343*32879Sdonn 		} else if (p->in.left->in.type == UNSIGNED &&
1344*32879Sdonn 			   r->in.type == UNSIGNED) {
1345*32879Sdonn 			/* let the code table handle it */
1346*32879Sdonn 			p->in.right = r->in.left;
1347*32879Sdonn 			r->in.op = FREE;
1348*32879Sdonn 		} else if ((p->in.left->in.type == FLOAT ||
1349*32879Sdonn 			    p->in.left->in.type == DOUBLE) &&
1350*32879Sdonn 			   p->in.left->in.type == r->in.type &&
1351*32879Sdonn 			   r->in.left->in.type == UNSIGNED) {
1352*32879Sdonn 			/* let the code table handle it */
1353*32879Sdonn 			p->in.right = r->in.left;
1354*32879Sdonn 			r->in.op = FREE;
135530360Ssam 		}
135630360Ssam 		return;
135725828Ssam 	}
135825828Ssam # endif
135925828Ssam }
136025828Ssam 
136125828Ssam struct functbl {
136225828Ssam 	int fop;
136332877Sdonn 	TWORD ftype;
136425828Ssam 	char *func;
136532877Sdonn 	} opfunc[] = {
136632877Sdonn 	DIV,		TANY,	"udiv",
136732877Sdonn 	MOD,		TANY,	"urem",
136832877Sdonn 	ASG DIV,	TANY,	"audiv",
136932877Sdonn 	ASG MOD,	TANY,	"aurem",
137032877Sdonn 	0,	0,	0 };
137125828Ssam 
137225828Ssam hardops(p)  register NODE *p; {
137325828Ssam 	/* change hard to do operators into function calls.  */
137425828Ssam 	register NODE *q;
137525828Ssam 	register struct functbl *f;
137632877Sdonn 	register o;
137732877Sdonn 	NODE *old,*temp;
137825828Ssam 
137925828Ssam 	o = p->in.op;
138032877Sdonn 	if( ! (optype(o)==BITYPE &&
138132877Sdonn 	       (ISUNSIGNED(p->in.left->in.type) ||
138232877Sdonn 		ISUNSIGNED(p->in.right->in.type))) )
138332877Sdonn 		return;
138425828Ssam 
138525828Ssam 	for( f=opfunc; f->fop; f++ ) {
138625828Ssam 		if( o==f->fop ) goto convert;
138732877Sdonn 		}
138825828Ssam 	return;
138925828Ssam 
139025828Ssam 	convert:
139125828Ssam 	if( asgop( o ) ) {
139232877Sdonn 		old = NIL;
139332877Sdonn 		switch( p->in.left->in.op ){
139432877Sdonn 		case FLD:
139532877Sdonn 			q = p->in.left->in.left;
139632877Sdonn 			/*
139732877Sdonn 			 * rewrite (lval.fld /= rval); as
139832877Sdonn 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
139932877Sdonn 			 * else the compiler will evaluate lval twice.
140032877Sdonn 			 */
140132877Sdonn 			if( q->in.op == UNARY MUL ){
140232877Sdonn 				/* first allocate a temp storage */
140332877Sdonn 				temp = talloc();
140432877Sdonn 				temp->in.op = OREG;
140532877Sdonn 				temp->tn.rval = TMPREG;
140632877Sdonn 				temp->tn.lval = BITOOR(freetemp(1));
140732877Sdonn 				temp->in.type = INCREF(p->in.type);
140832877Sdonn #ifdef FLEXNAMES
140932877Sdonn 				temp->in.name = "";
141032877Sdonn #else
141132877Sdonn 				temp->in.name[0] = '\0';
141232877Sdonn #endif
141332877Sdonn 				old = q->in.left;
141432877Sdonn 				q->in.left = temp;
141532877Sdonn 			}
141632877Sdonn 			/* fall thru ... */
141725828Ssam 
141832877Sdonn 		case REG:
141932877Sdonn 		case NAME:
142032877Sdonn 		case OREG:
142132877Sdonn 			/* change ASG OP to a simple OP */
142232877Sdonn 			q = talloc();
142332877Sdonn 			q->in.op = NOASG p->in.op;
142432877Sdonn 			q->in.rall = NOPREF;
142532877Sdonn 			q->in.type = p->in.type;
142632877Sdonn 			q->in.left = tcopy(p->in.left);
142732877Sdonn 			q->in.right = p->in.right;
142832877Sdonn 			p->in.op = ASSIGN;
142932877Sdonn 			p->in.right = q;
143032877Sdonn 			p = q;
143132877Sdonn 			f -= 2; /* Note: this depends on the table order */
143232877Sdonn 			/* on the right side only - replace *temp with
143332877Sdonn 			 *(temp = &lval), build the assignment node */
143432877Sdonn 			if( old ){
143532877Sdonn 				temp = q->in.left->in.left; /* the "*" node */
143632877Sdonn 				q = talloc();
143732877Sdonn 				q->in.op = ASSIGN;
143832877Sdonn 				q->in.left = temp->in.left;
143932877Sdonn 				q->in.right = old;
144032877Sdonn 				q->in.type = old->in.type;
144132877Sdonn #ifdef FLEXNAMES
144232877Sdonn 				q->in.name = "";
144325828Ssam #else
144432877Sdonn 				q->in.name[0] = '\0';
144525828Ssam #endif
144632877Sdonn 				temp->in.left = q;
144732877Sdonn 			}
144832877Sdonn 			break;
144925828Ssam 
145032877Sdonn 		case UNARY MUL:
145132877Sdonn 			/* avoid doing side effects twice */
145232877Sdonn 			q = p->in.left;
145332877Sdonn 			p->in.left = q->in.left;
145432877Sdonn 			q->in.op = FREE;
145532877Sdonn 			break;
145632877Sdonn 
145732877Sdonn 		default:
145832877Sdonn 			cerror( "hardops: can't compute & LHS" );
145932877Sdonn 			}
146032877Sdonn 		}
146132877Sdonn 
146225828Ssam 	/* build comma op for args to function */
146332877Sdonn 	q = talloc();
146432877Sdonn 	q->in.op = CM;
146532877Sdonn 	q->in.rall = NOPREF;
146632877Sdonn 	q->in.type = INT;
146732877Sdonn 	q->in.left = p->in.left;
146832877Sdonn 	q->in.right = p->in.right;
146925828Ssam 	p->in.op = CALL;
147025828Ssam 	p->in.right = q;
147125828Ssam 
147225828Ssam 	/* put function name in left node of call */
147325828Ssam 	p->in.left = q = talloc();
147425828Ssam 	q->in.op = ICON;
147525828Ssam 	q->in.rall = NOPREF;
147625828Ssam 	q->in.type = INCREF( FTN + p->in.type );
147725828Ssam #ifndef FLEXNAMES
147832877Sdonn 	strcpy( q->in.name, f->func );
147925828Ssam #else
148032877Sdonn 	q->in.name = f->func;
148125828Ssam #endif
148225828Ssam 	q->tn.lval = 0;
148325828Ssam 	q->tn.rval = 0;
148425828Ssam 
148525828Ssam 	}
148625828Ssam 
148725828Ssam zappost(p) NODE *p; {
148825828Ssam 	/* look for ++ and -- operators and remove them */
148925828Ssam 
149025828Ssam 	register int o, ty;
149125828Ssam 	register NODE *q;
149225828Ssam 	o = p->in.op;
149325828Ssam 	ty = optype( o );
149425828Ssam 
149525828Ssam 	switch( o ){
149625828Ssam 
149725828Ssam 	case INCR:
149825828Ssam 	case DECR:
149925828Ssam 			q = p->in.left;
150025828Ssam 			p->in.right->in.op = FREE;  /* zap constant */
150125828Ssam 			ncopy( p, q );
150225828Ssam 			q->in.op = FREE;
150325828Ssam 			return;
150425828Ssam 
150525828Ssam 		}
150625828Ssam 
150725828Ssam 	if( ty == BITYPE ) zappost( p->in.right );
150825828Ssam 	if( ty != LTYPE ) zappost( p->in.left );
150925828Ssam }
151025828Ssam 
151125828Ssam fixpre(p) NODE *p; {
151225828Ssam 
151325828Ssam 	register int o, ty;
151425828Ssam 	o = p->in.op;
151525828Ssam 	ty = optype( o );
151625828Ssam 
151725828Ssam 	switch( o ){
151825828Ssam 
151925828Ssam 	case ASG PLUS:
152025828Ssam 			p->in.op = PLUS;
152125828Ssam 			break;
152225828Ssam 	case ASG MINUS:
152325828Ssam 			p->in.op = MINUS;
152425828Ssam 			break;
152525828Ssam 		}
152625828Ssam 
152725828Ssam 	if( ty == BITYPE ) fixpre( p->in.right );
152825828Ssam 	if( ty != LTYPE ) fixpre( p->in.left );
152925828Ssam }
153025828Ssam 
153125828Ssam NODE * addroreg(l) NODE *l;
153225828Ssam 				/* OREG was built in clocal()
153325828Ssam 				 * for an auto or formal parameter
153425828Ssam 				 * now its address is being taken
153525828Ssam 				 * local code must unwind it
153625828Ssam 				 * back to PLUS/MINUS REG ICON
153725828Ssam 				 * according to local conventions
153825828Ssam 				 */
153925828Ssam {
154025828Ssam 	cerror("address of OREG taken");
154125828Ssam }
154225828Ssam 
154325828Ssam # ifndef ONEPASS
154425828Ssam main( argc, argv ) char *argv[]; {
154525828Ssam 	return( mainp2( argc, argv ) );
154625828Ssam 	}
154725828Ssam # endif
154825828Ssam 
154930360Ssam strip(p) register NODE *p; {
155030360Ssam 	NODE *q;
155130360Ssam 
155230360Ssam 	/* strip nodes off the top when no side effects occur */
155330360Ssam 	for( ; ; ) {
155430360Ssam 		switch( p->in.op ) {
155530360Ssam 		case SCONV:			/* remove lint tidbits */
155630360Ssam 			q = p->in.left;
155730360Ssam 			ncopy( p, q );
155830360Ssam 			q->in.op = FREE;
155930360Ssam 			break;
156030360Ssam 		/* could probably add a few more here */
156130360Ssam 		default:
156230360Ssam 			return;
156330360Ssam 			}
156430360Ssam 		}
156530360Ssam 	}
156630360Ssam 
156725828Ssam myreader(p) register NODE *p; {
156830360Ssam 	strip( p );		/* strip off operations with no side effects */
156925828Ssam 	walkf( p, hardops );	/* convert ops to function calls */
157025828Ssam 	canon( p );		/* expands r-vals for fileds */
157125828Ssam 	walkf( p, optim2 );
157225828Ssam 	}
1573