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