xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32888)
1 # ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.26 (Berkeley) 12/10/87";
3 # endif
4 
5 # include "pass2.h"
6 # include <ctype.h>
7 
8 # define putstr(s)	fputs((s), stdout)
9 # define ISCHAR(p)	(p->in.type == UCHAR || p->in.type == CHAR)
10 
11 # ifdef FORT
12 int ftlab1, ftlab2;
13 # endif
14 /* a lot of the machine dependent parts of the second pass */
15 
16 # define BITMASK(n) ((1L<<n)-1)
17 
18 # ifndef ONEPASS
19 /*ARGSUSED*/
20 where(c){
21 	fprintf( stderr, "%s, line %d: ", filename, lineno );
22 	}
23 # endif
24 
25 lineid( l, fn ) char *fn; {
26 	/* identify line l and file fn */
27 	printf( "#	line %d, file %s\n", l, fn );
28 	}
29 
30 int ent_mask;
31 
32 eobl2(){
33 	register OFFSZ spoff;	/* offset from stack pointer */
34 #ifndef FORT
35 	extern int ftlab1, ftlab2;
36 #endif
37 
38 	spoff = maxoff;
39 	spoff /= SZCHAR;
40 	SETOFF(spoff,4);
41 #ifdef FORT
42 #ifndef FLEXNAMES
43 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
44 #else
45 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
46 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
47 #endif
48 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
49 #else
50 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
51 	printf( "L%d:\n", ftlab1);
52 	if( maxoff > AUTOINIT )
53 		printf( "	subl3	$%ld,fp,sp\n", spoff);
54 	printf( "	jbr 	L%d\n", ftlab2);
55 #endif
56 	ent_mask = 0;
57 	maxargs = -1;
58 	}
59 
60 struct hoptab { int opmask; char * opstring; } ioptab[] = {
61 
62 	PLUS,	"add",
63 	MINUS,	"sub",
64 	MUL,	"mul",
65 	DIV,	"div",
66 	MOD,	"div",
67 	OR,	"or",
68 	ER,	"xor",
69 	AND,	"and",
70 	-1,	""    };
71 
72 hopcode( f, o ){
73 	/* output the appropriate string from the above table */
74 
75 	register struct hoptab *q;
76 
77 	if(asgop(o))
78 		o = NOASG o;
79 	for( q = ioptab;  q->opmask>=0; ++q ){
80 		if( q->opmask == o ){
81 			if(f == 'E')
82 				printf( "e%s", q->opstring);
83 			else
84 				printf( "%s%c", q->opstring, tolower(f));
85 			return;
86 			}
87 		}
88 	cerror( "no hoptab for %s", opst[o] );
89 	}
90 
91 char *
92 rnames[] = {  /* keyed to register number tokens */
93 
94 	"r0", "r1",
95 	"r2", "r3", "r4", "r5",
96 	"r6", "r7", "r8", "r9", "r10", "r11",
97 	"r12", "fp", "sp", "pc",
98 	};
99 
100 /* output register name and update entry mask */
101 char *
102 rname(r)
103 	register int r;
104 {
105 
106 	if (!istreg(r))
107 		ent_mask |= 1<<r;
108 	return(rnames[r]);
109 }
110 
111 int rstatus[] = {
112 	SAREG|STAREG, SAREG|STAREG,
113 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
114 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
115 	SAREG, SAREG, SAREG, SAREG,
116 	};
117 
118 tlen(p) NODE *p;
119 {
120 	switch(p->in.type) {
121 		case CHAR:
122 		case UCHAR:
123 			return(1);
124 
125 		case SHORT:
126 		case USHORT:
127 			return(SZSHORT/SZCHAR);
128 
129 		case DOUBLE:
130 			return(SZDOUBLE/SZCHAR);
131 
132 		default:
133 			return(SZINT/SZCHAR);
134 		}
135 }
136 
137 mixtypes(p, q) NODE *p, *q;
138 {
139 	register TWORD tp, tq;
140 
141 	tp = p->in.type;
142 	tq = q->in.type;
143 
144 	return( (tp==FLOAT || tp==DOUBLE) !=
145 		(tq==FLOAT || tq==DOUBLE) );
146 }
147 
148 prtype(n) NODE *n;
149 {
150 	switch (n->in.type)
151 		{
152 
153 		case DOUBLE:
154 			putchar('d');
155 			return;
156 
157 		case FLOAT:
158 			putchar('f');
159 			return;
160 
161 		case LONG:
162 		case ULONG:
163 		case INT:
164 		case UNSIGNED:
165 			putchar('l');
166 			return;
167 
168 		case SHORT:
169 		case USHORT:
170 			putchar('w');
171 			return;
172 
173 		case CHAR:
174 		case UCHAR:
175 			putchar('b');
176 			return;
177 
178 		default:
179 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
180 			else {
181 				putchar('l');
182 				return;
183 				}
184 		}
185 }
186 
187 zzzcode( p, c ) register NODE *p; {
188 	register int m;
189 	int val;
190 	switch( c ){
191 
192 	case 'N':  /* logical ops, turned into 0-1 */
193 		/* use register given by register 1 */
194 		cbgen( 0, m=getlab(), 'I' );
195 		deflab( p->bn.label );
196 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
197 		deflab( m );
198 		return;
199 
200 	case 'P':
201 		cbgen( p->in.op, p->bn.label, c );
202 		return;
203 
204 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
205 		{
206 		register NODE *l, *r, *s;
207 		int lt, rt;
208 
209 		l = p->in.left;
210 		r = p->in.right;
211 		s = talloc();
212 		rt = r->in.type;
213 		lt = l->in.type;
214 
215 		if (lt != INT && lt != UNSIGNED) {
216 			s->in.op = SCONV;
217 			s->in.left = l;
218 			s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
219 			zzzcode(s, 'U');
220 			putstr("\n\t");
221 		}
222 
223 		if (ISUNSIGNED(lt)) {
224 			s->in.op = SCONV;
225 			s->in.left = lt == UNSIGNED ? l : resc;
226 			s->in.type = rt;
227 			unsigned_to_float(s);
228 		} else {
229 			putstr("cvl");
230 			prtype(r);
231 			putchar('\t');
232 			adrput(lt == INT ? l : resc);
233 		}
234 		putstr("\n\t");
235 
236 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
237 		putchar('\t');
238 		adrput(r);
239 
240 		if (ISUNSIGNED(lt)) {
241 			putstr("\n\t");
242 			s->in.op = SCONV;
243 			s->in.left = r;		/* we need only the type */
244 			s->in.type = UNSIGNED;
245 			float_to_unsigned(s);
246 		} else {
247 			putstr("\n\tcv");
248 			prtype(r);
249 			putstr("l\t");
250 			if (lt == INT)
251 				adrput(l);
252 			else
253 				adrput(resc);
254 		}
255 		if (lt != INT) {
256 			putstr("\n\t");
257 			s->in.op = ASSIGN;
258 			s->in.left = l;
259 			s->in.right = resc;
260 			s->in.type = lt;
261 			zzzcode(s, 'U');
262 		}
263 
264 		s->in.op = FREE;
265 		return;
266 		}
267 
268 	case 'J':	/* unsigned DIV/MOD with constant divisors */
269 		{
270 		register int ck = INAREG;
271 		int label1, label2;
272 
273 		/* case constant <= 1 is handled by optim() in pass 1 */
274 		/* case constant < 0x80000000 is handled in table */
275 		switch( p->in.op ) {
276 		/* case DIV: handled in optim2() */
277 		case MOD:
278 			if( p->in.left->in.op == REG &&
279 			    p->in.left->tn.rval == resc->tn.rval )
280 				goto asgmod;
281 			label1 = getlab();
282 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
283 			printf("\tjlssu\tL%d\n", label1);
284 			expand(p, ck, "\tsubl2\tAR,A1\n");
285 			printf("L%d:", label1);
286 			break;
287 		case ASG DIV:
288 			label1 = getlab();
289 			label2 = getlab();
290 			expand(p, ck, "cmpl\tAL,AR\n");
291 			printf("\tjgequ\tL%d\n", label1);
292 			expand(p, ck, "\tmovl\t$1,AL\n");
293 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
294 			expand(p, ck, "\tclrl\tAL\n");
295 			printf("L%d:", label2);
296 			break;
297 		case ASG MOD:
298 		asgmod:
299 			label1 = getlab();
300 			expand(p, ck, "cmpl\tAL,AR\n");
301 			printf("\tjlssu\tL%d\n", label1);
302 			expand(p, ck, "\tsubl2\tAR,AL\n");
303 			printf("L%d:", label1);
304 			break;
305 			}
306 		return;
307 		}
308 
309 	case 'B':	/* get oreg value in temp register for shift */
310 		{
311 		register NODE *r;
312 		if (xdebug) eprint(p, 0, &val, &val);
313 		r = p->in.right;
314 		if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
315 			putstr("movl");
316 		else {
317 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
318 			prtype(r);
319 			putchar('l');
320 			}
321 		return;
322 		}
323 
324 	case 'C':	/* generate 'call[fs] $bytes' */
325 		{
326 		extern int gc_numbytes;
327 		extern int xdebug;
328 
329 		if (xdebug) printf("->%d<-",gc_numbytes);
330 
331 		printf("call%c	$%d",
332 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
333 		 gc_numbytes+4);
334 		/* don't change to double (here's the only place to catch it) */
335 		if(p->in.type == FLOAT)
336 			rtyflg = 1;
337 		return;
338 		}
339 
340 	case 'D':	/* INCR and DECR */
341 		zzzcode(p->in.left, 'U');
342 		putstr("\n	");
343 
344 	case 'E':	/* INCR and DECR, FOREFF */
345  		if (p->in.right->tn.lval == 1)
346 			{
347 			putstr(p->in.op == INCR ? "inc" : "dec");
348 			prtype(p->in.left);
349 			putchar('\t');
350 			adrput(p->in.left);
351 			return;
352 			}
353 		putstr(p->in.op == INCR ? "add" : "sub");
354 		prtype(p->in.left);
355 		putstr("2	");
356 		adrput(p->in.right);
357 		putchar(',');
358 		adrput(p->in.left);
359 		return;
360 
361 	case 'F':	/* masked constant for fields */
362 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
363 		return;
364 
365 	case 'I':	/* produce value of bitfield assignment */
366 			/* avoid shifts -- shifts are SLOW on this machine */
367 			/* XXX this wouldn't be necessary if we were smarter
368 			       and masked BEFORE shifting XXX */
369 		{
370 		register NODE *r = p->in.right;
371 		if(r->in.op == ICON && r->tn.name[0] == '\0') {
372 			putstr("movl\t");
373 			printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
374 			}
375 		else {
376 			putstr("andl3\t");
377 			printf(ACONFMT, (1 << fldsz) - 1);
378 			putchar(',');
379 			adrput(r);
380 			}
381 		putchar(',');
382 		adrput(resc);
383 		break;
384 		}
385 
386 	case 'H':	/* opcode for shift */
387 		if(p->in.op == LS || p->in.op == ASG LS)
388 			putstr("shll");
389 		else if(ISUNSIGNED(p->in.left->in.type))
390 			putstr("shrl");
391 		else
392 			putstr("shar");
393 		return;
394 
395 	case 'L':	/* type of left operand */
396 	case 'R':	/* type of right operand */
397 		{
398 		register NODE *n;
399 		extern int xdebug;
400 
401 		n = getlr ( p, c);
402 		if (xdebug) printf("->%d<-", n->in.type);
403 
404 		prtype(n);
405 		return;
406 		}
407 
408 	case 'M': {  /* initiate ediv for mod and unsigned div */
409 		putstr("clrl\t");
410 		adrput(resc);
411 		putstr("\n\tmovl\t");
412 		adrput(p->in.left);
413 		putchar(',');
414 		upput(resc, SZLONG);
415 		printf("\n\tjgeq\tL%d\n\tmnegl\t$1,", m = getlab());
416 		adrput(resc);
417 		putchar('\n');
418 		deflab(m);
419 		return;
420 	}
421 
422 	case 'T': {	/* rounded structure length for arguments */
423 		int size = p->stn.stsize;
424 		SETOFF( size, 4);
425 		printf("movab	-%d(sp),sp", size);
426 		return;
427 	}
428 
429 	case 'S':  /* structure assignment */
430 		stasg(p);
431 		break;
432 
433 #ifdef I_don_t_understand_this
434 	case 'X':	/* multiplication for short and char */
435 		if (ISUNSIGNED(p->in.left->in.type))
436 			printf("\tmovz");
437 		else
438 			printf("\tcvt");
439 		zzzcode(p, 'L');
440 		printf("l\t");
441 		adrput(p->in.left);
442 		printf(",");
443 		adrput(&resc[0]);
444 		printf("\n");
445 		if (ISUNSIGNED(p->in.right->in.type))
446 			printf("\tmovz");
447 		else
448 			printf("\tcvt");
449 		zzzcode(p, 'R');
450 		printf("l\t");
451 		adrput(p->in.right);
452 		printf(",");
453 		adrput(&resc[1]);
454 		printf("\n");
455 		return;
456 #endif
457 
458 	case 'U':		/* SCONV */
459 	case 'V':		/* SCONV with FORCC */
460 		sconv(p, c == 'V');
461 		break;
462 
463 	case 'W': {		/* SCONV or ASSIGN float/double => unsigned */
464 		NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
465 
466 		putstr("ld");
467 		prtype(src);
468 		putchar('\t');
469 		adrput(src);
470 		putstr("\n\t");
471 		float_to_unsigned(p);
472 		break;
473 	}
474 
475 	case 'Y':		/* SCONV or ASSIGN unsigned => float/double */
476 		unsigned_to_float(p);	/* stores into accumulator */
477 		putstr("\n\tst");
478 		prtype(p);
479 		putchar('\t');
480 		if (p->in.op == SCONV)
481 			adrput(resc);
482 		else
483 			adrput(p->in.left);
484 		rtyflg = 1;
485 		break;
486 
487 #ifdef I_don_t_understand_this
488 	case 'Z':
489 		p = p->in.right;
490 		switch (p->in.type) {
491 		case SHORT: {
492 			short w = p->tn.lval;
493 			p->tn.lval = w;
494 			break;
495 		}
496 		case CHAR: {
497 			char c = p->tn.lval;
498 			p->tn.lval = c;
499 			break;
500 		}
501 		}
502 		printf("$%d", p->tn.lval);
503 		break;
504 #endif
505 
506 	default:
507 		cerror( "illegal zzzcode" );
508 	}
509 }
510 
511 #define	MOVB(dst, src, off) { \
512 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
513 	upput(dst, off); putchar('\n'); \
514 }
515 #define	MOVW(dst, src, off) { \
516 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
517 	upput(dst, off); putchar('\n'); \
518 }
519 #define	MOVL(dst, src, off) { \
520 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
521 	upput(dst, off); putchar('\n'); \
522 }
523 /*
524  * Generate code for a structure assignment.
525  */
526 stasg(p)
527 	register NODE *p;
528 {
529 	register NODE *l, *r;
530 	register int size;
531 
532 	switch (p->in.op) {
533 	case STASG:			/* regular assignment */
534 		l = p->in.left;
535 		r = p->in.right;
536 		break;
537 	case STARG:			/* place arg on the stack */
538 		l = getlr(p, '3');
539 		r = p->in.left;
540 		break;
541 	default:
542 		cerror("STASG bad");
543 		/*NOTREACHED*/
544 	}
545 	/*
546 	 * Pun source for use in code generation.
547 	 */
548 	switch (r->in.op) {
549 	case ICON:
550 		r->in.op = NAME;
551 		break;
552 	case REG:
553 		r->in.op = OREG;
554 		break;
555 	default:
556 		cerror( "STASG-r" );
557 		/*NOTREACHED*/
558 	}
559 	size = p->stn.stsize;
560 	if (size <= 0 || size > 65535)
561 		cerror("structure size out of range");
562 	/*
563 	 * Generate optimized code based on structure size
564 	 * and alignment properties....
565 	 */
566 	switch (size) {
567 
568 	case 1:
569 		putstr("\tmovb\t");
570 	optimized:
571 		adrput(r);
572 		putchar(',');
573 		adrput(l);
574 		putchar('\n');
575 		break;
576 
577 	case 2:
578 		if (p->stn.stalign != 2) {
579 			MOVB(l, r, SZCHAR);
580 			putstr("\tmovb\t");
581 		} else
582 			putstr("\tmovw\t");
583 		goto optimized;
584 
585 	case 4:
586 		if (p->stn.stalign != 4) {
587 			if (p->stn.stalign != 2) {
588 				MOVB(l, r, 3*SZCHAR);
589 				MOVB(l, r, 2*SZCHAR);
590 				MOVB(l, r, 1*SZCHAR);
591 				putstr("\tmovb\t");
592 			} else {
593 				MOVW(l, r, SZSHORT);
594 				putstr("\tmovw\t");
595 			}
596 		} else
597 			putstr("\tmovl\t");
598 		goto optimized;
599 
600 	case 6:
601 		if (p->stn.stalign != 2)
602 			goto movblk;
603 		MOVW(l, r, 2*SZSHORT);
604 		MOVW(l, r, 1*SZSHORT);
605 		putstr("\tmovw\t");
606 		goto optimized;
607 
608 	case 8:
609 		if (p->stn.stalign == 4) {
610 			MOVL(l, r, SZLONG);
611 			putstr("\tmovl\t");
612 			goto optimized;
613 		}
614 		/* fall thru...*/
615 
616 	default:
617 	movblk:
618 		/*
619 		 * Can we ever get a register conflict with R1 here?
620 		 */
621 		putstr("\tmovab\t");
622 		adrput(l);
623 		putstr(",r1\n\tmovab\t");
624 		adrput(r);
625 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
626 		rname(R2);
627 		break;
628 	}
629 	/*
630 	 * Reverse above pun for reclaim.
631 	 */
632 	if (r->in.op == NAME)
633 		r->in.op = ICON;
634 	else if (r->in.op == OREG)
635 		r->in.op = REG;
636 }
637 
638 /*
639  * Convert a float or double in the accumulator into an unsigned int.
640  * Unlike the vax, the tahoe stores 0 into the destination
641  *	on a conversion of > 2 ** 31, so we compensate.
642  */
643 float_to_unsigned(p)
644 	NODE *p;
645 {
646 	register NODE *l = p->in.left;
647 	int label1 = getlab();
648 	int label2 = getlab();
649 	int label3 = getlab();
650 	NODE *src, *dst;
651 
652 	if (p->in.op == SCONV) {
653 		src = p->in.left;
654 		dst = resc;
655 	} else {
656 		src = p->in.right;
657 		dst = p->in.left;
658 	}
659 
660 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
661 	if (src->in.type == DOUBLE)
662 		putstr(", 0x00000000 # .double");
663 	else
664 		putstr(" # .float");
665 	putstr(" 2147483648\n\t.text\n\tcmp");
666 	prtype(src);
667 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
668 	prtype(src);
669 	printf("\tL%d\n\tcv", label1);
670 	prtype(src);
671 	putstr("l\t");
672 	adrput(dst);
673 	putstr("\n\taddl2\t$-2147483648,");
674 	adrput(dst);
675 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
676 	prtype(src);
677 	putstr("l\t");
678 	adrput(dst);
679 	printf("\nL%d:", label3);
680 }
681 
682 /*
683  * Convert an unsigned int into a float or double, leaving the result
684  *	in the accumulator.
685  */
686 unsigned_to_float(p)
687 	register NODE *p;
688 {
689 	int label1 = getlab();
690 	int label2 = getlab();
691 	NODE *src, *dst;
692 
693 	if (p->in.op == SCONV) {
694 		src = p->in.left;
695 		dst = resc;
696 	} else {
697 		src = p->in.right;
698 		dst = p->in.left;
699 	}
700 
701 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
702 	if (p->in.type == DOUBLE)
703 		putstr(", 0x00000000 # .double");
704 	else
705 		putstr(" # .float");
706 	putstr(" 4294967296\n\t.text\n\tmovl\t");
707 	adrput(src);
708 	putchar(',');
709 	adrput(dst);
710 	putstr("\n\tcvl");
711 	prtype(p);
712 	putchar('\t');
713 	adrput(dst);
714 	printf("\n\tjgeq\tL%d\n\tadd", label1);
715 	prtype(p);
716 	printf("\tL%d\nL%d:", label2, label1);
717 }
718 
719 /*
720  * Prlen() is a cheap prtype()...
721  */
722 static char convtab[SZINT/SZCHAR + 1] = {
723 	'?', 'b', 'w', '?', 'l'
724 };
725 #define	prlen(len)	putchar(convtab[len])
726 
727 
728 /*
729  * Generate code for integral scalar conversions.
730  * Some of this code is designed to work around a tahoe misfeature
731  *	that causes sign- and zero- extension to be defeated in
732  *	certain circumstances.
733  * Basically if the source operand of a CVT or MOVZ instruction is
734  *	shorter than the destination, and the source is a register
735  *	or an immediate constant, sign- and zero- extension are
736  *	ignored and the high bits of the source are copied.  (Note
737  *	that zero-extension is not a problem for immediate
738  *	constants.)
739  */
740 sconv(p, forcc)
741 	NODE *p;
742 	int forcc;
743 {
744 	register NODE *src, *dst;
745 	register NODE *tmp;
746 	register int srclen, dstlen;
747 	int srctype, dsttype;
748 	int val;
749 	int neg = 0;
750 
751 	if (p->in.op == ASSIGN) {
752 		src = p->in.right;
753 		dst = p->in.left;
754 		dstlen = tlen(dst);
755 		dsttype = dst->in.type;
756 	} else if (p->in.op == SCONV) {
757 		src = p->in.left;
758 		dst = resc;
759 		dstlen = tlen(p);
760 		dsttype = p->in.type;
761 	} else /* if (p->in.op == OPLEAF) */ {
762 		src = p;
763 		dst = resc;
764 		dstlen = SZINT/SZCHAR;
765 		dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
766 	}
767 
768 	if (src->in.op == REG) {
769 		srclen = SZINT/SZCHAR;
770 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
771 	} else {
772 		srclen = tlen(src);
773 		srctype = src->in.type;
774 	}
775 
776 	if (src->in.op == ICON && src->tn.name[0] == '\0') {
777 		if (src->tn.lval == 0) {
778 			putstr("clr");
779 			prtype(dst);
780 			putchar('\t');
781 			adrput(dst);
782 			return;
783 		}
784 		if (dstlen < srclen) {
785 			switch (dsttype) {
786 			case CHAR:
787 				src->tn.lval = (char) src->tn.lval;
788 				break;
789 			case UCHAR:
790 				src->tn.lval = (unsigned char) src->tn.lval;
791 				break;
792 			case SHORT:
793 				src->tn.lval = (short) src->tn.lval;
794 				break;
795 			case USHORT:
796 				src->tn.lval = (unsigned short) src->tn.lval;
797 				break;
798 			}
799 		}
800 		if (dst->in.op == REG) {
801 			dsttype = INT;
802 			dstlen = SZINT/SZCHAR;
803 		}
804 		srctype = dsttype;
805 		srclen = dstlen;
806 		val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
807 		if ((unsigned) val < 64) {
808 			src->tn.lval = val;
809 			++neg;		/* MNEGx may be shorter */
810 		}
811 	}
812 
813 	if (srclen < dstlen) {
814 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
815 			/* (unsigned short) c; => sign extend to 16 bits */
816 			putstr("cvtbl\t");
817 			adrput(src);
818 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
819 			adrput(dst);
820 			putstr("\n\tmovab\t4(sp),sp");
821 			if (forcc) {
822 				/* inverted test */
823 				putstr("\n\tcmpl\t$0,");
824 				adrput(dst);
825 			}
826 			return;
827 		}
828 		genconv(ISUNSIGNED(srctype),
829 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
830 			src, dst);
831 		return;
832 	}
833 
834 	if (srclen > dstlen && dst->in.op == REG) {
835 		/* if dst is a register, the result must look like an int */
836 		if (src->in.op == REG) {
837 			if (ISUNSIGNED(dsttype)) {
838 				val = (1 << dstlen * SZCHAR) - 1;
839 				if (src->tn.rval == dst->tn.rval)
840 					/* conversion in place */
841 					printf("andl2\t$%ld,", val);
842 				else {
843 					printf("andl3\t$%ld,", val);
844 					adrput(src);
845 					putchar(',');
846 				}
847 				adrput(dst);
848 				return;
849 			}
850 			/*
851 			 * Sign extension in register can also be
852 			 * accomplished by shifts, but unfortunately
853 			 * shifts are extremely slow, due to the lack
854 			 * of a barrel shifter.
855 			 */
856 			putstr("pushl\t");
857 			adrput(src);
858 			putstr("\n\tcvt");
859 			prlen(dstlen);
860 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
861 			adrput(dst);
862 			putstr("\n\tmovab\t4(sp),sp");
863 			if (forcc) {
864 				/* inverted test */
865 				putstr("\n\tcmpl\t$0,");
866 				adrput(dst);
867 			}
868 			return;
869 		}
870 		tmp = talloc();
871 		if ((src->in.op == NAME) ||
872 		    (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
873 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
874 			/* we can increment src's address & pun it */
875 			*tmp = *src;
876 			tmp->tn.lval += srclen - dstlen;
877 		} else {
878 			/* we must store src's address */
879 			*tmp = *dst;
880 			putstr("mova");
881 			prlen(srclen);
882 			putchar('\t');
883 			adrput(src);
884 			putchar(',');
885 			adrput(tmp);
886 			putstr("\n\t");
887 			tmp->tn.op = OREG;
888 			tmp->tn.lval = srclen - dstlen;
889 		}
890 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
891 		tmp->in.op = FREE;
892 		return;
893 	}
894 
895 	genconv(neg ? -1 : ISUNSIGNED(dsttype),
896 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
897 		src, dst);
898 }
899 
900 genconv(srcflag, srclen, dstlen, src, dst)
901 	int srcflag;
902 	register int srclen, dstlen;
903 	NODE *src, *dst;
904 {
905 	if (srclen != dstlen) {
906 		if (srcflag > 0 && srclen < dstlen)
907 			putstr("movz");
908 		else
909 			putstr("cvt");
910 		prlen(srclen);
911 	} else if (srcflag < 0)
912 		putstr("mneg");
913 	else
914 		putstr("mov");
915 	prlen(dstlen);
916 	putchar('\t');
917 	adrput(src);
918 	putchar(',');
919 	adrput(dst);
920 }
921 
922 rmove( rt, rs, t ) TWORD t; {
923 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
924 	if(t==DOUBLE)
925 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
926 	}
927 
928 struct respref
929 respref[] = {
930 	INTAREG|INTBREG,	INTAREG|INTBREG,
931 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
932 	INTEMP,	INTEMP,
933 	FORARG,	FORARG,
934 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
935 	0,	0 };
936 
937 setregs(){ /* set up temporary registers */
938 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
939 	}
940 
941 #ifndef szty
942 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
943 	return(t==DOUBLE ? 2 : 1 );
944 	}
945 #endif
946 
947 /*ARGSUSED*/
948 rewfld( p ) NODE *p; {
949 	return(1);
950 	}
951 
952 /*ARGSUSED*/
953 callreg(p) NODE *p; {
954 	return( R0 );
955 	}
956 
957 base( p ) register NODE *p; {
958 	register int o = p->in.op;
959 
960 	if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
961 	if( o==REG ) return( p->tn.rval );
962     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
963 		return( p->in.left->tn.rval );
964     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
965 		return( p->tn.rval + 0200*1 );
966 	if( o==NAME ) return( 100 + 0200*1 );
967 	return( -1 );
968 	}
969 
970 offset( p, tyl ) register NODE *p; int tyl; {
971 
972 	if( tyl==1 &&
973 	    p->in.op==REG &&
974 	    (p->in.type==INT || p->in.type==UNSIGNED) )
975 		return( p->tn.rval );
976 	if( p->in.op==LS &&
977 	    p->in.left->in.op==REG &&
978 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
979 	    p->in.right->in.op==ICON &&
980 	    p->in.right->in.name[0]=='\0' &&
981 	    (1<<p->in.right->tn.lval)==tyl)
982 		return( p->in.left->tn.rval );
983 	if( tyl==2 &&
984 	    p->in.op==PLUS &&
985 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
986 	    p->in.left->in.op==REG &&
987 	    p->in.right->in.op==REG &&
988 	    p->in.left->tn.rval==p->in.right->tn.rval )
989 		return( p->in.left->tn.rval );
990 	return( -1 );
991 	}
992 
993 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
994 	register NODE *t;
995 	NODE *f;
996 
997 	p->in.op = OREG;
998 	f = p->in.left; 	/* have to free this subtree later */
999 
1000 	/* init base */
1001 	switch (q->in.op) {
1002 		case ICON:
1003 		case REG:
1004 		case OREG:
1005 		case NAME:
1006 			t = q;
1007 			break;
1008 
1009 		case MINUS:
1010 			q->in.right->tn.lval = -q->in.right->tn.lval;
1011 		case PLUS:
1012 			t = q->in.right;
1013 			break;
1014 
1015 		case UNARY MUL:
1016 			t = q->in.left->in.left;
1017 			break;
1018 
1019 		default:
1020 			cerror("illegal makeor2");
1021 	}
1022 
1023 	p->tn.lval = t->tn.lval;
1024 #ifndef FLEXNAMES
1025 	{
1026 		register int i;
1027 		for(i=0; i<NCHNAM; ++i)
1028 			p->in.name[i] = t->in.name[i];
1029 	}
1030 #else
1031 	p->in.name = t->in.name;
1032 #endif
1033 
1034 	/* init offset */
1035 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
1036 
1037 	tfree(f);
1038 	return;
1039 	}
1040 
1041 canaddr( p ) NODE *p; {
1042 	register int o = p->in.op;
1043 
1044 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1045 	return(0);
1046 	}
1047 
1048 #ifndef shltype
1049 shltype( o, p ) register NODE *p; {
1050 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
1051 	}
1052 #endif
1053 
1054 flshape( p ) NODE *p; {
1055 	register int o = p->in.op;
1056 
1057 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1058 	return(0);
1059 	}
1060 
1061 /* INTEMP shapes must not contain any temporary registers */
1062 shtemp( p ) register NODE *p; {
1063 	int r;
1064 
1065 	if( p->in.op == STARG ) p = p->in.left;
1066 
1067 	switch (p->in.op) {
1068 	case REG:
1069 		return( !istreg(p->tn.rval) );
1070 	case OREG:
1071 		r = p->tn.rval;
1072 		if( R2TEST(r) ) {
1073 			if( istreg(R2UPK1(r)) )
1074 				return(0);
1075 			r = R2UPK2(r);
1076 			}
1077 		return( !istreg(r) );
1078 	case UNARY MUL:
1079 		p = p->in.left;
1080 		return( p->in.op != UNARY MUL && shtemp(p) );
1081 		}
1082 
1083 	if( optype( p->in.op ) != LTYPE ) return(0);
1084 	return(1);
1085 	}
1086 
1087 shumul( p ) register NODE *p; {
1088 	register int o;
1089 	extern int xdebug;
1090 
1091 	if (xdebug) {
1092 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1093 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1094 		}
1095 
1096 	o = p->in.op;
1097 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1098 	 && p->in.type != PTR+DOUBLE)
1099 		return( STARNM );
1100 
1101 	return( 0 );
1102 	}
1103 
1104 special( p, shape ) register NODE *p; {
1105 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
1106 	else return(0);
1107 }
1108 
1109 adrcon( val ) CONSZ val; {
1110 	printf(ACONFMT, val);
1111 	}
1112 
1113 conput( p ) register NODE *p; {
1114 	switch( p->in.op ){
1115 
1116 	case ICON:
1117 		acon( p );
1118 		return;
1119 
1120 	case REG:
1121 		putstr(rname(p->tn.rval));
1122 		return;
1123 
1124 	default:
1125 		cerror( "illegal conput" );
1126 		}
1127 	}
1128 
1129 /*ARGSUSED*/
1130 insput( p ) NODE *p; {
1131 	cerror( "insput" );
1132 	}
1133 
1134 /*
1135  * Output the address of the second item in the
1136  * pair pointed to by p.
1137  */
1138 upput(p, size)
1139 	register NODE *p;
1140 {
1141 	CONSZ save;
1142 
1143 	if (p->in.op == FLD)
1144 		p = p->in.left;
1145 	switch (p->in.op) {
1146 
1147 	case NAME:
1148 	case OREG:
1149 		save = p->tn.lval;
1150 		p->tn.lval += size/SZCHAR;
1151 		adrput(p);
1152 		p->tn.lval = save;
1153 		break;
1154 
1155 	case REG:
1156 		if (size == SZLONG) {
1157 			putstr(rname(p->tn.rval+1));
1158 			break;
1159 		}
1160 		/* fall thru... */
1161 
1162 	default:
1163 		cerror("illegal upper address op %s size %d",
1164 		    opst[p->tn.op], size);
1165 		/*NOTREACHED*/
1166 	}
1167 }
1168 
1169 adrput( p ) register NODE *p; {
1170 	register int r;
1171 	/* output an address, with offsets, from p */
1172 
1173 	if( p->in.op == FLD ){
1174 		p = p->in.left;
1175 		}
1176 	switch( p->in.op ){
1177 
1178 	case NAME:
1179 		acon( p );
1180 		return;
1181 
1182 	case ICON:
1183 		/* addressable value of the constant */
1184 		putchar('$');
1185 		acon( p );
1186 		return;
1187 
1188 	case REG:
1189 		putstr(rname(p->tn.rval));
1190 		if(p->in.type == DOUBLE)	/* for entry mask */
1191 			(void) rname(p->tn.rval+1);
1192 		return;
1193 
1194 	case OREG:
1195 		r = p->tn.rval;
1196 		if( R2TEST(r) ){ /* double indexing */
1197 			register int flags;
1198 
1199 			flags = R2UPK3(r);
1200 			if( flags & 1 ) putchar('*');
1201 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1202 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1203 			printf( "[%s]", rname(R2UPK2(r)) );
1204 			return;
1205 			}
1206 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
1207 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1208 			printf( CONFMT, p->tn.lval );
1209 			putstr( "(fp)" );
1210 			return;
1211 			}
1212 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1213 		printf( "(%s)", rname(p->tn.rval) );
1214 		return;
1215 
1216 	case UNARY MUL:
1217 		/* STARNM or STARREG found */
1218 		if( tshape(p, STARNM) ) {
1219 			putchar( '*' );
1220 			adrput( p->in.left);
1221 			}
1222 		return;
1223 
1224 	default:
1225 		cerror( "illegal address" );
1226 		return;
1227 
1228 		}
1229 
1230 	}
1231 
1232 acon( p ) register NODE *p; { /* print out a constant */
1233 
1234 	if( p->in.name[0] == '\0' )
1235 		printf( CONFMT, p->tn.lval);
1236 	else {
1237 #ifndef FLEXNAMES
1238 		printf( "%.8s", p->in.name );
1239 #else
1240 		putstr( p->in.name );
1241 #endif
1242 		if( p->tn.lval != 0 ) {
1243 			putchar( '+' );
1244 			printf( CONFMT, p->tn.lval );
1245 			}
1246 		}
1247 	}
1248 
1249 genscall( p, cookie ) register NODE *p; {
1250 	/* structure valued call */
1251 	return( gencall( p, cookie ) );
1252 	}
1253 
1254 genfcall( p, cookie ) register NODE *p; {
1255 	register NODE *p1;
1256 	register int m;
1257 	static char *funcops[6] = {
1258 		"sin", "cos", "sqrt", "exp", "log", "atan"
1259 	};
1260 
1261 	/* generate function opcodes */
1262 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1263 	 (p1 = p->in.left)->in.op==ICON &&
1264 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1265 #ifdef FLEXNAMES
1266 		p1->in.name++;
1267 #else
1268 		strcpy(p1->in.name, p1->in.name[1]);
1269 #endif
1270 		for(m=0; m<6; m++)
1271 			if(!strcmp(p1->in.name, funcops[m]))
1272 				break;
1273 		if(m >= 6)
1274 			uerror("no opcode for fortarn function %s", p1->in.name);
1275 	} else
1276 		uerror("illegal type of fortarn function");
1277 	p1 = p->in.right;
1278 	p->in.op = FORTCALL;
1279 	if(!canaddr(p1))
1280 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1281 	m = match( p, INTAREG|INTBREG );
1282 	return(m != MDONE);
1283 }
1284 
1285 /* tbl */
1286 int gc_numbytes;
1287 /* tbl */
1288 
1289 /*ARGSUSED*/
1290 gencall( p, cookie ) register NODE *p; {
1291 	/* generate the call given by p */
1292 	register NODE *p1, *ptemp;
1293 	register int temp, temp1;
1294 	register int m;
1295 
1296 	if( p->in.right ) temp = argsize( p->in.right );
1297 	else temp = 0;
1298 
1299 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1300 		/* set aside room for structure return */
1301 
1302 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1303 		else temp1 = temp;
1304 		}
1305 
1306 	if( temp > maxargs ) maxargs = temp;
1307 	SETOFF(temp1,4);
1308 
1309 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1310 		ptemp = talloc();
1311 		ptemp->in.op = OREG;
1312 		ptemp->tn.lval = -1;
1313 		ptemp->tn.rval = SP;
1314 #ifndef FLEXNAMES
1315 		ptemp->in.name[0] = '\0';
1316 #else
1317 		ptemp->in.name = "";
1318 #endif
1319 		ptemp->in.rall = NOPREF;
1320 		ptemp->in.su = 0;
1321 		genargs( p->in.right, ptemp );
1322 		ptemp->in.op = FREE;
1323 		}
1324 
1325 	p1 = p->in.left;
1326 	if( p1->in.op != ICON ){
1327 		if( p1->in.op != REG ){
1328 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1329 				if( p1->in.op != NAME ){
1330 					order( p1, INAREG );
1331 					}
1332 				}
1333 			}
1334 		}
1335 
1336 /* tbl
1337 	setup gc_numbytes so reference to ZC works */
1338 
1339 	gc_numbytes = temp&(0x3ff);
1340 
1341 	p->in.op = UNARY CALL;
1342 	m = match( p, INTAREG|INTBREG );
1343 
1344 	return(m != MDONE);
1345 	}
1346 
1347 /* tbl */
1348 char *
1349 ccbranches[] = {
1350 	"eql",
1351 	"neq",
1352 	"leq",
1353 	"lss",
1354 	"geq",
1355 	"gtr",
1356 	"lequ",
1357 	"lssu",
1358 	"gequ",
1359 	"gtru",
1360 	};
1361 /* tbl */
1362 
1363 /*ARGSUSED*/
1364 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1365 
1366 	if( o != 0 && ( o < EQ || o > UGT ) )
1367 		cerror( "bad conditional branch: %s", opst[o] );
1368 	printf( "	j%s	L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
1369 	}
1370 
1371 nextcook( p, cookie ) NODE *p; {
1372 	/* we have failed to match p with cookie; try another */
1373 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1374 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1375 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1376 	return( FORREW );
1377 	}
1378 
1379 /*ARGSUSED*/
1380 lastchance( p, cook ) NODE *p; {
1381 	/* forget it! */
1382 	return(0);
1383 	}
1384 
1385 optim2( p ) register NODE *p; {
1386 	/* do local tree transformations and optimizations */
1387 
1388 	int o;
1389 	int i, mask;
1390 	register NODE *l, *r;
1391 
1392 	switch( o = p->in.op ) {
1393 
1394 	case ASG PLUS:
1395 	case ASG MINUS:
1396 	case ASG MUL:
1397 	case ASG OR:
1398 		/* simple ASG OPSIMP -- reduce range of constant rhs */
1399 		l = p->in.left;
1400 		r = p->in.right;
1401 		if( tlen(l) < SZINT/SZCHAR &&
1402 		    r->in.op==ICON && r->in.name[0]==0 ){
1403 			mask = (1 << tlen(l) * SZCHAR) - 1;
1404 			if( r->tn.lval & (mask & ~(mask >> 1)) )
1405 				r->tn.lval |= ~mask;
1406 			else
1407 				r->tn.lval &= mask;
1408 			}
1409 		break;
1410 
1411 	case AND:
1412 	case ASG AND:
1413 		r = p->in.right;
1414 		if( r->in.op==ICON && r->in.name[0]==0 ) {
1415 			/* check for degenerate operations */
1416 			l = p->in.left;
1417 			mask = (1 << tlen(l) * SZCHAR) - 1;
1418 			if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
1419 				i = r->tn.lval & mask;
1420 				if( i == mask ) {
1421 					/* redundant mask */
1422 					r->in.op = FREE;
1423 					ncopy(p, l);
1424 					l->in.op = FREE;
1425 					break;
1426 					}
1427 				else if( i == 0 )
1428 					/* all bits masked off */
1429 					goto zero;
1430 				r->tn.lval = i;
1431 				if( tlen(l) < SZINT/SZCHAR ){
1432 					/* sign extend */
1433 					if( r->tn.lval & (mask & ~(mask >> 1)) )
1434 						r->tn.lval |= ~mask;
1435 					else
1436 						r->tn.lval &= mask;
1437 					}
1438 				}
1439 			else if( r->tn.lval == mask &&
1440 				 tlen(l) < SZINT/SZCHAR ) {
1441 				/* use movz instead of and */
1442 				r->in.op = SCONV;
1443 				r->in.left = l;
1444 				r->in.right = 0;
1445 				r->in.type = ENUNSIGN(l->in.type);
1446 				r->in.su = l->in.su > 1 ? l->in.su : 1;
1447 				ncopy(p, r);
1448 				p->in.left = r;
1449 				p->in.type = INT;
1450 				}
1451 			}
1452 		break;
1453 
1454 	case SCONV:
1455 		l = p->in.left;
1456 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1457 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1458 			return;
1459 		if( l->in.op == PCONV )
1460 			return;
1461 		if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
1462 		    l->in.type != INT && l->in.type != UNSIGNED )
1463 			return;
1464 
1465 		/* Only trust it to get it right if the size is the same */
1466 		if( tlen(p) != tlen(l) )
1467 			return;
1468 
1469 		/* clobber conversion */
1470 		if( l->in.op != FLD )
1471 			l->in.type = p->in.type;
1472 		ncopy( p, l );
1473 		l->in.op = FREE;
1474 
1475 		break;
1476 
1477 	case ASSIGN:
1478 		/*
1479 		 * Conversions are equivalent to assignments;
1480 		 * when the two operations are combined,
1481 		 * we can sometimes zap the conversion.
1482 		 */
1483 		r = p->in.right;
1484 		l = p->in.left;
1485 		if ( r->in.op == SCONV &&
1486 		     !mixtypes(l, r) &&
1487 		     l->in.op != FLD &&
1488 		     tlen(l) == tlen(r) ) {
1489 				p->in.right = r->in.left;
1490 				r->in.op = FREE;
1491 			}
1492 		break;
1493 
1494 	case ULE:
1495 	case ULT:
1496 	case UGE:
1497 	case UGT:
1498 		p->in.op -= (UGE-GE);
1499 		if( degenerate(p) )
1500 			break;
1501 		p->in.op += (UGE-GE);
1502 		break;
1503 
1504 	case EQ:
1505 	case NE:
1506 	case LE:
1507 	case LT:
1508 	case GE:
1509 	case GT:
1510 		if( p->in.left->in.op == SCONV &&
1511 		    p->in.right->in.op == SCONV ) {
1512 			l = p->in.left;
1513 			r = p->in.right;
1514 			if( l->in.type == DOUBLE &&
1515 			    l->in.left->in.type == FLOAT &&
1516 			    r->in.left->in.type == FLOAT ) {
1517 				/* nuke the conversions */
1518 				p->in.left = l->in.left;
1519 				p->in.right = r->in.left;
1520 				l->in.op = FREE;
1521 				r->in.op = FREE;
1522 				}
1523 			/* more? */
1524 			}
1525 		(void) degenerate(p);
1526 		break;
1527 
1528 	case DIV:
1529 		if( p->in.right->in.op == ICON &&
1530 		    p->in.right->tn.name[0] == '\0' &&
1531 		    ISUNSIGNED(p->in.right->in.type) &&
1532 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1533 			/* easy to do here, harder to do in zzzcode() */
1534 			p->in.op = UGE;
1535 			break;
1536 			}
1537 	case MOD:
1538 	case ASG DIV:
1539 	case ASG MOD:
1540 		/*
1541 		 * optimize DIV and MOD
1542 		 *
1543 		 * basically we spot UCHAR and USHORT and try to do them
1544 		 * as signed ints...  this may need tuning for the tahoe.
1545 		 */
1546 		if( degenerate(p) )
1547 			break;
1548 		l = p->in.left;
1549 		r = p->in.right;
1550 		if( !ISUNSIGNED(r->in.type) ||
1551 		    tlen(l) >= SZINT/SZCHAR ||
1552 		    !(tlen(r) < SZINT/SZCHAR ||
1553 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
1554 			break;
1555 		if( r->in.op == ICON )
1556 			r->tn.type = INT;
1557 		else {
1558 			NODE *t = talloc();
1559 			t->in.left = r;
1560 			r = t;
1561 			r->in.op = SCONV;
1562 			r->in.type = INT;
1563 			r->in.right = 0;
1564 			p->in.right = r;
1565 			}
1566 		if( o == DIV || o == MOD ) {
1567 			NODE *t = talloc();
1568 			t->in.left = l;
1569 			l = t;
1570 			l->in.op = SCONV;
1571 			l->in.type = INT;
1572 			l->in.right = 0;
1573 			p->in.left = l;
1574 			}
1575 		/* handle asgops in table */
1576 		break;
1577 
1578 	case RS:
1579 	case ASG RS:
1580 	case LS:
1581 	case ASG LS:
1582 		/* pick up degenerate shifts */
1583 		l = p->in.left;
1584 		r = p->in.right;
1585 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
1586 			break;
1587 		i = r->tn.lval;
1588 		if( i < 0 )
1589 			/* front end 'fixes' this? */
1590 			if( o == LS || o == ASG LS )
1591 				o += (RS-LS);
1592 			else
1593 				o += (LS-RS);
1594 		if( (o == RS || o == ASG RS) &&
1595 		    !ISUNSIGNED(l->in.type) )
1596 			/* can't optimize signed right shifts */
1597 			break;
1598 		if( o == LS ) {
1599 			if( i < SZINT )
1600 				break;
1601 			}
1602 		else {
1603 			if( i < tlen(l) * SZCHAR )
1604 				break;
1605 			}
1606 	zero:
1607 		if( !asgop( o ) )
1608 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1609 				/* no side effects */
1610 				tfree(l);
1611 				ncopy(p, r);
1612 				r->in.op = FREE;
1613 				p->tn.lval = 0;
1614 				}
1615 			else {
1616 				p->in.op = COMOP;
1617 				r->tn.lval = 0;
1618 				}
1619 		else {
1620 			p->in.op = ASSIGN;
1621 			r->tn.lval = 0;
1622 			}
1623 		break;
1624 		}
1625 	}
1626 
1627 degenerate(p) register NODE *p; {
1628 	int o;
1629 	int result, i;
1630 	int lower, upper;
1631 	register NODE *l, *r;
1632 
1633 	/*
1634 	 * try to keep degenerate comparisons with constants
1635 	 * out of the table.
1636 	 */
1637 	r = p->in.right;
1638 	l = p->in.left;
1639 	if( r->in.op != ICON ||
1640 	    r->tn.name[0] != '\0' ||
1641 	    tlen(l) >= tlen(r) )
1642 		return (0);
1643 	switch( l->in.type ) {
1644 	case CHAR:
1645 		lower = -(1 << SZCHAR - 1);
1646 		upper = (1 << SZCHAR - 1) - 1;
1647 		break;
1648 	case UCHAR:
1649 		lower = 0;
1650 		upper = (1 << SZCHAR) - 1;
1651 		break;
1652 	case SHORT:
1653 		lower = -(1 << SZSHORT - 1);
1654 		upper = (1 << SZSHORT - 1) - 1;
1655 		break;
1656 	case USHORT:
1657 		lower = 0;
1658 		upper = (1 << SZSHORT) - 1;
1659 		break;
1660 	default:
1661 		cerror("unsupported type in degenerate()");
1662 		}
1663 	i = r->tn.lval;
1664 	switch( o = p->in.op ) {
1665 	case DIV:
1666 	case ASG DIV:
1667 	case MOD:
1668 	case ASG MOD:
1669 		/* DIV and MOD work like EQ */
1670 	case EQ:
1671 	case NE:
1672 		if( lower == 0 && (unsigned) i > upper )
1673 			result = o == NE;
1674 		else if( i < lower || i > upper )
1675 			result = o == NE;
1676 		else
1677 			return (0);
1678 		break;
1679 	case LT:
1680 	case GE:
1681 		if( lower == 0 && (unsigned) i > upper )
1682 			result = o == LT;
1683 		else if( i <= lower )
1684 			result = o != LT;
1685 		else if( i > upper )
1686 			result = o == LT;
1687 		else
1688 			return (0);
1689 		break;
1690 	case LE:
1691 	case GT:
1692 		if( lower == 0 && (unsigned) i >= upper )
1693 			result = o == LE;
1694 		else if( i < lower )
1695 			result = o != LE;
1696 		else if( i >= upper )
1697 			result = o == LE;
1698 		else
1699 			return (0);
1700 		break;
1701 	default:
1702 		cerror("unknown op in degenerate()");
1703 		}
1704 
1705 	if( o == MOD || o == ASG MOD ) {
1706 		r->in.op = FREE;
1707 		ncopy(p, l);
1708 		l->in.op = FREE;
1709 		}
1710 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1711 		/* no side effects */
1712 		tfree(l);
1713 		ncopy(p, r);
1714 		r->in.op = FREE;
1715 		p->tn.lval = result;
1716 		}
1717 	else {
1718 		if( o == ASG DIV )
1719 			p->in.op = ASSIGN;
1720 		else {
1721 			p->in.op = COMOP;
1722 			r->tn.type = INT;
1723 			}
1724 		r->tn.lval = result;
1725 		}
1726 	if( logop(o) )
1727 		p->in.type = INT;
1728 
1729 	return (1);
1730 	}
1731 
1732 struct functbl {
1733 	int fop;
1734 	TWORD ftype;
1735 	char *func;
1736 	} opfunc[] = {
1737 	DIV,		TANY,	"udiv",
1738 	MOD,		TANY,	"urem",
1739 	ASG DIV,	TANY,	"audiv",
1740 	ASG MOD,	TANY,	"aurem",
1741 	0,	0,	0 };
1742 
1743 hardops(p)  register NODE *p; {
1744 	/* change hard to do operators into function calls.  */
1745 	register NODE *q;
1746 	register struct functbl *f;
1747 	register o;
1748 	NODE *old,*temp;
1749 
1750 	o = p->in.op;
1751 	if( ! (optype(o)==BITYPE &&
1752 	       (ISUNSIGNED(p->in.left->in.type) ||
1753 		ISUNSIGNED(p->in.right->in.type))) )
1754 		return;
1755 
1756 	for( f=opfunc; f->fop; f++ ) {
1757 		if( o==f->fop ) goto convert;
1758 		}
1759 	return;
1760 
1761 	convert:
1762 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1763 		/* 'J' in zzzcode() -- assumes DIV or MOD operations */
1764 		/* save a subroutine call -- use at most 5 instructions */
1765 		return;
1766 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1767 		/* optim2() will modify the op into an ordinary int op */
1768 		return;
1769 	if( asgop( o ) ) {
1770 		old = NIL;
1771 		switch( p->in.left->in.op ){
1772 		case FLD:
1773 			q = p->in.left->in.left;
1774 			/*
1775 			 * rewrite (lval.fld /= rval); as
1776 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1777 			 * else the compiler will evaluate lval twice.
1778 			 */
1779 			if( q->in.op == UNARY MUL ){
1780 				/* first allocate a temp storage */
1781 				temp = talloc();
1782 				temp->in.op = OREG;
1783 				temp->tn.rval = TMPREG;
1784 				temp->tn.lval = BITOOR(freetemp(1));
1785 				temp->in.type = INCREF(p->in.type);
1786 #ifdef FLEXNAMES
1787 				temp->in.name = "";
1788 #else
1789 				temp->in.name[0] = '\0';
1790 #endif
1791 				old = q->in.left;
1792 				q->in.left = temp;
1793 			}
1794 			/* fall thru ... */
1795 
1796 		case REG:
1797 		case NAME:
1798 		case OREG:
1799 			/* change ASG OP to a simple OP */
1800 			q = talloc();
1801 			q->in.op = NOASG p->in.op;
1802 			q->in.rall = NOPREF;
1803 			q->in.type = p->in.type;
1804 			q->in.left = tcopy(p->in.left);
1805 			q->in.right = p->in.right;
1806 			p->in.op = ASSIGN;
1807 			p->in.right = q;
1808 			p = q;
1809 			f -= 2; /* Note: this depends on the table order */
1810 			/* on the right side only - replace *temp with
1811 			 *(temp = &lval), build the assignment node */
1812 			if( old ){
1813 				temp = q->in.left->in.left; /* the "*" node */
1814 				q = talloc();
1815 				q->in.op = ASSIGN;
1816 				q->in.left = temp->in.left;
1817 				q->in.right = old;
1818 				q->in.type = old->in.type;
1819 #ifdef FLEXNAMES
1820 				q->in.name = "";
1821 #else
1822 				q->in.name[0] = '\0';
1823 #endif
1824 				temp->in.left = q;
1825 			}
1826 			break;
1827 
1828 		case UNARY MUL:
1829 			/* avoid doing side effects twice */
1830 			q = p->in.left;
1831 			p->in.left = q->in.left;
1832 			q->in.op = FREE;
1833 			break;
1834 
1835 		default:
1836 			cerror( "hardops: can't compute & LHS" );
1837 			}
1838 		}
1839 
1840 	/* build comma op for args to function */
1841 	q = talloc();
1842 	q->in.op = CM;
1843 	q->in.rall = NOPREF;
1844 	q->in.type = INT;
1845 	q->in.left = p->in.left;
1846 	q->in.right = p->in.right;
1847 	p->in.op = CALL;
1848 	p->in.right = q;
1849 
1850 	/* put function name in left node of call */
1851 	p->in.left = q = talloc();
1852 	q->in.op = ICON;
1853 	q->in.rall = NOPREF;
1854 	q->in.type = INCREF( FTN + p->in.type );
1855 #ifndef FLEXNAMES
1856 	strcpy( q->in.name, f->func );
1857 #else
1858 	q->in.name = f->func;
1859 #endif
1860 	q->tn.lval = 0;
1861 	q->tn.rval = 0;
1862 
1863 	}
1864 
1865 zappost(p) NODE *p; {
1866 	/* look for ++ and -- operators and remove them */
1867 
1868 	register int o, ty;
1869 	register NODE *q;
1870 	o = p->in.op;
1871 	ty = optype( o );
1872 
1873 	switch( o ){
1874 
1875 	case INCR:
1876 	case DECR:
1877 			q = p->in.left;
1878 			p->in.right->in.op = FREE;  /* zap constant */
1879 			ncopy( p, q );
1880 			q->in.op = FREE;
1881 			return;
1882 
1883 		}
1884 
1885 	if( ty == BITYPE ) zappost( p->in.right );
1886 	if( ty != LTYPE ) zappost( p->in.left );
1887 }
1888 
1889 fixpre(p) NODE *p; {
1890 
1891 	register int o, ty;
1892 	o = p->in.op;
1893 	ty = optype( o );
1894 
1895 	switch( o ){
1896 
1897 	case ASG PLUS:
1898 			p->in.op = PLUS;
1899 			break;
1900 	case ASG MINUS:
1901 			p->in.op = MINUS;
1902 			break;
1903 		}
1904 
1905 	if( ty == BITYPE ) fixpre( p->in.right );
1906 	if( ty != LTYPE ) fixpre( p->in.left );
1907 }
1908 
1909 /*ARGSUSED*/
1910 NODE * addroreg(l) NODE *l;
1911 				/* OREG was built in clocal()
1912 				 * for an auto or formal parameter
1913 				 * now its address is being taken
1914 				 * local code must unwind it
1915 				 * back to PLUS/MINUS REG ICON
1916 				 * according to local conventions
1917 				 */
1918 {
1919 	cerror("address of OREG taken");
1920 	/*NOTREACHED*/
1921 }
1922 
1923 # ifndef ONEPASS
1924 main( argc, argv ) char *argv[]; {
1925 	return( mainp2( argc, argv ) );
1926 	}
1927 # endif
1928 
1929 strip(p) register NODE *p; {
1930 	NODE *q;
1931 
1932 	/* strip nodes off the top when no side effects occur */
1933 	for( ; ; ) {
1934 		switch( p->in.op ) {
1935 		case SCONV:			/* remove lint tidbits */
1936 			q = p->in.left;
1937 			ncopy( p, q );
1938 			q->in.op = FREE;
1939 			break;
1940 		/* could probably add a few more here */
1941 		default:
1942 			return;
1943 			}
1944 		}
1945 	}
1946 
1947 myreader(p) register NODE *p; {
1948 	strip( p );		/* strip off operations with no side effects */
1949 	canon( p );		/* expands r-vals for fields */
1950 	walkf( p, hardops );	/* convert ops to function calls */
1951 	walkf( p, optim2 );
1952 	}
1953