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