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