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