xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 33622)
132890Sdonn #ifndef lint
2*33622Sdonn static char sccsid[] = "@(#)local2.c	1.32 (Berkeley) 02/29/88";
332890Sdonn #endif
425828Ssam 
526076Ssam # include "pass2.h"
626076Ssam # include <ctype.h>
726162Ssam 
826162Ssam # define putstr(s)	fputs((s), stdout)
929672Ssam # define ISCHAR(p)	(p->in.type == UCHAR || p->in.type == CHAR)
1026162Ssam 
1125828Ssam # ifdef FORT
1225828Ssam int ftlab1, ftlab2;
1325828Ssam # endif
1425828Ssam /* a lot of the machine dependent parts of the second pass */
1525828Ssam 
1625828Ssam # define BITMASK(n) ((1L<<n)-1)
1725828Ssam 
1825828Ssam # ifndef ONEPASS
1932886Sdonn /*ARGSUSED*/
where(c)2025828Ssam where(c){
2125828Ssam 	fprintf( stderr, "%s, line %d: ", filename, lineno );
2225828Ssam 	}
2325828Ssam # endif
2425828Ssam 
lineid(l,fn)2525828Ssam lineid( l, fn ) char *fn; {
2625828Ssam 	/* identify line l and file fn */
2725828Ssam 	printf( "#	line %d, file %s\n", l, fn );
2825828Ssam 	}
2925828Ssam 
3025828Ssam int ent_mask;
3125828Ssam 
eobl2()3225828Ssam eobl2(){
3325828Ssam 	register OFFSZ spoff;	/* offset from stack pointer */
3425828Ssam #ifndef FORT
3525828Ssam 	extern int ftlab1, ftlab2;
3625828Ssam #endif
3725828Ssam 
3825828Ssam 	spoff = maxoff;
3925828Ssam 	spoff /= SZCHAR;
4025828Ssam 	SETOFF(spoff,4);
4125828Ssam #ifdef FORT
4225828Ssam #ifndef FLEXNAMES
4332886Sdonn 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
4425828Ssam #else
4525828Ssam 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
4632886Sdonn 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
4725828Ssam #endif
4825828Ssam 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
4925828Ssam #else
5025828Ssam 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
5125828Ssam 	printf( "L%d:\n", ftlab1);
5225828Ssam 	if( maxoff > AUTOINIT )
5332886Sdonn 		printf( "	subl3	$%ld,fp,sp\n", spoff);
5425828Ssam 	printf( "	jbr 	L%d\n", ftlab2);
5525828Ssam #endif
5625828Ssam 	ent_mask = 0;
5725828Ssam 	maxargs = -1;
5825828Ssam 	}
5925828Ssam 
6025828Ssam struct hoptab { int opmask; char * opstring; } ioptab[] = {
6125828Ssam 
6225828Ssam 	PLUS,	"add",
6325828Ssam 	MINUS,	"sub",
6425828Ssam 	MUL,	"mul",
6525828Ssam 	DIV,	"div",
6625828Ssam 	MOD,	"div",
6725828Ssam 	OR,	"or",
6825828Ssam 	ER,	"xor",
6925828Ssam 	AND,	"and",
7025828Ssam 	-1,	""    };
7125828Ssam 
hopcode(f,o)7225828Ssam hopcode( f, o ){
7325828Ssam 	/* output the appropriate string from the above table */
7425828Ssam 
7525828Ssam 	register struct hoptab *q;
7625828Ssam 
7725828Ssam 	if(asgop(o))
7825828Ssam 		o = NOASG o;
7925828Ssam 	for( q = ioptab;  q->opmask>=0; ++q ){
8025828Ssam 		if( q->opmask == o ){
8125828Ssam 			if(f == 'E')
8225828Ssam 				printf( "e%s", q->opstring);
8325828Ssam 			else
8425828Ssam 				printf( "%s%c", q->opstring, tolower(f));
8525828Ssam 			return;
8625828Ssam 			}
8725828Ssam 		}
8825828Ssam 	cerror( "no hoptab for %s", opst[o] );
8925828Ssam 	}
9025828Ssam 
9125828Ssam char *
9225828Ssam rnames[] = {  /* keyed to register number tokens */
9325828Ssam 
9425828Ssam 	"r0", "r1",
9525828Ssam 	"r2", "r3", "r4", "r5",
9625828Ssam 	"r6", "r7", "r8", "r9", "r10", "r11",
9725828Ssam 	"r12", "fp", "sp", "pc",
9825828Ssam 	};
9925828Ssam 
10025828Ssam /* output register name and update entry mask */
10125828Ssam char *
rname(r)10225828Ssam rname(r)
10325828Ssam 	register int r;
10425828Ssam {
10525828Ssam 
10632887Sdonn 	if (!istreg(r))
10732887Sdonn 		ent_mask |= 1<<r;
10825828Ssam 	return(rnames[r]);
10925828Ssam }
11025828Ssam 
11125828Ssam int rstatus[] = {
11225828Ssam 	SAREG|STAREG, SAREG|STAREG,
11325828Ssam 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
11425828Ssam 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
11525828Ssam 	SAREG, SAREG, SAREG, SAREG,
11625828Ssam 	};
11725828Ssam 
tlen(p)11825828Ssam tlen(p) NODE *p;
11925828Ssam {
12025828Ssam 	switch(p->in.type) {
12125828Ssam 		case CHAR:
12225828Ssam 		case UCHAR:
12325828Ssam 			return(1);
12425828Ssam 
12525828Ssam 		case SHORT:
12625828Ssam 		case USHORT:
12732886Sdonn 			return(SZSHORT/SZCHAR);
12825828Ssam 
12925828Ssam 		case DOUBLE:
13032886Sdonn 			return(SZDOUBLE/SZCHAR);
13125828Ssam 
13225828Ssam 		default:
13332886Sdonn 			return(SZINT/SZCHAR);
13425828Ssam 		}
13525828Ssam }
13625828Ssam 
mixtypes(p,q)13732886Sdonn mixtypes(p, q) NODE *p, *q;
13830360Ssam {
13930360Ssam 	register TWORD tp, tq;
14030360Ssam 
14130360Ssam 	tp = p->in.type;
14230360Ssam 	tq = q->in.type;
14332886Sdonn 
14432886Sdonn 	return( (tp==FLOAT || tp==DOUBLE) !=
14532886Sdonn 		(tq==FLOAT || tq==DOUBLE) );
14630360Ssam }
14730360Ssam 
prtype(n)14825828Ssam prtype(n) NODE *n;
14925828Ssam {
15025828Ssam 	switch (n->in.type)
15125828Ssam 		{
15225828Ssam 
15325828Ssam 		case DOUBLE:
15426162Ssam 			putchar('d');
15525828Ssam 			return;
15625828Ssam 
15725828Ssam 		case FLOAT:
15826162Ssam 			putchar('f');
15925828Ssam 			return;
16025828Ssam 
16132886Sdonn 		case LONG:
16232886Sdonn 		case ULONG:
16325828Ssam 		case INT:
16425828Ssam 		case UNSIGNED:
16526162Ssam 			putchar('l');
16625828Ssam 			return;
16725828Ssam 
16825828Ssam 		case SHORT:
16925828Ssam 		case USHORT:
17026162Ssam 			putchar('w');
17125828Ssam 			return;
17225828Ssam 
17325828Ssam 		case CHAR:
17425828Ssam 		case UCHAR:
17526162Ssam 			putchar('b');
17625828Ssam 			return;
17725828Ssam 
17825828Ssam 		default:
17925828Ssam 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
18025828Ssam 			else {
18126162Ssam 				putchar('l');
18225828Ssam 				return;
18325828Ssam 				}
18425828Ssam 		}
18525828Ssam }
18625828Ssam 
zzzcode(p,c)18725828Ssam zzzcode( p, c ) register NODE *p; {
18825828Ssam 	register int m;
18925828Ssam 	int val;
19025828Ssam 	switch( c ){
19125828Ssam 
19225828Ssam 	case 'N':  /* logical ops, turned into 0-1 */
19325828Ssam 		/* use register given by register 1 */
19425828Ssam 		cbgen( 0, m=getlab(), 'I' );
19525828Ssam 		deflab( p->bn.label );
19625828Ssam 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
19725828Ssam 		deflab( m );
19825828Ssam 		return;
19925828Ssam 
20025828Ssam 	case 'P':
20125828Ssam 		cbgen( p->in.op, p->bn.label, c );
20225828Ssam 		return;
20325828Ssam 
20432876Sdonn 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
20525828Ssam 		{
20632876Sdonn 		register NODE *l, *r, *s;
20732876Sdonn 		int lt, rt;
20825828Ssam 
20932876Sdonn 		l = p->in.left;
21032876Sdonn 		r = p->in.right;
21132876Sdonn 		s = talloc();
21232876Sdonn 		rt = r->in.type;
21332876Sdonn 		lt = l->in.type;
21425828Ssam 
21532876Sdonn 		if (lt != INT && lt != UNSIGNED) {
21632876Sdonn 			s->in.op = SCONV;
21732876Sdonn 			s->in.left = l;
21832876Sdonn 			s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
21932876Sdonn 			zzzcode(s, 'U');
22032876Sdonn 			putstr("\n\t");
22125828Ssam 		}
22232876Sdonn 
22332876Sdonn 		if (ISUNSIGNED(lt)) {
22432876Sdonn 			s->in.op = SCONV;
22532876Sdonn 			s->in.left = lt == UNSIGNED ? l : resc;
22632876Sdonn 			s->in.type = rt;
22732876Sdonn 			unsigned_to_float(s);
22832876Sdonn 		} else {
22932876Sdonn 			putstr("cvl");
23032876Sdonn 			prtype(r);
23132876Sdonn 			putchar('\t');
23232876Sdonn 			adrput(lt == INT ? l : resc);
23332876Sdonn 		}
23432876Sdonn 		putstr("\n\t");
23532876Sdonn 
23632876Sdonn 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
23726162Ssam 		putchar('\t');
23825828Ssam 		adrput(r);
23932876Sdonn 
24032876Sdonn 		if (ISUNSIGNED(lt)) {
24132876Sdonn 			putstr("\n\t");
24232876Sdonn 			s->in.op = SCONV;
24332876Sdonn 			s->in.left = r;		/* we need only the type */
24432876Sdonn 			s->in.type = UNSIGNED;
24532876Sdonn 			float_to_unsigned(s);
24632876Sdonn 		} else {
24732876Sdonn 			putstr("\n\tcv");
24832876Sdonn 			prtype(r);
24932876Sdonn 			putstr("l\t");
25032876Sdonn 			if (lt == INT)
25132876Sdonn 				adrput(l);
25232876Sdonn 			else
25332876Sdonn 				adrput(resc);
25432876Sdonn 		}
25532876Sdonn 		if (lt != INT) {
25632876Sdonn 			putstr("\n\t");
25732876Sdonn 			s->in.op = ASSIGN;
25832876Sdonn 			s->in.left = l;
25932876Sdonn 			s->in.right = resc;
26032876Sdonn 			s->in.type = lt;
26132876Sdonn 			zzzcode(s, 'U');
26232876Sdonn 		}
26332876Sdonn 
26432876Sdonn 		s->in.op = FREE;
26525828Ssam 		return;
26625828Ssam 		}
26725828Ssam 
26832886Sdonn 	case 'J':	/* unsigned DIV/MOD with constant divisors */
26932886Sdonn 		{
27032886Sdonn 		register int ck = INAREG;
27132886Sdonn 		int label1, label2;
27232886Sdonn 
27332886Sdonn 		/* case constant <= 1 is handled by optim() in pass 1 */
27432886Sdonn 		/* case constant < 0x80000000 is handled in table */
27532886Sdonn 		switch( p->in.op ) {
27632887Sdonn 		/* case DIV: handled in optim2() */
27732886Sdonn 		case MOD:
27832886Sdonn 			if( p->in.left->in.op == REG &&
27932886Sdonn 			    p->in.left->tn.rval == resc->tn.rval )
28032886Sdonn 				goto asgmod;
28132886Sdonn 			label1 = getlab();
28232886Sdonn 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
28332886Sdonn 			printf("\tjlssu\tL%d\n", label1);
28432886Sdonn 			expand(p, ck, "\tsubl2\tAR,A1\n");
28532886Sdonn 			printf("L%d:", label1);
28632886Sdonn 			break;
28732886Sdonn 		case ASG DIV:
28832886Sdonn 			label1 = getlab();
28932886Sdonn 			label2 = getlab();
29032886Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
29132886Sdonn 			printf("\tjgequ\tL%d\n", label1);
29232886Sdonn 			expand(p, ck, "\tmovl\t$1,AL\n");
29332886Sdonn 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
29432886Sdonn 			expand(p, ck, "\tclrl\tAL\n");
29532886Sdonn 			printf("L%d:", label2);
29632886Sdonn 			break;
29732886Sdonn 		case ASG MOD:
29832886Sdonn 		asgmod:
29932886Sdonn 			label1 = getlab();
30032886Sdonn 			expand(p, ck, "cmpl\tAL,AR\n");
30132886Sdonn 			printf("\tjlssu\tL%d\n", label1);
30232886Sdonn 			expand(p, ck, "\tsubl2\tAR,AL\n");
30332886Sdonn 			printf("L%d:", label1);
30432886Sdonn 			break;
30532886Sdonn 			}
30632886Sdonn 		return;
30732886Sdonn 		}
30832886Sdonn 
30925828Ssam 	case 'B':	/* get oreg value in temp register for shift */
31025828Ssam 		{
31125828Ssam 		register NODE *r;
31225828Ssam 		if (xdebug) eprint(p, 0, &val, &val);
31325828Ssam 		r = p->in.right;
31432886Sdonn 		if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
31526162Ssam 			putstr("movl");
31625828Ssam 		else {
31726162Ssam 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
31825828Ssam 			prtype(r);
31926162Ssam 			putchar('l');
32025828Ssam 			}
32125828Ssam 		return;
32225828Ssam 		}
32325828Ssam 
32432886Sdonn 	case 'C':	/* generate 'call[fs] $bytes' */
32525828Ssam 		{
32625828Ssam 		extern int gc_numbytes;
32725828Ssam 		extern int xdebug;
32825828Ssam 
32925828Ssam 		if (xdebug) printf("->%d<-",gc_numbytes);
33025828Ssam 
33125828Ssam 		printf("call%c	$%d",
33225828Ssam 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
33325828Ssam 		 gc_numbytes+4);
33432886Sdonn 		/* don't change to double (here's the only place to catch it) */
33525828Ssam 		if(p->in.type == FLOAT)
33625828Ssam 			rtyflg = 1;
33725828Ssam 		return;
33825828Ssam 		}
33925828Ssam 
34025828Ssam 	case 'D':	/* INCR and DECR */
34133413Sdonn 		if (p->in.left->in.type == FLOAT)
34233413Sdonn 			expand(p, INAREG, "movl\tAL,A1");
34333413Sdonn 		else if (p->in.left->in.type == DOUBLE)
34433413Sdonn 			expand(p, INAREG, "ldd\tAL\n\tstd\tA1");
34533413Sdonn 		else
34633413Sdonn 			zzzcode(p->in.left, 'U');
34726162Ssam 		putstr("\n	");
34825828Ssam 
34925828Ssam 	case 'E':	/* INCR and DECR, FOREFF */
35033368Sdonn  		if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
35125828Ssam 			{
35226162Ssam 			putstr(p->in.op == INCR ? "inc" : "dec");
35325828Ssam 			prtype(p->in.left);
35426162Ssam 			putchar('\t');
35525828Ssam 			adrput(p->in.left);
35625828Ssam 			return;
35725828Ssam 			}
35833368Sdonn 		else if (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE) {
35933413Sdonn 			if (c == 'E' || p->in.left->in.type == FLOAT)
36033413Sdonn 				expand(p, INAREG, "ldZL\tAL\n\t");
36133368Sdonn 			if (p->in.op == INCR)
36233413Sdonn 				expand(p, INAREG, "addZL\tAR\n\tstZL\tAL");
36333368Sdonn 			else /* DECR */
36433413Sdonn 				expand(p, INAREG, "subZL\tAR\n\tstZL\tAL");
36533368Sdonn 			return;
36633368Sdonn 			}
36726162Ssam 		putstr(p->in.op == INCR ? "add" : "sub");
36825828Ssam 		prtype(p->in.left);
36926162Ssam 		putstr("2	");
37025828Ssam 		adrput(p->in.right);
37126162Ssam 		putchar(',');
37225828Ssam 		adrput(p->in.left);
37325828Ssam 		return;
37425828Ssam 
37525828Ssam 	case 'F':	/* masked constant for fields */
37625947Ssam 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
37725828Ssam 		return;
37825828Ssam 
37932884Sdonn 	case 'I':	/* produce value of bitfield assignment */
38032884Sdonn 			/* avoid shifts -- shifts are SLOW on this machine */
38132887Sdonn 			/* XXX this wouldn't be necessary if we were smarter
38232887Sdonn 			       and masked BEFORE shifting XXX */
38332884Sdonn 		{
38432886Sdonn 		register NODE *r = p->in.right;
38532886Sdonn 		if(r->in.op == ICON && r->tn.name[0] == '\0') {
38632886Sdonn 			putstr("movl\t");
38732886Sdonn 			printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
38832886Sdonn 			}
38932886Sdonn 		else {
39032886Sdonn 			putstr("andl3\t");
39132886Sdonn 			printf(ACONFMT, (1 << fldsz) - 1);
39232884Sdonn 			putchar(',');
39332886Sdonn 			adrput(r);
39432884Sdonn 			}
39532886Sdonn 		putchar(',');
39632886Sdonn 		adrput(resc);
39732886Sdonn 		break;
39832886Sdonn 		}
39932884Sdonn 
40025828Ssam 	case 'H':	/* opcode for shift */
40125828Ssam 		if(p->in.op == LS || p->in.op == ASG LS)
40226162Ssam 			putstr("shll");
40325828Ssam 		else if(ISUNSIGNED(p->in.left->in.type))
40426162Ssam 			putstr("shrl");
40525828Ssam 		else
40626162Ssam 			putstr("shar");
40725828Ssam 		return;
40825828Ssam 
40925828Ssam 	case 'L':	/* type of left operand */
41025828Ssam 	case 'R':	/* type of right operand */
41125828Ssam 		{
41225828Ssam 		register NODE *n;
41325828Ssam 		extern int xdebug;
41425828Ssam 
41525828Ssam 		n = getlr ( p, c);
41625828Ssam 		if (xdebug) printf("->%d<-", n->in.type);
41725828Ssam 
41825828Ssam 		prtype(n);
41925828Ssam 		return;
42025828Ssam 		}
42125828Ssam 
42230360Ssam 	case 'M': {  /* initiate ediv for mod and unsigned div */
42332887Sdonn 		putstr("clrl\t");
42432887Sdonn 		adrput(resc);
42532887Sdonn 		putstr("\n\tmovl\t");
42625828Ssam 		adrput(p->in.left);
42732887Sdonn 		putchar(',');
42832887Sdonn 		upput(resc, SZLONG);
42932887Sdonn 		printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
43032887Sdonn 		adrput(resc);
43132887Sdonn 		putchar('\n');
43232887Sdonn 		deflab(m);
43325828Ssam 		return;
43430360Ssam 	}
43525828Ssam 
43630360Ssam 	case 'T': {	/* rounded structure length for arguments */
43730360Ssam 		int size = p->stn.stsize;
43825828Ssam 		SETOFF( size, 4);
43925828Ssam 		printf("movab	-%d(sp),sp", size);
44025828Ssam 		return;
44130360Ssam 	}
44225828Ssam 
44325828Ssam 	case 'S':  /* structure assignment */
44425977Ssam 		stasg(p);
44525977Ssam 		break;
44625828Ssam 
44732886Sdonn #ifdef I_don_t_understand_this
44829672Ssam 	case 'X':	/* multiplication for short and char */
44929672Ssam 		if (ISUNSIGNED(p->in.left->in.type))
45029672Ssam 			printf("\tmovz");
45129672Ssam 		else
45229672Ssam 			printf("\tcvt");
45329672Ssam 		zzzcode(p, 'L');
45429672Ssam 		printf("l\t");
45529672Ssam 		adrput(p->in.left);
45629672Ssam 		printf(",");
45729672Ssam 		adrput(&resc[0]);
45829672Ssam 		printf("\n");
45929672Ssam 		if (ISUNSIGNED(p->in.right->in.type))
46029672Ssam 			printf("\tmovz");
46129672Ssam 		else
46229672Ssam 			printf("\tcvt");
46329672Ssam 		zzzcode(p, 'R');
46429672Ssam 		printf("l\t");
46529672Ssam 		adrput(p->in.right);
46629672Ssam 		printf(",");
46729672Ssam 		adrput(&resc[1]);
46829672Ssam 		printf("\n");
46929672Ssam 		return;
47032886Sdonn #endif
47129672Ssam 
47230360Ssam 	case 'U':		/* SCONV */
47330360Ssam 	case 'V':		/* SCONV with FORCC */
47430360Ssam 		sconv(p, c == 'V');
47530360Ssam 		break;
47630360Ssam 
47732879Sdonn 	case 'W': {		/* SCONV or ASSIGN float/double => unsigned */
47832879Sdonn 		NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
47932879Sdonn 
48032876Sdonn 		putstr("ld");
48132879Sdonn 		prtype(src);
48232876Sdonn 		putchar('\t');
48332879Sdonn 		adrput(src);
48432876Sdonn 		putstr("\n\t");
48532876Sdonn 		float_to_unsigned(p);
48632876Sdonn 		break;
48732879Sdonn 	}
48832876Sdonn 
48932879Sdonn 	case 'Y':		/* SCONV or ASSIGN unsigned => float/double */
49032876Sdonn 		unsigned_to_float(p);	/* stores into accumulator */
49132876Sdonn 		putstr("\n\tst");
49232876Sdonn 		prtype(p);
49332876Sdonn 		putchar('\t');
49432879Sdonn 		if (p->in.op == SCONV)
49532879Sdonn 			adrput(resc);
49632879Sdonn 		else
49732879Sdonn 			adrput(p->in.left);
49832879Sdonn 		rtyflg = 1;
49932876Sdonn 		break;
50032876Sdonn 
50132886Sdonn #ifdef I_don_t_understand_this
50230360Ssam 	case 'Z':
50330360Ssam 		p = p->in.right;
50430360Ssam 		switch (p->in.type) {
50530360Ssam 		case SHORT: {
50630360Ssam 			short w = p->tn.lval;
50730360Ssam 			p->tn.lval = w;
50830360Ssam 			break;
50930360Ssam 		}
51030360Ssam 		case CHAR: {
51130360Ssam 			char c = p->tn.lval;
51230360Ssam 			p->tn.lval = c;
51330360Ssam 			break;
51430360Ssam 		}
51530360Ssam 		}
51630360Ssam 		printf("$%d", p->tn.lval);
51730360Ssam 		break;
51832886Sdonn #endif
51930360Ssam 
52025977Ssam 	default:
52125977Ssam 		cerror( "illegal zzzcode" );
52225977Ssam 	}
52330360Ssam }
52425828Ssam 
52525977Ssam #define	MOVB(dst, src, off) { \
52626162Ssam 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
52725977Ssam 	upput(dst, off); putchar('\n'); \
52825977Ssam }
52925977Ssam #define	MOVW(dst, src, off) { \
53026162Ssam 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
53125977Ssam 	upput(dst, off); putchar('\n'); \
53225977Ssam }
53325977Ssam #define	MOVL(dst, src, off) { \
53426162Ssam 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
53525977Ssam 	upput(dst, off); putchar('\n'); \
53625977Ssam }
53725977Ssam /*
53825977Ssam  * Generate code for a structure assignment.
53925977Ssam  */
stasg(p)54025977Ssam stasg(p)
54125977Ssam 	register NODE *p;
54225977Ssam {
54325977Ssam 	register NODE *l, *r;
54425977Ssam 	register int size;
54525828Ssam 
54625977Ssam 	switch (p->in.op) {
54725977Ssam 	case STASG:			/* regular assignment */
54825977Ssam 		l = p->in.left;
54925977Ssam 		r = p->in.right;
55025977Ssam 		break;
55125977Ssam 	case STARG:			/* place arg on the stack */
55225977Ssam 		l = getlr(p, '3');
55325977Ssam 		r = p->in.left;
55425977Ssam 		break;
55525977Ssam 	default:
55625977Ssam 		cerror("STASG bad");
55725977Ssam 		/*NOTREACHED*/
55825977Ssam 	}
55925977Ssam 	/*
56025977Ssam 	 * Pun source for use in code generation.
56125977Ssam 	 */
56225977Ssam 	switch (r->in.op) {
56325977Ssam 	case ICON:
56425977Ssam 		r->in.op = NAME;
56525977Ssam 		break;
56625977Ssam 	case REG:
56725977Ssam 		r->in.op = OREG;
56825977Ssam 		break;
56925977Ssam 	default:
57025977Ssam 		cerror( "STASG-r" );
57125977Ssam 		/*NOTREACHED*/
57225977Ssam 	}
57325977Ssam 	size = p->stn.stsize;
57425977Ssam 	if (size <= 0 || size > 65535)
57525977Ssam 		cerror("structure size out of range");
57625977Ssam 	/*
57725977Ssam 	 * Generate optimized code based on structure size
57825977Ssam 	 * and alignment properties....
57925977Ssam 	 */
58025977Ssam 	switch (size) {
58125828Ssam 
58225977Ssam 	case 1:
58326162Ssam 		putstr("\tmovb\t");
58425977Ssam 	optimized:
58525977Ssam 		adrput(r);
58626162Ssam 		putchar(',');
58725977Ssam 		adrput(l);
58826162Ssam 		putchar('\n');
58925977Ssam 		break;
59025828Ssam 
59125977Ssam 	case 2:
59225977Ssam 		if (p->stn.stalign != 2) {
59325977Ssam 			MOVB(l, r, SZCHAR);
59426162Ssam 			putstr("\tmovb\t");
59525977Ssam 		} else
59626162Ssam 			putstr("\tmovw\t");
59725977Ssam 		goto optimized;
59825977Ssam 
59925977Ssam 	case 4:
60025977Ssam 		if (p->stn.stalign != 4) {
60125977Ssam 			if (p->stn.stalign != 2) {
60225977Ssam 				MOVB(l, r, 3*SZCHAR);
60325977Ssam 				MOVB(l, r, 2*SZCHAR);
60425977Ssam 				MOVB(l, r, 1*SZCHAR);
60526162Ssam 				putstr("\tmovb\t");
60625947Ssam 			} else {
60725977Ssam 				MOVW(l, r, SZSHORT);
60826162Ssam 				putstr("\tmovw\t");
60925828Ssam 			}
61025977Ssam 		} else
61126162Ssam 			putstr("\tmovl\t");
61225977Ssam 		goto optimized;
61325828Ssam 
61425977Ssam 	case 6:
61525977Ssam 		if (p->stn.stalign != 2)
61625977Ssam 			goto movblk;
61725977Ssam 		MOVW(l, r, 2*SZSHORT);
61825977Ssam 		MOVW(l, r, 1*SZSHORT);
61926162Ssam 		putstr("\tmovw\t");
62025977Ssam 		goto optimized;
62125977Ssam 
62225977Ssam 	case 8:
62325977Ssam 		if (p->stn.stalign == 4) {
62425977Ssam 			MOVL(l, r, SZLONG);
62526162Ssam 			putstr("\tmovl\t");
62625977Ssam 			goto optimized;
62725977Ssam 		}
62825977Ssam 		/* fall thru...*/
62925977Ssam 
63025977Ssam 	default:
63125977Ssam 	movblk:
63225977Ssam 		/*
63325977Ssam 		 * Can we ever get a register conflict with R1 here?
63425977Ssam 		 */
63526162Ssam 		putstr("\tmovab\t");
63632890Sdonn 		if(r->in.op == OREG && r->tn.rval == R1)
63732890Sdonn 		{
63832890Sdonn 			adrput(r);
63932890Sdonn 			printf(",r0\n\tmovab\t");
64032890Sdonn 			adrput(l);
64132890Sdonn 			putstr(",r1\n");
64232890Sdonn 		}
64332890Sdonn 		else
64432890Sdonn 		{
64532890Sdonn 			adrput(l);
64632890Sdonn 			putstr(",r1\n\tmovab\t");
64732890Sdonn 			adrput(r);
64832890Sdonn 			printf(",r0\n");
64932890Sdonn 		}
65032890Sdonn 		printf("\tmovl\t$%d,r2\n\tmovblk\n", size);
65125977Ssam 		rname(R2);
65225828Ssam 		break;
65325977Ssam 	}
65425977Ssam 	/*
65525977Ssam 	 * Reverse above pun for reclaim.
65625977Ssam 	 */
65725977Ssam 	if (r->in.op == NAME)
65825977Ssam 		r->in.op = ICON;
65925977Ssam 	else if (r->in.op == OREG)
66025977Ssam 		r->in.op = REG;
66125977Ssam }
66225828Ssam 
66325977Ssam /*
66432876Sdonn  * Convert a float or double in the accumulator into an unsigned int.
66532876Sdonn  * Unlike the vax, the tahoe stores 0 into the destination
66632876Sdonn  *	on a conversion of > 2 ** 31, so we compensate.
66732876Sdonn  */
float_to_unsigned(p)66832876Sdonn float_to_unsigned(p)
66932876Sdonn 	NODE *p;
67032876Sdonn {
67132876Sdonn 	register NODE *l = p->in.left;
67232876Sdonn 	int label1 = getlab();
67332876Sdonn 	int label2 = getlab();
67432876Sdonn 	int label3 = getlab();
67532879Sdonn 	NODE *src, *dst;
67632876Sdonn 
67732879Sdonn 	if (p->in.op == SCONV) {
67832879Sdonn 		src = p->in.left;
67932879Sdonn 		dst = resc;
68032879Sdonn 	} else {
68132879Sdonn 		src = p->in.right;
68232879Sdonn 		dst = p->in.left;
68332879Sdonn 	}
68432879Sdonn 
68532876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
68632879Sdonn 	if (src->in.type == DOUBLE)
68732879Sdonn 		putstr(", 0x00000000 # .double");
68832879Sdonn 	else
68932879Sdonn 		putstr(" # .float");
69032879Sdonn 	putstr(" 2147483648\n\t.text\n\tcmp");
69132879Sdonn 	prtype(src);
69232876Sdonn 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
69332879Sdonn 	prtype(src);
69432876Sdonn 	printf("\tL%d\n\tcv", label1);
69532879Sdonn 	prtype(src);
69632876Sdonn 	putstr("l\t");
69732879Sdonn 	adrput(dst);
69832876Sdonn 	putstr("\n\taddl2\t$-2147483648,");
69932879Sdonn 	adrput(dst);
70032876Sdonn 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
70132879Sdonn 	prtype(src);
70232876Sdonn 	putstr("l\t");
70332879Sdonn 	adrput(dst);
70432876Sdonn 	printf("\nL%d:", label3);
70532876Sdonn }
70632876Sdonn 
70732876Sdonn /*
70832876Sdonn  * Convert an unsigned int into a float or double, leaving the result
70932876Sdonn  *	in the accumulator.
71032876Sdonn  */
unsigned_to_float(p)71132876Sdonn unsigned_to_float(p)
71232876Sdonn 	register NODE *p;
71332876Sdonn {
71432876Sdonn 	int label1 = getlab();
71532876Sdonn 	int label2 = getlab();
71632879Sdonn 	NODE *src, *dst;
71732876Sdonn 
71832879Sdonn 	if (p->in.op == SCONV) {
71932879Sdonn 		src = p->in.left;
72032879Sdonn 		dst = resc;
72132879Sdonn 	} else {
72232879Sdonn 		src = p->in.right;
72332879Sdonn 		dst = p->in.left;
72432879Sdonn 	}
72532879Sdonn 
72632876Sdonn 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
72732876Sdonn 	if (p->in.type == DOUBLE)
72832879Sdonn 		putstr(", 0x00000000 # .double");
72932879Sdonn 	else
73032879Sdonn 		putstr(" # .float");
73132879Sdonn 	putstr(" 4294967296\n\t.text\n\tmovl\t");
73232879Sdonn 	adrput(src);
73332876Sdonn 	putchar(',');
73432879Sdonn 	adrput(dst);
73532876Sdonn 	putstr("\n\tcvl");
73632876Sdonn 	prtype(p);
73732876Sdonn 	putchar('\t');
73832879Sdonn 	adrput(dst);
73932879Sdonn 	printf("\n\tjgeq\tL%d\n\tadd", label1);
74032879Sdonn 	prtype(p);
74132879Sdonn 	printf("\tL%d\nL%d:", label2, label1);
74232876Sdonn }
74332876Sdonn 
74432876Sdonn /*
74532875Sdonn  * Prlen() is a cheap prtype()...
74632875Sdonn  */
74732875Sdonn static char convtab[SZINT/SZCHAR + 1] = {
74832875Sdonn 	'?', 'b', 'w', '?', 'l'
74932875Sdonn };
75032875Sdonn #define	prlen(len)	putchar(convtab[len])
75132875Sdonn 
75232875Sdonn 
75332875Sdonn /*
75432873Sdonn  * Generate code for integral scalar conversions.
75532875Sdonn  * Some of this code is designed to work around a tahoe misfeature
75632875Sdonn  *	that causes sign- and zero- extension to be defeated in
75732875Sdonn  *	certain circumstances.
75832875Sdonn  * Basically if the source operand of a CVT or MOVZ instruction is
75932875Sdonn  *	shorter than the destination, and the source is a register
76032875Sdonn  *	or an immediate constant, sign- and zero- extension are
76132875Sdonn  *	ignored and the high bits of the source are copied.  (Note
76232875Sdonn  *	that zero-extension is not a problem for immediate
76332875Sdonn  *	constants.)
76433351Sdonn  * Another problem -- condition codes for a conversion with a
76533351Sdonn  *	register source reflect the source rather than the destination.
76632873Sdonn  */
sconv(p,forcc)76732873Sdonn sconv(p, forcc)
76832873Sdonn 	NODE *p;
76932873Sdonn 	int forcc;
77032873Sdonn {
77132873Sdonn 	register NODE *src, *dst;
77232873Sdonn 	register NODE *tmp;
77332873Sdonn 	register int srclen, dstlen;
77432873Sdonn 	int srctype, dsttype;
77532873Sdonn 	int val;
77632882Sdonn 	int neg = 0;
77730360Ssam 
77832873Sdonn 	if (p->in.op == ASSIGN) {
77932879Sdonn 		src = p->in.right;
78032879Sdonn 		dst = p->in.left;
78132873Sdonn 		dstlen = tlen(dst);
78232873Sdonn 		dsttype = dst->in.type;
78332879Sdonn 	} else if (p->in.op == SCONV) {
78432879Sdonn 		src = p->in.left;
78532879Sdonn 		dst = resc;
78632873Sdonn 		dstlen = tlen(p);
78732873Sdonn 		dsttype = p->in.type;
78832879Sdonn 	} else /* if (p->in.op == OPLEAF) */ {
78932879Sdonn 		src = p;
79032879Sdonn 		dst = resc;
79132879Sdonn 		dstlen = SZINT/SZCHAR;
79232879Sdonn 		dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
79332873Sdonn 	}
79432873Sdonn 
79532875Sdonn 	if (src->in.op == REG) {
79632875Sdonn 		srclen = SZINT/SZCHAR;
79732875Sdonn 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
79832875Sdonn 	} else {
79932875Sdonn 		srclen = tlen(src);
80032875Sdonn 		srctype = src->in.type;
80132875Sdonn 	}
80232873Sdonn 
80332882Sdonn 	if (src->in.op == ICON && src->tn.name[0] == '\0') {
80432875Sdonn 		if (src->tn.lval == 0) {
80532875Sdonn 			putstr("clr");
80632875Sdonn 			prtype(dst);
80732875Sdonn 			putchar('\t');
80832875Sdonn 			adrput(dst);
80932875Sdonn 			return;
81032875Sdonn 		}
81132875Sdonn 		if (dstlen < srclen) {
81232875Sdonn 			switch (dsttype) {
81332875Sdonn 			case CHAR:
81432875Sdonn 				src->tn.lval = (char) src->tn.lval;
81532875Sdonn 				break;
81632875Sdonn 			case UCHAR:
81732875Sdonn 				src->tn.lval = (unsigned char) src->tn.lval;
81832875Sdonn 				break;
81932875Sdonn 			case SHORT:
82032875Sdonn 				src->tn.lval = (short) src->tn.lval;
82132875Sdonn 				break;
82232875Sdonn 			case USHORT:
82332875Sdonn 				src->tn.lval = (unsigned short) src->tn.lval;
82432875Sdonn 				break;
82532875Sdonn 			}
82632875Sdonn 		}
82732875Sdonn 		if (dst->in.op == REG) {
82832875Sdonn 			dsttype = INT;
82932875Sdonn 			dstlen = SZINT/SZCHAR;
83032875Sdonn 		}
83132875Sdonn 		srctype = dsttype;
83232875Sdonn 		srclen = dstlen;
83332887Sdonn 		val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
83432887Sdonn 		if ((unsigned) val < 64) {
83532887Sdonn 			src->tn.lval = val;
83632882Sdonn 			++neg;		/* MNEGx may be shorter */
83732882Sdonn 		}
83832875Sdonn 	}
83932875Sdonn 
84032873Sdonn 	if (srclen < dstlen) {
84132873Sdonn 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
84232873Sdonn 			/* (unsigned short) c; => sign extend to 16 bits */
84332874Sdonn 			putstr("cvtbl\t");
84432873Sdonn 			adrput(src);
84532873Sdonn 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
84632873Sdonn 			adrput(dst);
84732873Sdonn 			putstr("\n\tmovab\t4(sp),sp");
84832873Sdonn 			if (forcc) {
849*33622Sdonn 				putstr("\n\ttstl\t");
85032873Sdonn 				adrput(dst);
85132873Sdonn 			}
85232873Sdonn 			return;
85332873Sdonn 		}
85432873Sdonn 		genconv(ISUNSIGNED(srctype),
85532873Sdonn 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
85633351Sdonn 			src, dst, forcc);
85732873Sdonn 		return;
85832873Sdonn 	}
85932873Sdonn 
86032873Sdonn 	if (srclen > dstlen && dst->in.op == REG) {
86132875Sdonn 		/* if dst is a register, the result must look like an int */
86232873Sdonn 		if (src->in.op == REG) {
86332873Sdonn 			if (ISUNSIGNED(dsttype)) {
86432873Sdonn 				val = (1 << dstlen * SZCHAR) - 1;
86532873Sdonn 				if (src->tn.rval == dst->tn.rval)
86632873Sdonn 					/* conversion in place */
86732887Sdonn 					printf("andl2\t$%ld,", val);
86832873Sdonn 				else {
86932887Sdonn 					printf("andl3\t$%ld,", val);
87032873Sdonn 					adrput(src);
87132873Sdonn 					putchar(',');
87232873Sdonn 				}
87332873Sdonn 				adrput(dst);
87432873Sdonn 				return;
87532873Sdonn 			}
87632875Sdonn 			/*
87732875Sdonn 			 * Sign extension in register can also be
87832875Sdonn 			 * accomplished by shifts, but unfortunately
87932875Sdonn 			 * shifts are extremely slow, due to the lack
88032875Sdonn 			 * of a barrel shifter.
88132875Sdonn 			 */
88232875Sdonn 			putstr("pushl\t");
88332873Sdonn 			adrput(src);
88432875Sdonn 			putstr("\n\tcvt");
88532875Sdonn 			prlen(dstlen);
88632875Sdonn 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
88732873Sdonn 			adrput(dst);
88832875Sdonn 			putstr("\n\tmovab\t4(sp),sp");
88932875Sdonn 			if (forcc) {
890*33622Sdonn 				putstr("\n\ttstl\t");
89132875Sdonn 				adrput(dst);
89232875Sdonn 			}
89332873Sdonn 			return;
89432873Sdonn 		}
89532873Sdonn 		tmp = talloc();
89632887Sdonn 		if ((src->in.op == NAME) ||
89732887Sdonn 		    (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
89832873Sdonn 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
89932873Sdonn 			/* we can increment src's address & pun it */
90032873Sdonn 			*tmp = *src;
90132873Sdonn 			tmp->tn.lval += srclen - dstlen;
90232873Sdonn 		} else {
90332873Sdonn 			/* we must store src's address */
90432873Sdonn 			*tmp = *dst;
90532875Sdonn 			putstr("mova");
90632875Sdonn 			prlen(srclen);
90732875Sdonn 			putchar('\t');
90832873Sdonn 			adrput(src);
90932873Sdonn 			putchar(',');
91032873Sdonn 			adrput(tmp);
91132874Sdonn 			putstr("\n\t");
91232873Sdonn 			tmp->tn.op = OREG;
91332873Sdonn 			tmp->tn.lval = srclen - dstlen;
91432873Sdonn 		}
91533351Sdonn 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
91632873Sdonn 		tmp->in.op = FREE;
91732873Sdonn 		return;
91832873Sdonn 	}
91932873Sdonn 
92032882Sdonn 	genconv(neg ? -1 : ISUNSIGNED(dsttype),
92132873Sdonn 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
92233351Sdonn 		src, dst, forcc);
92332873Sdonn }
92432873Sdonn 
genconv(srcflag,srclen,dstlen,src,dst,forcc)92533351Sdonn genconv(srcflag, srclen, dstlen, src, dst, forcc)
92632882Sdonn 	int srcflag;
92732875Sdonn 	register int srclen, dstlen;
92832873Sdonn 	NODE *src, *dst;
92933351Sdonn 	int forcc;
93032873Sdonn {
93132873Sdonn 	if (srclen != dstlen) {
93232882Sdonn 		if (srcflag > 0 && srclen < dstlen)
93332874Sdonn 			putstr("movz");
93432873Sdonn 		else
93532874Sdonn 			putstr("cvt");
93632875Sdonn 		prlen(srclen);
93732882Sdonn 	} else if (srcflag < 0)
93832882Sdonn 		putstr("mneg");
93932882Sdonn 	else
94032874Sdonn 		putstr("mov");
94132875Sdonn 	prlen(dstlen);
94232873Sdonn 	putchar('\t');
94332873Sdonn 	adrput(src);
94432873Sdonn 	putchar(',');
94532873Sdonn 	adrput(dst);
94633351Sdonn 
94733351Sdonn 	/*
94833351Sdonn 	 * This hack is made necessary by architecture problems
94933351Sdonn 	 *	described above
95033351Sdonn 	 */
95133351Sdonn 	if (forcc && src->in.op == REG && srclen > dstlen) {
95233351Sdonn 		putstr("\n\ttst");
95333351Sdonn 		prlen(dstlen);
95433351Sdonn 		putchar('\t');
95533351Sdonn 		adrput(dst);
95633351Sdonn 	}
95732873Sdonn }
95832873Sdonn 
rmove(rt,rs,t)95932886Sdonn rmove( rt, rs, t ) TWORD t; {
96025828Ssam 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
96125828Ssam 	if(t==DOUBLE)
96225828Ssam 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
96325828Ssam 	}
96425828Ssam 
96525828Ssam struct respref
96625828Ssam respref[] = {
96725828Ssam 	INTAREG|INTBREG,	INTAREG|INTBREG,
96825828Ssam 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
96925828Ssam 	INTEMP,	INTEMP,
97025828Ssam 	FORARG,	FORARG,
97125828Ssam 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
97225828Ssam 	0,	0 };
97325828Ssam 
setregs()97425828Ssam setregs(){ /* set up temporary registers */
97525828Ssam 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
97625828Ssam 	}
97725828Ssam 
97826076Ssam #ifndef szty
szty(t)97925828Ssam szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
98025828Ssam 	return(t==DOUBLE ? 2 : 1 );
98125828Ssam 	}
98226076Ssam #endif
98325828Ssam 
98432886Sdonn /*ARGSUSED*/
rewfld(p)98525828Ssam rewfld( p ) NODE *p; {
98625828Ssam 	return(1);
98725828Ssam 	}
98825828Ssam 
98932886Sdonn /*ARGSUSED*/
callreg(p)99025828Ssam callreg(p) NODE *p; {
99125828Ssam 	return( R0 );
99225828Ssam 	}
99325828Ssam 
base(p)99425828Ssam base( p ) register NODE *p; {
99525828Ssam 	register int o = p->in.op;
99625828Ssam 
99732887Sdonn 	if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
99825828Ssam 	if( o==REG ) return( p->tn.rval );
99925828Ssam     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
100025828Ssam 		return( p->in.left->tn.rval );
100125828Ssam     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
100225828Ssam 		return( p->tn.rval + 0200*1 );
100332887Sdonn 	if( o==NAME ) return( 100 + 0200*1 );
100425828Ssam 	return( -1 );
100525828Ssam 	}
100625828Ssam 
offset(p,tyl)100725828Ssam offset( p, tyl ) register NODE *p; int tyl; {
100825828Ssam 
100932886Sdonn 	if( tyl==1 &&
101032886Sdonn 	    p->in.op==REG &&
101132886Sdonn 	    (p->in.type==INT || p->in.type==UNSIGNED) )
101232886Sdonn 		return( p->tn.rval );
101332886Sdonn 	if( p->in.op==LS &&
101432886Sdonn 	    p->in.left->in.op==REG &&
101532886Sdonn 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
101632886Sdonn 	    p->in.right->in.op==ICON &&
101732886Sdonn 	    p->in.right->in.name[0]=='\0' &&
101832886Sdonn 	    (1<<p->in.right->tn.lval)==tyl)
101925828Ssam 		return( p->in.left->tn.rval );
102032886Sdonn 	if( tyl==2 &&
102132886Sdonn 	    p->in.op==PLUS &&
102232886Sdonn 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
102332886Sdonn 	    p->in.left->in.op==REG &&
102432886Sdonn 	    p->in.right->in.op==REG &&
102532886Sdonn 	    p->in.left->tn.rval==p->in.right->tn.rval )
102632886Sdonn 		return( p->in.left->tn.rval );
102725828Ssam 	return( -1 );
102825828Ssam 	}
102925828Ssam 
makeor2(p,q,b,o)103025828Ssam makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
103125828Ssam 	register NODE *t;
103225828Ssam 	NODE *f;
103325828Ssam 
103425828Ssam 	p->in.op = OREG;
103525828Ssam 	f = p->in.left; 	/* have to free this subtree later */
103625828Ssam 
103725828Ssam 	/* init base */
103825828Ssam 	switch (q->in.op) {
103925828Ssam 		case ICON:
104025828Ssam 		case REG:
104125828Ssam 		case OREG:
104232887Sdonn 		case NAME:
104325828Ssam 			t = q;
104425828Ssam 			break;
104525828Ssam 
104625828Ssam 		case MINUS:
104725828Ssam 			q->in.right->tn.lval = -q->in.right->tn.lval;
104825828Ssam 		case PLUS:
104925828Ssam 			t = q->in.right;
105025828Ssam 			break;
105125828Ssam 
105225828Ssam 		case UNARY MUL:
105325828Ssam 			t = q->in.left->in.left;
105425828Ssam 			break;
105525828Ssam 
105625828Ssam 		default:
105725828Ssam 			cerror("illegal makeor2");
105825828Ssam 	}
105925828Ssam 
106025828Ssam 	p->tn.lval = t->tn.lval;
106125828Ssam #ifndef FLEXNAMES
106232886Sdonn 	{
106332886Sdonn 		register int i;
106432886Sdonn 		for(i=0; i<NCHNAM; ++i)
106532886Sdonn 			p->in.name[i] = t->in.name[i];
106632886Sdonn 	}
106725828Ssam #else
106825828Ssam 	p->in.name = t->in.name;
106925828Ssam #endif
107025828Ssam 
107125828Ssam 	/* init offset */
107225828Ssam 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
107325828Ssam 
107425828Ssam 	tfree(f);
107525828Ssam 	return;
107625828Ssam 	}
107725828Ssam 
canaddr(p)107825828Ssam canaddr( p ) NODE *p; {
107925828Ssam 	register int o = p->in.op;
108025828Ssam 
108125828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
108225828Ssam 	return(0);
108325828Ssam 	}
108425828Ssam 
108526076Ssam #ifndef shltype
shltype(o,p)108625828Ssam shltype( o, p ) register NODE *p; {
108725828Ssam 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
108825828Ssam 	}
108926076Ssam #endif
109025828Ssam 
flshape(p)109125828Ssam flshape( p ) NODE *p; {
109225828Ssam 	register int o = p->in.op;
109325828Ssam 
109425828Ssam 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
109525828Ssam 	return(0);
109625828Ssam 	}
109725828Ssam 
109832886Sdonn /* INTEMP shapes must not contain any temporary registers */
shtemp(p)109925828Ssam shtemp( p ) register NODE *p; {
110032886Sdonn 	int r;
110132886Sdonn 
110225828Ssam 	if( p->in.op == STARG ) p = p->in.left;
110332886Sdonn 
110432886Sdonn 	switch (p->in.op) {
110532886Sdonn 	case REG:
110632886Sdonn 		return( !istreg(p->tn.rval) );
110732886Sdonn 	case OREG:
110832886Sdonn 		r = p->tn.rval;
110932886Sdonn 		if( R2TEST(r) ) {
111032886Sdonn 			if( istreg(R2UPK1(r)) )
111132886Sdonn 				return(0);
111232886Sdonn 			r = R2UPK2(r);
111332886Sdonn 			}
111432886Sdonn 		return( !istreg(r) );
111532886Sdonn 	case UNARY MUL:
111632886Sdonn 		p = p->in.left;
111732886Sdonn 		return( p->in.op != UNARY MUL && shtemp(p) );
111832886Sdonn 		}
111932886Sdonn 
112032886Sdonn 	if( optype( p->in.op ) != LTYPE ) return(0);
112132886Sdonn 	return(1);
112225828Ssam 	}
112325828Ssam 
shumul(p)112425828Ssam shumul( p ) register NODE *p; {
112525828Ssam 	register int o;
112625828Ssam 	extern int xdebug;
112725828Ssam 
112825828Ssam 	if (xdebug) {
112925828Ssam 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
113025828Ssam 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
113125828Ssam 		}
113225828Ssam 
113325828Ssam 	o = p->in.op;
113425828Ssam 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
113525828Ssam 	 && p->in.type != PTR+DOUBLE)
113625828Ssam 		return( STARNM );
113725828Ssam 
113825828Ssam 	return( 0 );
113925828Ssam 	}
114025828Ssam 
special(p,shape)114132887Sdonn special( p, shape ) register NODE *p; {
114232887Sdonn 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
114332887Sdonn 	else return(0);
114432887Sdonn }
114532887Sdonn 
adrcon(val)114625828Ssam adrcon( val ) CONSZ val; {
114725947Ssam 	printf(ACONFMT, val);
114825828Ssam 	}
114925828Ssam 
conput(p)115025828Ssam conput( p ) register NODE *p; {
115125828Ssam 	switch( p->in.op ){
115225828Ssam 
115325828Ssam 	case ICON:
115425828Ssam 		acon( p );
115525828Ssam 		return;
115625828Ssam 
115725828Ssam 	case REG:
115826162Ssam 		putstr(rname(p->tn.rval));
115925828Ssam 		return;
116025828Ssam 
116125828Ssam 	default:
116225828Ssam 		cerror( "illegal conput" );
116325828Ssam 		}
116425828Ssam 	}
116525828Ssam 
116632886Sdonn /*ARGSUSED*/
insput(p)116725828Ssam insput( p ) NODE *p; {
116825828Ssam 	cerror( "insput" );
116925828Ssam 	}
117025828Ssam 
117132886Sdonn /*
117232886Sdonn  * Output the address of the second item in the
117332886Sdonn  * pair pointed to by p.
117432886Sdonn  */
upput(p,size)117532886Sdonn upput(p, size)
117632886Sdonn 	register NODE *p;
117732886Sdonn {
117832886Sdonn 	CONSZ save;
117932886Sdonn 
118032886Sdonn 	if (p->in.op == FLD)
118132886Sdonn 		p = p->in.left;
118232886Sdonn 	switch (p->in.op) {
118332886Sdonn 
118432886Sdonn 	case NAME:
118532886Sdonn 	case OREG:
118632886Sdonn 		save = p->tn.lval;
118732886Sdonn 		p->tn.lval += size/SZCHAR;
118832886Sdonn 		adrput(p);
118932886Sdonn 		p->tn.lval = save;
119032886Sdonn 		break;
119132886Sdonn 
119232886Sdonn 	case REG:
119332886Sdonn 		if (size == SZLONG) {
119432886Sdonn 			putstr(rname(p->tn.rval+1));
119532886Sdonn 			break;
119632886Sdonn 		}
119732886Sdonn 		/* fall thru... */
119832886Sdonn 
119932886Sdonn 	default:
120032886Sdonn 		cerror("illegal upper address op %s size %d",
120132886Sdonn 		    opst[p->tn.op], size);
120232886Sdonn 		/*NOTREACHED*/
120332886Sdonn 	}
120432886Sdonn }
120532886Sdonn 
adrput(p)120625828Ssam adrput( p ) register NODE *p; {
120725828Ssam 	register int r;
120825828Ssam 	/* output an address, with offsets, from p */
120925828Ssam 
121025828Ssam 	if( p->in.op == FLD ){
121125828Ssam 		p = p->in.left;
121225828Ssam 		}
121325828Ssam 	switch( p->in.op ){
121425828Ssam 
121525828Ssam 	case NAME:
121625828Ssam 		acon( p );
121725828Ssam 		return;
121825828Ssam 
121925828Ssam 	case ICON:
122025828Ssam 		/* addressable value of the constant */
122126162Ssam 		putchar('$');
122225828Ssam 		acon( p );
122325828Ssam 		return;
122425828Ssam 
122525828Ssam 	case REG:
122626162Ssam 		putstr(rname(p->tn.rval));
122725828Ssam 		if(p->in.type == DOUBLE)	/* for entry mask */
122825828Ssam 			(void) rname(p->tn.rval+1);
122925828Ssam 		return;
123025828Ssam 
123125828Ssam 	case OREG:
123225828Ssam 		r = p->tn.rval;
123325828Ssam 		if( R2TEST(r) ){ /* double indexing */
123425828Ssam 			register int flags;
123525828Ssam 
123625828Ssam 			flags = R2UPK3(r);
123726162Ssam 			if( flags & 1 ) putchar('*');
123825828Ssam 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
123925828Ssam 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
124025828Ssam 			printf( "[%s]", rname(R2UPK2(r)) );
124125828Ssam 			return;
124225828Ssam 			}
124325828Ssam 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
124425828Ssam 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
124525828Ssam 			printf( CONFMT, p->tn.lval );
124626162Ssam 			putstr( "(fp)" );
124725828Ssam 			return;
124825828Ssam 			}
124925828Ssam 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
125025828Ssam 		printf( "(%s)", rname(p->tn.rval) );
125125828Ssam 		return;
125225828Ssam 
125325828Ssam 	case UNARY MUL:
125425828Ssam 		/* STARNM or STARREG found */
125525828Ssam 		if( tshape(p, STARNM) ) {
125626162Ssam 			putchar( '*' );
125725828Ssam 			adrput( p->in.left);
125825828Ssam 			}
125925828Ssam 		return;
126025828Ssam 
126125828Ssam 	default:
126225828Ssam 		cerror( "illegal address" );
126325828Ssam 		return;
126425828Ssam 
126525828Ssam 		}
126625828Ssam 
126725828Ssam 	}
126825828Ssam 
acon(p)126925828Ssam acon( p ) register NODE *p; { /* print out a constant */
127025828Ssam 
127132886Sdonn 	if( p->in.name[0] == '\0' )
127225828Ssam 		printf( CONFMT, p->tn.lval);
127332886Sdonn 	else {
127425828Ssam #ifndef FLEXNAMES
127525828Ssam 		printf( "%.8s", p->in.name );
127625828Ssam #else
127732886Sdonn 		putstr( p->in.name );
127825828Ssam #endif
127932886Sdonn 		if( p->tn.lval != 0 ) {
128032886Sdonn 			putchar( '+' );
128132886Sdonn 			printf( CONFMT, p->tn.lval );
128232886Sdonn 			}
128325828Ssam 		}
128425828Ssam 	}
128525828Ssam 
genscall(p,cookie)128625828Ssam genscall( p, cookie ) register NODE *p; {
128725828Ssam 	/* structure valued call */
128825828Ssam 	return( gencall( p, cookie ) );
128925828Ssam 	}
129025828Ssam 
genfcall(p,cookie)129125828Ssam genfcall( p, cookie ) register NODE *p; {
129225828Ssam 	register NODE *p1;
129325828Ssam 	register int m;
129425828Ssam 	static char *funcops[6] = {
129525828Ssam 		"sin", "cos", "sqrt", "exp", "log", "atan"
129625828Ssam 	};
129725828Ssam 
129825828Ssam 	/* generate function opcodes */
129925828Ssam 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
130025828Ssam 	 (p1 = p->in.left)->in.op==ICON &&
130125828Ssam 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
130225828Ssam #ifdef FLEXNAMES
130325828Ssam 		p1->in.name++;
130425828Ssam #else
130525828Ssam 		strcpy(p1->in.name, p1->in.name[1]);
130625828Ssam #endif
130725828Ssam 		for(m=0; m<6; m++)
130825828Ssam 			if(!strcmp(p1->in.name, funcops[m]))
130925828Ssam 				break;
131025828Ssam 		if(m >= 6)
131125828Ssam 			uerror("no opcode for fortarn function %s", p1->in.name);
131225828Ssam 	} else
131325828Ssam 		uerror("illegal type of fortarn function");
131425828Ssam 	p1 = p->in.right;
131525828Ssam 	p->in.op = FORTCALL;
131625828Ssam 	if(!canaddr(p1))
131725828Ssam 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
131825828Ssam 	m = match( p, INTAREG|INTBREG );
131925828Ssam 	return(m != MDONE);
132025828Ssam }
132125828Ssam 
132225828Ssam /* tbl */
132325828Ssam int gc_numbytes;
132425828Ssam /* tbl */
132525828Ssam 
132632886Sdonn /*ARGSUSED*/
gencall(p,cookie)132725828Ssam gencall( p, cookie ) register NODE *p; {
132825828Ssam 	/* generate the call given by p */
132925828Ssam 	register NODE *p1, *ptemp;
133025828Ssam 	register int temp, temp1;
133125828Ssam 	register int m;
133225828Ssam 
133325828Ssam 	if( p->in.right ) temp = argsize( p->in.right );
133425828Ssam 	else temp = 0;
133525828Ssam 
133625828Ssam 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
133725828Ssam 		/* set aside room for structure return */
133825828Ssam 
133925828Ssam 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
134025828Ssam 		else temp1 = temp;
134125828Ssam 		}
134225828Ssam 
134325828Ssam 	if( temp > maxargs ) maxargs = temp;
134425828Ssam 	SETOFF(temp1,4);
134525828Ssam 
134625828Ssam 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
134725828Ssam 		ptemp = talloc();
134825828Ssam 		ptemp->in.op = OREG;
134925828Ssam 		ptemp->tn.lval = -1;
135025828Ssam 		ptemp->tn.rval = SP;
135125828Ssam #ifndef FLEXNAMES
135225828Ssam 		ptemp->in.name[0] = '\0';
135325828Ssam #else
135425828Ssam 		ptemp->in.name = "";
135525828Ssam #endif
135625828Ssam 		ptemp->in.rall = NOPREF;
135725828Ssam 		ptemp->in.su = 0;
135825828Ssam 		genargs( p->in.right, ptemp );
135925828Ssam 		ptemp->in.op = FREE;
136025828Ssam 		}
136125828Ssam 
136225828Ssam 	p1 = p->in.left;
136325828Ssam 	if( p1->in.op != ICON ){
136425828Ssam 		if( p1->in.op != REG ){
136525828Ssam 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
136625828Ssam 				if( p1->in.op != NAME ){
136725828Ssam 					order( p1, INAREG );
136825828Ssam 					}
136925828Ssam 				}
137025828Ssam 			}
137125828Ssam 		}
137225828Ssam 
137325828Ssam /* tbl
137425828Ssam 	setup gc_numbytes so reference to ZC works */
137525828Ssam 
137625828Ssam 	gc_numbytes = temp&(0x3ff);
137725828Ssam 
137825828Ssam 	p->in.op = UNARY CALL;
137925828Ssam 	m = match( p, INTAREG|INTBREG );
138025828Ssam 
138125828Ssam 	return(m != MDONE);
138225828Ssam 	}
138325828Ssam 
138425828Ssam /* tbl */
138525828Ssam char *
138625828Ssam ccbranches[] = {
138725828Ssam 	"eql",
138825828Ssam 	"neq",
138925828Ssam 	"leq",
139025828Ssam 	"lss",
139125828Ssam 	"geq",
139225828Ssam 	"gtr",
139325828Ssam 	"lequ",
139425828Ssam 	"lssu",
139525828Ssam 	"gequ",
139625828Ssam 	"gtru",
139725828Ssam 	};
139825828Ssam /* tbl */
139925828Ssam 
140032886Sdonn /*ARGSUSED*/
cbgen(o,lab,mode)140125828Ssam cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
140225828Ssam 
140332886Sdonn 	if( o != 0 && ( o < EQ || o > UGT ) )
140432886Sdonn 		cerror( "bad conditional branch: %s", opst[o] );
140532886Sdonn 	printf( "	j%s	L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
140625828Ssam 	}
140725828Ssam 
nextcook(p,cookie)140825828Ssam nextcook( p, cookie ) NODE *p; {
140925828Ssam 	/* we have failed to match p with cookie; try another */
141025828Ssam 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
141125828Ssam 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
141225828Ssam 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
141325828Ssam 	return( FORREW );
141425828Ssam 	}
141525828Ssam 
141632886Sdonn /*ARGSUSED*/
lastchance(p,cook)141725828Ssam lastchance( p, cook ) NODE *p; {
141825828Ssam 	/* forget it! */
141925828Ssam 	return(0);
142025828Ssam 	}
142125828Ssam 
optim2(p)142225828Ssam optim2( p ) register NODE *p; {
142325828Ssam 	/* do local tree transformations and optimizations */
142432886Sdonn 
142532886Sdonn 	int o;
142632886Sdonn 	int i, mask;
142730360Ssam 	register NODE *l, *r;
142825828Ssam 
142932886Sdonn 	switch( o = p->in.op ) {
143030360Ssam 
143132887Sdonn 	case ASG PLUS:
143232887Sdonn 	case ASG MINUS:
143332887Sdonn 	case ASG MUL:
143432887Sdonn 	case ASG OR:
143532887Sdonn 		/* simple ASG OPSIMP -- reduce range of constant rhs */
143632887Sdonn 		l = p->in.left;
143732887Sdonn 		r = p->in.right;
143832887Sdonn 		if( tlen(l) < SZINT/SZCHAR &&
143932887Sdonn 		    r->in.op==ICON && r->in.name[0]==0 ){
144032887Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
144132887Sdonn 			if( r->tn.lval & (mask & ~(mask >> 1)) )
144232887Sdonn 				r->tn.lval |= ~mask;
144332887Sdonn 			else
144432887Sdonn 				r->tn.lval &= mask;
144532887Sdonn 			}
144632887Sdonn 		break;
144732887Sdonn 
144832886Sdonn 	case AND:
144932886Sdonn 	case ASG AND:
145032886Sdonn 		r = p->in.right;
145132886Sdonn 		if( r->in.op==ICON && r->in.name[0]==0 ) {
145232886Sdonn 			/* check for degenerate operations */
145332886Sdonn 			l = p->in.left;
145432886Sdonn 			mask = (1 << tlen(l) * SZCHAR) - 1;
145532887Sdonn 			if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
145632887Sdonn 				i = r->tn.lval & mask;
145732886Sdonn 				if( i == mask ) {
145832887Sdonn 					/* redundant mask */
145932886Sdonn 					r->in.op = FREE;
146032886Sdonn 					ncopy(p, l);
146132886Sdonn 					l->in.op = FREE;
146232886Sdonn 					break;
146332886Sdonn 					}
146432886Sdonn 				else if( i == 0 )
146532887Sdonn 					/* all bits masked off */
146632886Sdonn 					goto zero;
146732887Sdonn 				r->tn.lval = i;
146832887Sdonn 				if( tlen(l) < SZINT/SZCHAR ){
146932887Sdonn 					/* sign extend */
147032887Sdonn 					if( r->tn.lval & (mask & ~(mask >> 1)) )
147132887Sdonn 						r->tn.lval |= ~mask;
147232887Sdonn 					else
147332887Sdonn 						r->tn.lval &= mask;
147432887Sdonn 					}
147532886Sdonn 				}
147632886Sdonn 			else if( r->tn.lval == mask &&
147732886Sdonn 				 tlen(l) < SZINT/SZCHAR ) {
147832887Sdonn 				/* use movz instead of and */
147932886Sdonn 				r->in.op = SCONV;
148032886Sdonn 				r->in.left = l;
148132886Sdonn 				r->in.right = 0;
148232886Sdonn 				r->in.type = ENUNSIGN(l->in.type);
148332886Sdonn 				r->in.su = l->in.su > 1 ? l->in.su : 1;
148432886Sdonn 				ncopy(p, r);
148532886Sdonn 				p->in.left = r;
148632886Sdonn 				p->in.type = INT;
148732886Sdonn 				}
148830360Ssam 			}
148932886Sdonn 		break;
149030360Ssam 
149130360Ssam 	case SCONV:
149230360Ssam 		l = p->in.left;
149332886Sdonn 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
149432886Sdonn 		    l->in.type == FLOAT || l->in.type == DOUBLE )
149532886Sdonn 			return;
149632887Sdonn 		if( l->in.op == PCONV )
149732886Sdonn 			return;
149832887Sdonn 		if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
149932887Sdonn 		    l->in.type != INT && l->in.type != UNSIGNED )
150032887Sdonn 			return;
150132879Sdonn 
150232886Sdonn 		/* Only trust it to get it right if the size is the same */
150332886Sdonn 		if( tlen(p) != tlen(l) )
150432886Sdonn 			return;
150530360Ssam 
150632886Sdonn 		/* clobber conversion */
150732886Sdonn 		if( l->in.op != FLD )
150832886Sdonn 			l->in.type = p->in.type;
150932886Sdonn 		ncopy( p, l );
151032886Sdonn 		l->in.op = FREE;
151132886Sdonn 
151232886Sdonn 		break;
151332886Sdonn 
151430360Ssam 	case ASSIGN:
151530360Ssam 		/*
151632886Sdonn 		 * Conversions are equivalent to assignments;
151732886Sdonn 		 * when the two operations are combined,
151832886Sdonn 		 * we can sometimes zap the conversion.
151930360Ssam 		 */
152030360Ssam 		r = p->in.right;
152132886Sdonn 		l = p->in.left;
152232886Sdonn 		if ( r->in.op == SCONV &&
152332886Sdonn 		     !mixtypes(l, r) &&
152432886Sdonn 		     l->in.op != FLD &&
152532886Sdonn 		     tlen(l) == tlen(r) ) {
152630360Ssam 				p->in.right = r->in.left;
152730360Ssam 				r->in.op = FREE;
152830360Ssam 			}
152932886Sdonn 		break;
153032885Sdonn 
153132885Sdonn 	case ULE:
153232885Sdonn 	case ULT:
153332885Sdonn 	case UGE:
153432885Sdonn 	case UGT:
153532886Sdonn 		p->in.op -= (UGE-GE);
153632886Sdonn 		if( degenerate(p) )
153732886Sdonn 			break;
153832886Sdonn 		p->in.op += (UGE-GE);
153932886Sdonn 		break;
154032886Sdonn 
154132885Sdonn 	case EQ:
154232885Sdonn 	case NE:
154332885Sdonn 	case LE:
154432885Sdonn 	case LT:
154532885Sdonn 	case GE:
154632885Sdonn 	case GT:
154732887Sdonn 		if( p->in.left->in.op == SCONV &&
154832887Sdonn 		    p->in.right->in.op == SCONV ) {
154932887Sdonn 			l = p->in.left;
155032887Sdonn 			r = p->in.right;
155132887Sdonn 			if( l->in.type == DOUBLE &&
155232887Sdonn 			    l->in.left->in.type == FLOAT &&
155332887Sdonn 			    r->in.left->in.type == FLOAT ) {
155432887Sdonn 				/* nuke the conversions */
155532887Sdonn 				p->in.left = l->in.left;
155632887Sdonn 				p->in.right = r->in.left;
155732887Sdonn 				l->in.op = FREE;
155832887Sdonn 				r->in.op = FREE;
155932887Sdonn 				}
156032887Sdonn 			/* more? */
156132887Sdonn 			}
156232886Sdonn 		(void) degenerate(p);
156332886Sdonn 		break;
156432886Sdonn 
156532886Sdonn 	case DIV:
156632886Sdonn 		if( p->in.right->in.op == ICON &&
156732886Sdonn 		    p->in.right->tn.name[0] == '\0' &&
156832886Sdonn 		    ISUNSIGNED(p->in.right->in.type) &&
156932886Sdonn 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
157032886Sdonn 			/* easy to do here, harder to do in zzzcode() */
157132886Sdonn 			p->in.op = UGE;
157232886Sdonn 			break;
157332886Sdonn 			}
157432886Sdonn 	case MOD:
157532886Sdonn 	case ASG DIV:
157632886Sdonn 	case ASG MOD:
157732885Sdonn 		/*
157832886Sdonn 		 * optimize DIV and MOD
157932886Sdonn 		 *
158032886Sdonn 		 * basically we spot UCHAR and USHORT and try to do them
158132886Sdonn 		 * as signed ints...  this may need tuning for the tahoe.
158232885Sdonn 		 */
158332886Sdonn 		if( degenerate(p) )
158432886Sdonn 			break;
158532886Sdonn 		l = p->in.left;
158632885Sdonn 		r = p->in.right;
158732886Sdonn 		if( !ISUNSIGNED(r->in.type) ||
158832886Sdonn 		    tlen(l) >= SZINT/SZCHAR ||
158932886Sdonn 		    !(tlen(r) < SZINT/SZCHAR ||
159032886Sdonn 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
159132886Sdonn 			break;
159232886Sdonn 		if( r->in.op == ICON )
159332886Sdonn 			r->tn.type = INT;
159432886Sdonn 		else {
159532886Sdonn 			NODE *t = talloc();
159632886Sdonn 			t->in.left = r;
159732886Sdonn 			r = t;
159832886Sdonn 			r->in.op = SCONV;
159932886Sdonn 			r->in.type = INT;
160032886Sdonn 			r->in.right = 0;
160132886Sdonn 			p->in.right = r;
160232886Sdonn 			}
160332886Sdonn 		if( o == DIV || o == MOD ) {
160432886Sdonn 			NODE *t = talloc();
160532886Sdonn 			t->in.left = l;
160632886Sdonn 			l = t;
160732886Sdonn 			l->in.op = SCONV;
160832886Sdonn 			l->in.type = INT;
160932886Sdonn 			l->in.right = 0;
161032886Sdonn 			p->in.left = l;
161132886Sdonn 			}
161232886Sdonn 		/* handle asgops in table */
161332886Sdonn 		break;
161432886Sdonn 
161532886Sdonn 	case RS:
161632886Sdonn 	case ASG RS:
161732886Sdonn 	case LS:
161832886Sdonn 	case ASG LS:
161932886Sdonn 		/* pick up degenerate shifts */
162032885Sdonn 		l = p->in.left;
162132886Sdonn 		r = p->in.right;
162232886Sdonn 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
162332885Sdonn 			break;
162432885Sdonn 		i = r->tn.lval;
162532886Sdonn 		if( i < 0 )
162632886Sdonn 			/* front end 'fixes' this? */
162732886Sdonn 			if( o == LS || o == ASG LS )
162832886Sdonn 				o += (RS-LS);
162932886Sdonn 			else
163032886Sdonn 				o += (LS-RS);
163132886Sdonn 		if( (o == RS || o == ASG RS) &&
163232886Sdonn 		    !ISUNSIGNED(l->in.type) )
163332886Sdonn 			/* can't optimize signed right shifts */
163432885Sdonn 			break;
163532886Sdonn 		if( o == LS ) {
163632886Sdonn 			if( i < SZINT )
163732886Sdonn 				break;
163832886Sdonn 			}
163932886Sdonn 		else {
164032886Sdonn 			if( i < tlen(l) * SZCHAR )
164132886Sdonn 				break;
164232886Sdonn 			}
164332886Sdonn 	zero:
164432886Sdonn 		if( !asgop( o ) )
164532886Sdonn 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
164632886Sdonn 				/* no side effects */
164732886Sdonn 				tfree(l);
164832886Sdonn 				ncopy(p, r);
164932886Sdonn 				r->in.op = FREE;
165032886Sdonn 				p->tn.lval = 0;
165132886Sdonn 				}
165232886Sdonn 			else {
165332886Sdonn 				p->in.op = COMOP;
165432886Sdonn 				r->tn.lval = 0;
165532886Sdonn 				}
165632886Sdonn 		else {
165732886Sdonn 			p->in.op = ASSIGN;
165832886Sdonn 			r->tn.lval = 0;
165932886Sdonn 			}
166032886Sdonn 		break;
166132885Sdonn 		}
166232886Sdonn 	}
166332885Sdonn 
degenerate(p)166432886Sdonn degenerate(p) register NODE *p; {
166532886Sdonn 	int o;
166632886Sdonn 	int result, i;
166732886Sdonn 	int lower, upper;
166832886Sdonn 	register NODE *l, *r;
166932886Sdonn 
167032886Sdonn 	/*
167132886Sdonn 	 * try to keep degenerate comparisons with constants
167232886Sdonn 	 * out of the table.
167332886Sdonn 	 */
167432886Sdonn 	r = p->in.right;
167532886Sdonn 	l = p->in.left;
167632886Sdonn 	if( r->in.op != ICON ||
167732886Sdonn 	    r->tn.name[0] != '\0' ||
167832886Sdonn 	    tlen(l) >= tlen(r) )
167932886Sdonn 		return (0);
168032886Sdonn 	switch( l->in.type ) {
168132886Sdonn 	case CHAR:
168232886Sdonn 		lower = -(1 << SZCHAR - 1);
168332886Sdonn 		upper = (1 << SZCHAR - 1) - 1;
168432886Sdonn 		break;
168532886Sdonn 	case UCHAR:
168632886Sdonn 		lower = 0;
168732886Sdonn 		upper = (1 << SZCHAR) - 1;
168832886Sdonn 		break;
168932886Sdonn 	case SHORT:
169032886Sdonn 		lower = -(1 << SZSHORT - 1);
169132886Sdonn 		upper = (1 << SZSHORT - 1) - 1;
169232886Sdonn 		break;
169332886Sdonn 	case USHORT:
169432886Sdonn 		lower = 0;
169532886Sdonn 		upper = (1 << SZSHORT) - 1;
169632886Sdonn 		break;
169732886Sdonn 	default:
169832886Sdonn 		cerror("unsupported type in degenerate()");
169932886Sdonn 		}
170032886Sdonn 	i = r->tn.lval;
170132886Sdonn 	switch( o = p->in.op ) {
170232886Sdonn 	case DIV:
170332886Sdonn 	case ASG DIV:
170432886Sdonn 	case MOD:
170532886Sdonn 	case ASG MOD:
170632886Sdonn 		/* DIV and MOD work like EQ */
170732886Sdonn 	case EQ:
170832886Sdonn 	case NE:
170932886Sdonn 		if( lower == 0 && (unsigned) i > upper )
171032886Sdonn 			result = o == NE;
171132886Sdonn 		else if( i < lower || i > upper )
171232886Sdonn 			result = o == NE;
171332886Sdonn 		else
171432886Sdonn 			return (0);
171532886Sdonn 		break;
171632886Sdonn 	case LT:
171732886Sdonn 	case GE:
171832886Sdonn 		if( lower == 0 && (unsigned) i > upper )
171932886Sdonn 			result = o == LT;
172032886Sdonn 		else if( i <= lower )
172132886Sdonn 			result = o != LT;
172232886Sdonn 		else if( i > upper )
172332886Sdonn 			result = o == LT;
172432886Sdonn 		else
172532886Sdonn 			return (0);
172632886Sdonn 		break;
172732886Sdonn 	case LE:
172832886Sdonn 	case GT:
172932886Sdonn 		if( lower == 0 && (unsigned) i >= upper )
173032886Sdonn 			result = o == LE;
173132886Sdonn 		else if( i < lower )
173232886Sdonn 			result = o != LE;
173332886Sdonn 		else if( i >= upper )
173432886Sdonn 			result = o == LE;
173532886Sdonn 		else
173632886Sdonn 			return (0);
173732886Sdonn 		break;
173832886Sdonn 	default:
173932886Sdonn 		cerror("unknown op in degenerate()");
174032886Sdonn 		}
174132886Sdonn 
174232886Sdonn 	if( o == MOD || o == ASG MOD ) {
174332886Sdonn 		r->in.op = FREE;
174432886Sdonn 		ncopy(p, l);
174532886Sdonn 		l->in.op = FREE;
174632886Sdonn 		}
174732886Sdonn 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
174832886Sdonn 		/* no side effects */
174932886Sdonn 		tfree(l);
175032886Sdonn 		ncopy(p, r);
175132886Sdonn 		r->in.op = FREE;
175232886Sdonn 		p->tn.lval = result;
175332886Sdonn 		}
175432886Sdonn 	else {
175532886Sdonn 		if( o == ASG DIV )
175632886Sdonn 			p->in.op = ASSIGN;
175732886Sdonn 		else {
175832885Sdonn 			p->in.op = COMOP;
175932885Sdonn 			r->tn.type = INT;
176032886Sdonn 			}
176132886Sdonn 		r->tn.lval = result;
176232885Sdonn 		}
176332886Sdonn 	if( logop(o) )
176432886Sdonn 		p->in.type = INT;
176532886Sdonn 
176632886Sdonn 	return (1);
176725828Ssam 	}
176825828Ssam 
176925828Ssam struct functbl {
177025828Ssam 	int fop;
177132877Sdonn 	TWORD ftype;
177225828Ssam 	char *func;
177332877Sdonn 	} opfunc[] = {
177432877Sdonn 	DIV,		TANY,	"udiv",
177532877Sdonn 	MOD,		TANY,	"urem",
177632877Sdonn 	ASG DIV,	TANY,	"audiv",
177732877Sdonn 	ASG MOD,	TANY,	"aurem",
177832877Sdonn 	0,	0,	0 };
177925828Ssam 
hardops(p)178025828Ssam hardops(p)  register NODE *p; {
178125828Ssam 	/* change hard to do operators into function calls.  */
178225828Ssam 	register NODE *q;
178325828Ssam 	register struct functbl *f;
178432877Sdonn 	register o;
178532877Sdonn 	NODE *old,*temp;
178625828Ssam 
178725828Ssam 	o = p->in.op;
178832877Sdonn 	if( ! (optype(o)==BITYPE &&
178932877Sdonn 	       (ISUNSIGNED(p->in.left->in.type) ||
179032877Sdonn 		ISUNSIGNED(p->in.right->in.type))) )
179132877Sdonn 		return;
179225828Ssam 
179325828Ssam 	for( f=opfunc; f->fop; f++ ) {
179425828Ssam 		if( o==f->fop ) goto convert;
179532877Sdonn 		}
179625828Ssam 	return;
179725828Ssam 
179825828Ssam 	convert:
179932886Sdonn 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
180032886Sdonn 		/* 'J' in zzzcode() -- assumes DIV or MOD operations */
180132886Sdonn 		/* save a subroutine call -- use at most 5 instructions */
180232886Sdonn 		return;
180332886Sdonn 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
180432886Sdonn 		/* optim2() will modify the op into an ordinary int op */
180532886Sdonn 		return;
180625828Ssam 	if( asgop( o ) ) {
180732877Sdonn 		old = NIL;
180832877Sdonn 		switch( p->in.left->in.op ){
180932877Sdonn 		case FLD:
181032877Sdonn 			q = p->in.left->in.left;
181132877Sdonn 			/*
181232877Sdonn 			 * rewrite (lval.fld /= rval); as
181332877Sdonn 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
181432877Sdonn 			 * else the compiler will evaluate lval twice.
181532877Sdonn 			 */
181632877Sdonn 			if( q->in.op == UNARY MUL ){
181732877Sdonn 				/* first allocate a temp storage */
181832877Sdonn 				temp = talloc();
181932877Sdonn 				temp->in.op = OREG;
182032877Sdonn 				temp->tn.rval = TMPREG;
182132877Sdonn 				temp->tn.lval = BITOOR(freetemp(1));
182232877Sdonn 				temp->in.type = INCREF(p->in.type);
182332877Sdonn #ifdef FLEXNAMES
182432877Sdonn 				temp->in.name = "";
182532877Sdonn #else
182632877Sdonn 				temp->in.name[0] = '\0';
182732877Sdonn #endif
182832877Sdonn 				old = q->in.left;
182932877Sdonn 				q->in.left = temp;
183032877Sdonn 			}
183132877Sdonn 			/* fall thru ... */
183225828Ssam 
183332877Sdonn 		case REG:
183432877Sdonn 		case NAME:
183532877Sdonn 		case OREG:
183632877Sdonn 			/* change ASG OP to a simple OP */
183732877Sdonn 			q = talloc();
183832877Sdonn 			q->in.op = NOASG p->in.op;
183932877Sdonn 			q->in.rall = NOPREF;
184032877Sdonn 			q->in.type = p->in.type;
184132877Sdonn 			q->in.left = tcopy(p->in.left);
184232877Sdonn 			q->in.right = p->in.right;
184332877Sdonn 			p->in.op = ASSIGN;
184432877Sdonn 			p->in.right = q;
184532877Sdonn 			p = q;
184632877Sdonn 			f -= 2; /* Note: this depends on the table order */
184732877Sdonn 			/* on the right side only - replace *temp with
184832877Sdonn 			 *(temp = &lval), build the assignment node */
184932877Sdonn 			if( old ){
185032877Sdonn 				temp = q->in.left->in.left; /* the "*" node */
185132877Sdonn 				q = talloc();
185232877Sdonn 				q->in.op = ASSIGN;
185332877Sdonn 				q->in.left = temp->in.left;
185432877Sdonn 				q->in.right = old;
185532877Sdonn 				q->in.type = old->in.type;
185632877Sdonn #ifdef FLEXNAMES
185732877Sdonn 				q->in.name = "";
185825828Ssam #else
185932877Sdonn 				q->in.name[0] = '\0';
186025828Ssam #endif
186132877Sdonn 				temp->in.left = q;
186232877Sdonn 			}
186332877Sdonn 			break;
186425828Ssam 
186532877Sdonn 		case UNARY MUL:
186632877Sdonn 			/* avoid doing side effects twice */
186732877Sdonn 			q = p->in.left;
186832877Sdonn 			p->in.left = q->in.left;
186932877Sdonn 			q->in.op = FREE;
187032877Sdonn 			break;
187132877Sdonn 
187232877Sdonn 		default:
187332877Sdonn 			cerror( "hardops: can't compute & LHS" );
187432877Sdonn 			}
187532877Sdonn 		}
187632877Sdonn 
187725828Ssam 	/* build comma op for args to function */
187832877Sdonn 	q = talloc();
187932877Sdonn 	q->in.op = CM;
188032877Sdonn 	q->in.rall = NOPREF;
188132877Sdonn 	q->in.type = INT;
188232877Sdonn 	q->in.left = p->in.left;
188332877Sdonn 	q->in.right = p->in.right;
188425828Ssam 	p->in.op = CALL;
188525828Ssam 	p->in.right = q;
188625828Ssam 
188725828Ssam 	/* put function name in left node of call */
188825828Ssam 	p->in.left = q = talloc();
188925828Ssam 	q->in.op = ICON;
189025828Ssam 	q->in.rall = NOPREF;
189125828Ssam 	q->in.type = INCREF( FTN + p->in.type );
189225828Ssam #ifndef FLEXNAMES
189332877Sdonn 	strcpy( q->in.name, f->func );
189425828Ssam #else
189532877Sdonn 	q->in.name = f->func;
189625828Ssam #endif
189725828Ssam 	q->tn.lval = 0;
189825828Ssam 	q->tn.rval = 0;
189925828Ssam 
190025828Ssam 	}
190125828Ssam 
zappost(p)190225828Ssam zappost(p) NODE *p; {
190325828Ssam 	/* look for ++ and -- operators and remove them */
190425828Ssam 
190525828Ssam 	register int o, ty;
190625828Ssam 	register NODE *q;
190725828Ssam 	o = p->in.op;
190825828Ssam 	ty = optype( o );
190925828Ssam 
191025828Ssam 	switch( o ){
191125828Ssam 
191225828Ssam 	case INCR:
191325828Ssam 	case DECR:
191425828Ssam 			q = p->in.left;
191525828Ssam 			p->in.right->in.op = FREE;  /* zap constant */
191625828Ssam 			ncopy( p, q );
191725828Ssam 			q->in.op = FREE;
191825828Ssam 			return;
191925828Ssam 
192025828Ssam 		}
192125828Ssam 
192225828Ssam 	if( ty == BITYPE ) zappost( p->in.right );
192325828Ssam 	if( ty != LTYPE ) zappost( p->in.left );
192425828Ssam }
192525828Ssam 
fixpre(p)192625828Ssam fixpre(p) NODE *p; {
192725828Ssam 
192825828Ssam 	register int o, ty;
192925828Ssam 	o = p->in.op;
193025828Ssam 	ty = optype( o );
193125828Ssam 
193225828Ssam 	switch( o ){
193325828Ssam 
193425828Ssam 	case ASG PLUS:
193525828Ssam 			p->in.op = PLUS;
193625828Ssam 			break;
193725828Ssam 	case ASG MINUS:
193825828Ssam 			p->in.op = MINUS;
193925828Ssam 			break;
194025828Ssam 		}
194125828Ssam 
194225828Ssam 	if( ty == BITYPE ) fixpre( p->in.right );
194325828Ssam 	if( ty != LTYPE ) fixpre( p->in.left );
194425828Ssam }
194525828Ssam 
194632886Sdonn /*ARGSUSED*/
addroreg(l)194725828Ssam NODE * addroreg(l) NODE *l;
194825828Ssam 				/* OREG was built in clocal()
194925828Ssam 				 * for an auto or formal parameter
195025828Ssam 				 * now its address is being taken
195125828Ssam 				 * local code must unwind it
195225828Ssam 				 * back to PLUS/MINUS REG ICON
195325828Ssam 				 * according to local conventions
195425828Ssam 				 */
195525828Ssam {
195625828Ssam 	cerror("address of OREG taken");
195732886Sdonn 	/*NOTREACHED*/
195825828Ssam }
195925828Ssam 
196025828Ssam # ifndef ONEPASS
main(argc,argv)196125828Ssam main( argc, argv ) char *argv[]; {
196225828Ssam 	return( mainp2( argc, argv ) );
196325828Ssam 	}
196425828Ssam # endif
196525828Ssam 
strip(p)196630360Ssam strip(p) register NODE *p; {
196730360Ssam 	NODE *q;
196830360Ssam 
196930360Ssam 	/* strip nodes off the top when no side effects occur */
197030360Ssam 	for( ; ; ) {
197130360Ssam 		switch( p->in.op ) {
197230360Ssam 		case SCONV:			/* remove lint tidbits */
197330360Ssam 			q = p->in.left;
197430360Ssam 			ncopy( p, q );
197530360Ssam 			q->in.op = FREE;
197630360Ssam 			break;
197730360Ssam 		/* could probably add a few more here */
197830360Ssam 		default:
197930360Ssam 			return;
198030360Ssam 			}
198130360Ssam 		}
198230360Ssam 	}
198330360Ssam 
myreader(p)198425828Ssam myreader(p) register NODE *p; {
198530360Ssam 	strip( p );		/* strip off operations with no side effects */
198632886Sdonn 	canon( p );		/* expands r-vals for fields */
198725828Ssam 	walkf( p, hardops );	/* convert ops to function calls */
198825828Ssam 	walkf( p, optim2 );
198925828Ssam 	}
1990