xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32877)
1 #ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.15 (Berkeley) 12/10/87";
3 #endif
4 
5 # include "pass2.h"
6 # include <ctype.h>
7 
8 # define putstr(s)	fputs((s), stdout)
9 # define ISCHAR(p)	(p->in.type == UCHAR || p->in.type == CHAR)
10 
11 # ifdef FORT
12 int ftlab1, ftlab2;
13 # endif
14 /* a lot of the machine dependent parts of the second pass */
15 
16 # define BITMASK(n) ((1L<<n)-1)
17 
18 # ifndef ONEPASS
19 where(c){
20 	fprintf( stderr, "%s, line %d: ", filename, lineno );
21 	}
22 # endif
23 
24 lineid( l, fn ) char *fn; {
25 	/* identify line l and file fn */
26 	printf( "#	line %d, file %s\n", l, fn );
27 	}
28 
29 int ent_mask;
30 
31 eobl2(){
32 	register OFFSZ spoff;	/* offset from stack pointer */
33 #ifndef FORT
34 	extern int ftlab1, ftlab2;
35 #endif
36 
37 	spoff = maxoff;
38 	spoff /= SZCHAR;
39 	SETOFF(spoff,4);
40 #ifdef FORT
41 #ifndef FLEXNAMES
42 	printf( "	.set	.F%d,%d\n", ftnno, spoff );
43 #else
44 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
45 	printf( "	.set	LF%d,%d\n", ftnno, spoff );
46 #endif
47 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
48 #else
49 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
50 	printf( "L%d:\n", ftlab1);
51 	if( maxoff > AUTOINIT )
52 		printf( "	subl3	$%d,fp,sp\n", spoff);
53 	printf( "	jbr 	L%d\n", ftlab2);
54 #endif
55 	ent_mask = 0;
56 	maxargs = -1;
57 	}
58 
59 struct hoptab { int opmask; char * opstring; } ioptab[] = {
60 
61 	PLUS,	"add",
62 	MINUS,	"sub",
63 	MUL,	"mul",
64 	DIV,	"div",
65 	MOD,	"div",
66 	OR,	"or",
67 	ER,	"xor",
68 	AND,	"and",
69 	-1,	""    };
70 
71 hopcode( f, o ){
72 	/* output the appropriate string from the above table */
73 
74 	register struct hoptab *q;
75 
76 	if(asgop(o))
77 		o = NOASG o;
78 	for( q = ioptab;  q->opmask>=0; ++q ){
79 		if( q->opmask == o ){
80 			if(f == 'E')
81 				printf( "e%s", q->opstring);
82 			else
83 				printf( "%s%c", q->opstring, tolower(f));
84 			return;
85 			}
86 		}
87 	cerror( "no hoptab for %s", opst[o] );
88 	}
89 
90 char *
91 rnames[] = {  /* keyed to register number tokens */
92 
93 	"r0", "r1",
94 	"r2", "r3", "r4", "r5",
95 	"r6", "r7", "r8", "r9", "r10", "r11",
96 	"r12", "fp", "sp", "pc",
97 	};
98 
99 /* output register name and update entry mask */
100 char *
101 rname(r)
102 	register int r;
103 {
104 
105 	ent_mask |= 1<<r;
106 	return(rnames[r]);
107 }
108 
109 int rstatus[] = {
110 	SAREG|STAREG, SAREG|STAREG,
111 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
112 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
113 	SAREG, SAREG, SAREG, SAREG,
114 	};
115 
116 tlen(p) NODE *p;
117 {
118 	switch(p->in.type) {
119 		case CHAR:
120 		case UCHAR:
121 			return(1);
122 
123 		case SHORT:
124 		case USHORT:
125 			return(2);
126 
127 		case DOUBLE:
128 			return(8);
129 
130 		default:
131 			return(4);
132 		}
133 }
134 
135 anyfloat(p, q)
136 	NODE *p, *q;
137 {
138 	register TWORD tp, tq;
139 
140 	tp = p->in.type;
141 	tq = q->in.type;
142 	return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
143 }
144 
145 prtype(n) NODE *n;
146 {
147 	switch (n->in.type)
148 		{
149 
150 		case DOUBLE:
151 			putchar('d');
152 			return;
153 
154 		case FLOAT:
155 			putchar('f');
156 			return;
157 
158 		case INT:
159 		case UNSIGNED:
160 			putchar('l');
161 			return;
162 
163 		case SHORT:
164 		case USHORT:
165 			putchar('w');
166 			return;
167 
168 		case CHAR:
169 		case UCHAR:
170 			putchar('b');
171 			return;
172 
173 		default:
174 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
175 			else {
176 				putchar('l');
177 				return;
178 				}
179 		}
180 }
181 
182 zzzcode( p, c ) register NODE *p; {
183 	register int m;
184 	int val;
185 	switch( c ){
186 
187 	case 'N':  /* logical ops, turned into 0-1 */
188 		/* use register given by register 1 */
189 		cbgen( 0, m=getlab(), 'I' );
190 		deflab( p->bn.label );
191 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
192 		deflab( m );
193 		return;
194 
195 	case 'P':
196 		cbgen( p->in.op, p->bn.label, c );
197 		return;
198 
199 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
200 		{
201 		register NODE *l, *r, *s;
202 		int lt, rt;
203 
204 		l = p->in.left;
205 		r = p->in.right;
206 		s = talloc();
207 		rt = r->in.type;
208 		lt = l->in.type;
209 
210 		if (lt != INT && lt != UNSIGNED) {
211 			s->in.op = SCONV;
212 			s->in.left = l;
213 			s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
214 			zzzcode(s, 'U');
215 			putstr("\n\t");
216 		}
217 
218 		if (ISUNSIGNED(lt)) {
219 			s->in.op = SCONV;
220 			s->in.left = lt == UNSIGNED ? l : resc;
221 			s->in.type = rt;
222 			unsigned_to_float(s);
223 		} else {
224 			putstr("cvl");
225 			prtype(r);
226 			putchar('\t');
227 			adrput(lt == INT ? l : resc);
228 		}
229 		putstr("\n\t");
230 
231 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
232 		putchar('\t');
233 		adrput(r);
234 
235 		if (ISUNSIGNED(lt)) {
236 			putstr("\n\t");
237 			s->in.op = SCONV;
238 			s->in.left = r;		/* we need only the type */
239 			s->in.type = UNSIGNED;
240 			float_to_unsigned(s);
241 		} else {
242 			putstr("\n\tcv");
243 			prtype(r);
244 			putstr("l\t");
245 			if (lt == INT)
246 				adrput(l);
247 			else
248 				adrput(resc);
249 		}
250 		if (lt != INT) {
251 			putstr("\n\t");
252 			s->in.op = ASSIGN;
253 			s->in.left = l;
254 			s->in.right = resc;
255 			s->in.type = lt;
256 			zzzcode(s, 'U');
257 		}
258 
259 		s->in.op = FREE;
260 		return;
261 		}
262 
263 	case 'B':	/* get oreg value in temp register for shift */
264 		{
265 		register NODE *r;
266 		if (xdebug) eprint(p, 0, &val, &val);
267 		r = p->in.right;
268 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
269 			putstr("movl");
270 		else {
271 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
272 			prtype(r);
273 			putchar('l');
274 			}
275 		return;
276 		}
277 
278 	case 'C':	/* num bytes pushed on arg stack */
279 		{
280 		extern int gc_numbytes;
281 		extern int xdebug;
282 
283 		if (xdebug) printf("->%d<-",gc_numbytes);
284 
285 		printf("call%c	$%d",
286 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
287 		 gc_numbytes+4);
288 		/* dont change to double (here's the only place to catch it) */
289 		if(p->in.type == FLOAT)
290 			rtyflg = 1;
291 		return;
292 		}
293 
294 	case 'D':	/* INCR and DECR */
295 		zzzcode(p->in.left, 'U');
296 		putstr("\n	");
297 
298 	case 'E':	/* INCR and DECR, FOREFF */
299  		if (p->in.right->tn.lval == 1)
300 			{
301 			putstr(p->in.op == INCR ? "inc" : "dec");
302 			prtype(p->in.left);
303 			putchar('\t');
304 			adrput(p->in.left);
305 			return;
306 			}
307 		putstr(p->in.op == INCR ? "add" : "sub");
308 		prtype(p->in.left);
309 		putstr("2	");
310 		adrput(p->in.right);
311 		putchar(',');
312 		adrput(p->in.left);
313 		return;
314 
315 	case 'F':	/* masked constant for fields */
316 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
317 		return;
318 
319 	case 'H':	/* opcode for shift */
320 		if(p->in.op == LS || p->in.op == ASG LS)
321 			putstr("shll");
322 		else if(ISUNSIGNED(p->in.left->in.type))
323 			putstr("shrl");
324 		else
325 			putstr("shar");
326 		return;
327 
328 	case 'L':	/* type of left operand */
329 	case 'R':	/* type of right operand */
330 		{
331 		register NODE *n;
332 		extern int xdebug;
333 
334 		n = getlr ( p, c);
335 		if (xdebug) printf("->%d<-", n->in.type);
336 
337 		prtype(n);
338 		return;
339 		}
340 
341 	case 'M': {  /* initiate ediv for mod and unsigned div */
342 		register char *r;
343 		m = getlr(p, '1')->tn.rval;
344 		r = rname(m);
345 		printf("\tclrl\t%s\n\tmovl\t", r);
346 		adrput(p->in.left);
347 		printf(",%s\n", rname(m+1));
348 		if(!ISUNSIGNED(p->in.type)) { 	/* should be MOD */
349 			m = getlab();
350 			printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
351 			deflab(m);
352 		}
353 		return;
354 	}
355 
356 	case 'T': {	/* rounded structure length for arguments */
357 		int size = p->stn.stsize;
358 		SETOFF( size, 4);
359 		printf("movab	-%d(sp),sp", size);
360 		return;
361 	}
362 
363 	case 'S':  /* structure assignment */
364 		stasg(p);
365 		break;
366 
367 	case 'X':	/* multiplication for short and char */
368 		if (ISUNSIGNED(p->in.left->in.type))
369 			printf("\tmovz");
370 		else
371 			printf("\tcvt");
372 		zzzcode(p, 'L');
373 		printf("l\t");
374 		adrput(p->in.left);
375 		printf(",");
376 		adrput(&resc[0]);
377 		printf("\n");
378 		if (ISUNSIGNED(p->in.right->in.type))
379 			printf("\tmovz");
380 		else
381 			printf("\tcvt");
382 		zzzcode(p, 'R');
383 		printf("l\t");
384 		adrput(p->in.right);
385 		printf(",");
386 		adrput(&resc[1]);
387 		printf("\n");
388 		return;
389 
390 	case 'U':		/* SCONV */
391 	case 'V':		/* SCONV with FORCC */
392 		sconv(p, c == 'V');
393 		break;
394 
395 	case 'W':		/* SCONV float/double => unsigned */
396 		putstr("ld");
397 		prtype(p->in.left);
398 		putchar('\t');
399 		adrput(p->in.left);
400 		putstr("\n\t");
401 		float_to_unsigned(p);
402 		break;
403 
404 	case 'Y':		/* SCONV unsigned => float/double */
405 		unsigned_to_float(p);	/* stores into accumulator */
406 		putstr("\n\tst");
407 		prtype(p);
408 		putchar('\t');
409 		adrput(resc);
410 		break;
411 
412 	case 'Z':
413 		p = p->in.right;
414 		switch (p->in.type) {
415 		case SHORT: {
416 			short w = p->tn.lval;
417 			p->tn.lval = w;
418 			break;
419 		}
420 		case CHAR: {
421 			char c = p->tn.lval;
422 			p->tn.lval = c;
423 			break;
424 		}
425 		}
426 		printf("$%d", p->tn.lval);
427 		break;
428 
429 	default:
430 		cerror( "illegal zzzcode" );
431 	}
432 }
433 
434 #define	MOVB(dst, src, off) { \
435 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
436 	upput(dst, off); putchar('\n'); \
437 }
438 #define	MOVW(dst, src, off) { \
439 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
440 	upput(dst, off); putchar('\n'); \
441 }
442 #define	MOVL(dst, src, off) { \
443 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
444 	upput(dst, off); putchar('\n'); \
445 }
446 /*
447  * Generate code for a structure assignment.
448  */
449 stasg(p)
450 	register NODE *p;
451 {
452 	register NODE *l, *r;
453 	register int size;
454 
455 	switch (p->in.op) {
456 	case STASG:			/* regular assignment */
457 		l = p->in.left;
458 		r = p->in.right;
459 		break;
460 	case STARG:			/* place arg on the stack */
461 		l = getlr(p, '3');
462 		r = p->in.left;
463 		break;
464 	default:
465 		cerror("STASG bad");
466 		/*NOTREACHED*/
467 	}
468 	/*
469 	 * Pun source for use in code generation.
470 	 */
471 	switch (r->in.op) {
472 	case ICON:
473 		r->in.op = NAME;
474 		break;
475 	case REG:
476 		r->in.op = OREG;
477 		break;
478 	default:
479 		cerror( "STASG-r" );
480 		/*NOTREACHED*/
481 	}
482 	size = p->stn.stsize;
483 	if (size <= 0 || size > 65535)
484 		cerror("structure size out of range");
485 	/*
486 	 * Generate optimized code based on structure size
487 	 * and alignment properties....
488 	 */
489 	switch (size) {
490 
491 	case 1:
492 		putstr("\tmovb\t");
493 	optimized:
494 		adrput(r);
495 		putchar(',');
496 		adrput(l);
497 		putchar('\n');
498 		break;
499 
500 	case 2:
501 		if (p->stn.stalign != 2) {
502 			MOVB(l, r, SZCHAR);
503 			putstr("\tmovb\t");
504 		} else
505 			putstr("\tmovw\t");
506 		goto optimized;
507 
508 	case 4:
509 		if (p->stn.stalign != 4) {
510 			if (p->stn.stalign != 2) {
511 				MOVB(l, r, 3*SZCHAR);
512 				MOVB(l, r, 2*SZCHAR);
513 				MOVB(l, r, 1*SZCHAR);
514 				putstr("\tmovb\t");
515 			} else {
516 				MOVW(l, r, SZSHORT);
517 				putstr("\tmovw\t");
518 			}
519 		} else
520 			putstr("\tmovl\t");
521 		goto optimized;
522 
523 	case 6:
524 		if (p->stn.stalign != 2)
525 			goto movblk;
526 		MOVW(l, r, 2*SZSHORT);
527 		MOVW(l, r, 1*SZSHORT);
528 		putstr("\tmovw\t");
529 		goto optimized;
530 
531 	case 8:
532 		if (p->stn.stalign == 4) {
533 			MOVL(l, r, SZLONG);
534 			putstr("\tmovl\t");
535 			goto optimized;
536 		}
537 		/* fall thru...*/
538 
539 	default:
540 	movblk:
541 		/*
542 		 * Can we ever get a register conflict with R1 here?
543 		 */
544 		putstr("\tmovab\t");
545 		adrput(l);
546 		putstr(",r1\n\tmovab\t");
547 		adrput(r);
548 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
549 		rname(R2);
550 		break;
551 	}
552 	/*
553 	 * Reverse above pun for reclaim.
554 	 */
555 	if (r->in.op == NAME)
556 		r->in.op = ICON;
557 	else if (r->in.op == OREG)
558 		r->in.op = REG;
559 }
560 
561 /*
562  * Output the address of the second item in the
563  * pair pointed to by p.
564  */
565 upput(p, size)
566 	register NODE *p;
567 {
568 	CONSZ save;
569 
570 	if (p->in.op == FLD)
571 		p = p->in.left;
572 	switch (p->in.op) {
573 
574 	case NAME:
575 	case OREG:
576 		save = p->tn.lval;
577 		p->tn.lval += size/SZCHAR;
578 		adrput(p);
579 		p->tn.lval = save;
580 		break;
581 
582 	case REG:
583 		if (size == SZLONG) {
584 			putstr(rname(p->tn.rval+1));
585 			break;
586 		}
587 		/* fall thru... */
588 
589 	default:
590 		cerror("illegal upper address op %s size %d",
591 		    opst[p->tn.op], size);
592 		/*NOTREACHED*/
593 	}
594 }
595 
596 /*
597  * Convert a float or double in the accumulator into an unsigned int.
598  * Unlike the vax, the tahoe stores 0 into the destination
599  *	on a conversion of > 2 ** 31, so we compensate.
600  */
601 float_to_unsigned(p)
602 	NODE *p;
603 {
604 	register NODE *l = p->in.left;
605 	int label1 = getlab();
606 	int label2 = getlab();
607 	int label3 = getlab();
608 
609 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
610 	if (l->in.type == DOUBLE)
611 		putstr(", 0x00000000");
612 	putstr(" # .double 2147483648\n\t.text\n\tcmp");
613 	prtype(l);
614 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
615 	prtype(l);
616 	printf("\tL%d\n\tcv", label1);
617 	prtype(l);
618 	putstr("l\t");
619 	adrput(resc);
620 	putstr("\n\taddl2\t$-2147483648,");
621 	adrput(resc);
622 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
623 	prtype(l);
624 	putstr("l\t");
625 	adrput(resc);
626 	printf("\nL%d:", label3);
627 }
628 
629 /*
630  * Convert an unsigned int into a float or double, leaving the result
631  *	in the accumulator.
632  */
633 unsigned_to_float(p)
634 	register NODE *p;
635 {
636 	int label1 = getlab();
637 	int label2 = getlab();
638 
639 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
640 	if (p->in.type == DOUBLE)
641 		putstr(", 0x00000000");
642 	putstr(" # .double 4294967296\n\t.text\n\tmovl\t");
643 	adrput(p->in.left);
644 	putchar(',');
645 	adrput(resc);
646 	putstr("\n\tcvl");
647 	prtype(p);
648 	putchar('\t');
649 	adrput(resc);
650 	printf("\n\tjgeq\tL%d\n\taddd\tL%d\nL%d:", label1, label2, label1);
651 }
652 
653 /*
654  * Prlen() is a cheap prtype()...
655  */
656 static char convtab[SZINT/SZCHAR + 1] = {
657 	'?', 'b', 'w', '?', 'l'
658 };
659 #define	prlen(len)	putchar(convtab[len])
660 
661 
662 /*
663  * Generate code for integral scalar conversions.
664  * Some of this code is designed to work around a tahoe misfeature
665  *	that causes sign- and zero- extension to be defeated in
666  *	certain circumstances.
667  * Basically if the source operand of a CVT or MOVZ instruction is
668  *	shorter than the destination, and the source is a register
669  *	or an immediate constant, sign- and zero- extension are
670  *	ignored and the high bits of the source are copied.  (Note
671  *	that zero-extension is not a problem for immediate
672  *	constants.)
673  */
674 sconv(p, forcc)
675 	NODE *p;
676 	int forcc;
677 {
678 	register NODE *src, *dst;
679 	register NODE *tmp;
680 	register int srclen, dstlen;
681 	int srctype, dsttype;
682 	int val;
683 
684 	if (p->in.op == ASSIGN) {
685 		src = getlr(p, 'R');
686 		dst = getlr(p, 'L');
687 		dstlen = tlen(dst);
688 		dsttype = dst->in.type;
689 	} else /* if (p->in.op == SCONV || optype(p->in.op) == LTYPE) */ {
690 		src = getlr(p, 'L');
691 		dst = getlr(p, '1');
692 		dstlen = tlen(p);
693 		dsttype = p->in.type;
694 	}
695 
696 	if (src->in.op == REG) {
697 		srclen = SZINT/SZCHAR;
698 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
699 	} else {
700 		srclen = tlen(src);
701 		srctype = src->in.type;
702 	}
703 
704 	if (src->in.op == ICON) {
705 		if (src->tn.lval == 0) {
706 			putstr("clr");
707 			prtype(dst);
708 			putchar('\t');
709 			adrput(dst);
710 			return;
711 		}
712 		if (dstlen < srclen) {
713 			switch (dsttype) {
714 			case CHAR:
715 				src->tn.lval = (char) src->tn.lval;
716 				break;
717 			case UCHAR:
718 				src->tn.lval = (unsigned char) src->tn.lval;
719 				break;
720 			case SHORT:
721 				src->tn.lval = (short) src->tn.lval;
722 				break;
723 			case USHORT:
724 				src->tn.lval = (unsigned short) src->tn.lval;
725 				break;
726 			}
727 		}
728 		if (dst->in.op == REG) {
729 			dsttype = INT;
730 			dstlen = SZINT/SZCHAR;
731 		}
732 		srctype = dsttype;
733 		srclen = dstlen;
734 	}
735 
736 	if (srclen < dstlen) {
737 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
738 			/* (unsigned short) c; => sign extend to 16 bits */
739 			putstr("cvtbl\t");
740 			adrput(src);
741 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
742 			adrput(dst);
743 			putstr("\n\tmovab\t4(sp),sp");
744 			if (forcc) {
745 				/* inverted test */
746 				putstr("\n\tcmpl\t$0,");
747 				adrput(dst);
748 			}
749 			return;
750 		}
751 		genconv(ISUNSIGNED(srctype),
752 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
753 			src, dst);
754 		return;
755 	}
756 
757 	if (srclen > dstlen && dst->in.op == REG) {
758 		/* if dst is a register, the result must look like an int */
759 		if (src->in.op == REG) {
760 			if (ISUNSIGNED(dsttype)) {
761 				val = (1 << dstlen * SZCHAR) - 1;
762 				if (src->tn.rval == dst->tn.rval)
763 					/* conversion in place */
764 					printf("andl2\t$%#x,", val);
765 				else {
766 					printf("andl3\t$%#x,", val);
767 					adrput(src);
768 					putchar(',');
769 				}
770 				adrput(dst);
771 				return;
772 			}
773 			/*
774 			 * Sign extension in register can also be
775 			 * accomplished by shifts, but unfortunately
776 			 * shifts are extremely slow, due to the lack
777 			 * of a barrel shifter.
778 			 */
779 			putstr("pushl\t");
780 			adrput(src);
781 			putstr("\n\tcvt");
782 			prlen(dstlen);
783 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
784 			adrput(dst);
785 			putstr("\n\tmovab\t4(sp),sp");
786 			if (forcc) {
787 				/* inverted test */
788 				putstr("\n\tcmpl\t$0,");
789 				adrput(dst);
790 			}
791 			return;
792 		}
793 		tmp = talloc();
794 		if ((src->in.op == UNARY MUL &&
795 		    ((src->in.left->in.op == NAME ||
796 		     (src->in.left->in.op == ICON)))) ||
797 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
798 			/* we can increment src's address & pun it */
799 			*tmp = *src;
800 			tmp->tn.lval += srclen - dstlen;
801 		} else {
802 			/* we must store src's address */
803 			*tmp = *dst;
804 			putstr("mova");
805 			prlen(srclen);
806 			putchar('\t');
807 			adrput(src);
808 			putchar(',');
809 			adrput(tmp);
810 			putstr("\n\t");
811 			tmp->tn.op = OREG;
812 			tmp->tn.lval = srclen - dstlen;
813 		}
814 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
815 		tmp->in.op = FREE;
816 		return;
817 	}
818 
819 	genconv(ISUNSIGNED(dsttype),
820 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
821 		src, dst);
822 }
823 
824 genconv(usrc, srclen, dstlen, src, dst)
825 	int usrc;
826 	register int srclen, dstlen;
827 	NODE *src, *dst;
828 {
829 	if (srclen != dstlen) {
830 		if (usrc && srclen < dstlen)
831 			putstr("movz");
832 		else
833 			putstr("cvt");
834 		prlen(srclen);
835 	} else
836 		putstr("mov");
837 	prlen(dstlen);
838 	putchar('\t');
839 	adrput(src);
840 	putchar(',');
841 	adrput(dst);
842 }
843 
844 rmove( rt, rs, t ) TWORD t;{
845 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
846 	if(t==DOUBLE)
847 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
848 	}
849 
850 struct respref
851 respref[] = {
852 	INTAREG|INTBREG,	INTAREG|INTBREG,
853 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
854 	INTEMP,	INTEMP,
855 	FORARG,	FORARG,
856 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
857 	0,	0 };
858 
859 setregs(){ /* set up temporary registers */
860 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
861 	}
862 
863 #ifndef szty
864 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
865 	return(t==DOUBLE ? 2 : 1 );
866 	}
867 #endif
868 
869 rewfld( p ) NODE *p; {
870 	return(1);
871 	}
872 
873 callreg(p) NODE *p; {
874 	return( R0 );
875 	}
876 
877 base( p ) register NODE *p; {
878 	register int o = p->in.op;
879 
880 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
881 	if( o==REG ) return( p->tn.rval );
882     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
883 		return( p->in.left->tn.rval );
884     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
885 		return( p->tn.rval + 0200*1 );
886 	return( -1 );
887 	}
888 
889 offset( p, tyl ) register NODE *p; int tyl; {
890 
891 	if(tyl > 8) return( -1 );
892 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
893 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
894 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
895 	      && (1<<p->in.right->tn.lval)==tyl))
896 		return( p->in.left->tn.rval );
897 	return( -1 );
898 	}
899 
900 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
901 	register NODE *t;
902 	register int i;
903 	NODE *f;
904 
905 	p->in.op = OREG;
906 	f = p->in.left; 	/* have to free this subtree later */
907 
908 	/* init base */
909 	switch (q->in.op) {
910 		case ICON:
911 		case REG:
912 		case OREG:
913 			t = q;
914 			break;
915 
916 		case MINUS:
917 			q->in.right->tn.lval = -q->in.right->tn.lval;
918 		case PLUS:
919 			t = q->in.right;
920 			break;
921 
922 		case UNARY MUL:
923 			t = q->in.left->in.left;
924 			break;
925 
926 		default:
927 			cerror("illegal makeor2");
928 	}
929 
930 	p->tn.lval = t->tn.lval;
931 #ifndef FLEXNAMES
932 	for(i=0; i<NCHNAM; ++i)
933 		p->in.name[i] = t->in.name[i];
934 #else
935 	p->in.name = t->in.name;
936 #endif
937 
938 	/* init offset */
939 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
940 
941 	tfree(f);
942 	return;
943 	}
944 
945 canaddr( p ) NODE *p; {
946 	register int o = p->in.op;
947 
948 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
949 	return(0);
950 	}
951 
952 #ifndef shltype
953 shltype( o, p ) register NODE *p; {
954 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
955 	}
956 #endif
957 
958 flshape( p ) NODE *p; {
959 	register int o = p->in.op;
960 
961 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
962 	return(0);
963 	}
964 
965 shtemp( p ) register NODE *p; {
966 	if( p->in.op == STARG ) p = p->in.left;
967 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
968 	}
969 
970 shumul( p ) register NODE *p; {
971 	register int o;
972 	extern int xdebug;
973 
974 	if (xdebug) {
975 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
976 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
977 		}
978 
979 	o = p->in.op;
980 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
981 	 && p->in.type != PTR+DOUBLE)
982 		return( STARNM );
983 
984 	return( 0 );
985 	}
986 
987 special( p, shape ) register NODE *p; {
988 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
989 	else return(0);
990 }
991 
992 adrcon( val ) CONSZ val; {
993 	printf(ACONFMT, val);
994 	}
995 
996 conput( p ) register NODE *p; {
997 	switch( p->in.op ){
998 
999 	case ICON:
1000 		acon( p );
1001 		return;
1002 
1003 	case REG:
1004 		putstr(rname(p->tn.rval));
1005 		return;
1006 
1007 	default:
1008 		cerror( "illegal conput" );
1009 		}
1010 	}
1011 
1012 insput( p ) NODE *p; {
1013 	cerror( "insput" );
1014 	}
1015 
1016 adrput( p ) register NODE *p; {
1017 	register int r;
1018 	/* output an address, with offsets, from p */
1019 
1020 	if( p->in.op == FLD ){
1021 		p = p->in.left;
1022 		}
1023 	switch( p->in.op ){
1024 
1025 	case NAME:
1026 		acon( p );
1027 		return;
1028 
1029 	case ICON:
1030 		/* addressable value of the constant */
1031 		putchar('$');
1032 		acon( p );
1033 		return;
1034 
1035 	case REG:
1036 		putstr(rname(p->tn.rval));
1037 		if(p->in.type == DOUBLE)	/* for entry mask */
1038 			(void) rname(p->tn.rval+1);
1039 		return;
1040 
1041 	case OREG:
1042 		r = p->tn.rval;
1043 		if( R2TEST(r) ){ /* double indexing */
1044 			register int flags;
1045 
1046 			flags = R2UPK3(r);
1047 			if( flags & 1 ) putchar('*');
1048 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1049 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1050 			printf( "[%s]", rname(R2UPK2(r)) );
1051 			return;
1052 			}
1053 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
1054 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1055 			printf( CONFMT, p->tn.lval );
1056 			putstr( "(fp)" );
1057 			return;
1058 			}
1059 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1060 		printf( "(%s)", rname(p->tn.rval) );
1061 		return;
1062 
1063 	case UNARY MUL:
1064 		/* STARNM or STARREG found */
1065 		if( tshape(p, STARNM) ) {
1066 			putchar( '*' );
1067 			adrput( p->in.left);
1068 			}
1069 		return;
1070 
1071 	default:
1072 		cerror( "illegal address" );
1073 		return;
1074 
1075 		}
1076 
1077 	}
1078 
1079 acon( p ) register NODE *p; { /* print out a constant */
1080 
1081 	if( p->in.name[0] == '\0' ){
1082 		printf( CONFMT, p->tn.lval);
1083 		return;
1084 	} else {
1085 #ifndef FLEXNAMES
1086 		printf( "%.8s", p->in.name );
1087 #else
1088 		putstr(p->in.name);
1089 #endif
1090 		if (p->tn.lval != 0) {
1091 			putchar('+');
1092 			printf(CONFMT, p->tn.lval);
1093 		}
1094 	}
1095 	}
1096 
1097 genscall( p, cookie ) register NODE *p; {
1098 	/* structure valued call */
1099 	return( gencall( p, cookie ) );
1100 	}
1101 
1102 genfcall( p, cookie ) register NODE *p; {
1103 	register NODE *p1;
1104 	register int m;
1105 	static char *funcops[6] = {
1106 		"sin", "cos", "sqrt", "exp", "log", "atan"
1107 	};
1108 
1109 	/* generate function opcodes */
1110 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1111 	 (p1 = p->in.left)->in.op==ICON &&
1112 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1113 #ifdef FLEXNAMES
1114 		p1->in.name++;
1115 #else
1116 		strcpy(p1->in.name, p1->in.name[1]);
1117 #endif
1118 		for(m=0; m<6; m++)
1119 			if(!strcmp(p1->in.name, funcops[m]))
1120 				break;
1121 		if(m >= 6)
1122 			uerror("no opcode for fortarn function %s", p1->in.name);
1123 	} else
1124 		uerror("illegal type of fortarn function");
1125 	p1 = p->in.right;
1126 	p->in.op = FORTCALL;
1127 	if(!canaddr(p1))
1128 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1129 	m = match( p, INTAREG|INTBREG );
1130 	return(m != MDONE);
1131 }
1132 
1133 /* tbl */
1134 int gc_numbytes;
1135 /* tbl */
1136 
1137 gencall( p, cookie ) register NODE *p; {
1138 	/* generate the call given by p */
1139 	register NODE *p1, *ptemp;
1140 	register int temp, temp1;
1141 	register int m;
1142 
1143 	if( p->in.right ) temp = argsize( p->in.right );
1144 	else temp = 0;
1145 
1146 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1147 		/* set aside room for structure return */
1148 
1149 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1150 		else temp1 = temp;
1151 		}
1152 
1153 	if( temp > maxargs ) maxargs = temp;
1154 	SETOFF(temp1,4);
1155 
1156 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1157 		ptemp = talloc();
1158 		ptemp->in.op = OREG;
1159 		ptemp->tn.lval = -1;
1160 		ptemp->tn.rval = SP;
1161 #ifndef FLEXNAMES
1162 		ptemp->in.name[0] = '\0';
1163 #else
1164 		ptemp->in.name = "";
1165 #endif
1166 		ptemp->in.rall = NOPREF;
1167 		ptemp->in.su = 0;
1168 		genargs( p->in.right, ptemp );
1169 		ptemp->in.op = FREE;
1170 		}
1171 
1172 	p1 = p->in.left;
1173 	if( p1->in.op != ICON ){
1174 		if( p1->in.op != REG ){
1175 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1176 				if( p1->in.op != NAME ){
1177 					order( p1, INAREG );
1178 					}
1179 				}
1180 			}
1181 		}
1182 
1183 /* tbl
1184 	setup gc_numbytes so reference to ZC works */
1185 
1186 	gc_numbytes = temp&(0x3ff);
1187 
1188 	p->in.op = UNARY CALL;
1189 	m = match( p, INTAREG|INTBREG );
1190 
1191 	return(m != MDONE);
1192 	}
1193 
1194 /* tbl */
1195 char *
1196 ccbranches[] = {
1197 	"eql",
1198 	"neq",
1199 	"leq",
1200 	"lss",
1201 	"geq",
1202 	"gtr",
1203 	"lequ",
1204 	"lssu",
1205 	"gequ",
1206 	"gtru",
1207 	};
1208 /* tbl */
1209 
1210 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1211 
1212 		if(o != 0 && (o < EQ || o > UGT ))
1213 			cerror( "bad conditional branch: %s", opst[o] );
1214 		printf( "	j%s	L%d\n",
1215 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
1216 	}
1217 
1218 nextcook( p, cookie ) NODE *p; {
1219 	/* we have failed to match p with cookie; try another */
1220 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1221 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1222 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1223 	return( FORREW );
1224 	}
1225 
1226 lastchance( p, cook ) NODE *p; {
1227 	/* forget it! */
1228 	return(0);
1229 	}
1230 
1231 optim2( p ) register NODE *p; {
1232 # ifdef ONEPASS
1233 	/* do local tree transformations and optimizations */
1234 # define RV(p) p->in.right->tn.lval
1235 # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
1236 	register int o, i;
1237 	register NODE *l, *r;
1238 
1239 	switch (o = p->in.op) {
1240 
1241 	case DIV: case ASG DIV:
1242 	case MOD: case ASG MOD:
1243 		/*
1244 		 * Change unsigned mods and divs to
1245 		 * logicals (mul is done in mip & c2)
1246 		 */
1247 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1248 		    (i = ispow2(RV(p))) >= 0) {
1249 			if (o == DIV || o == ASG DIV) {
1250 				p->in.op = RS;
1251 				RV(p) = i;
1252 			} else {
1253 				p->in.op = AND;
1254 				RV(p)--;
1255 			}
1256 			if (asgop(o))
1257 				p->in.op = ASG p->in.op;
1258 		}
1259 		return;
1260 
1261 	case SCONV:
1262 		l = p->in.left;
1263 		/* clobber conversions w/o side effects */
1264 		if (!anyfloat(p, l) && l->in.op != PCONV &&
1265 		    tlen(p) == tlen(l)) {
1266 			if (l->in.op != FLD)
1267 				l->in.type = p->in.type;
1268 			ncopy(p, l);
1269 			l->in.op = FREE;
1270 		}
1271 		return;
1272 
1273 	case ASSIGN:
1274 		/*
1275 		 * Try to zap storage conversions of non-float items.
1276 		 */
1277 		r = p->in.right;
1278 		if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
1279 			int wdest, wconv, wsrc;
1280 			wdest = tlen(p->in.left);
1281 			wconv = tlen(r);
1282 			/*
1283 			 * If size doesn't change across assignment or
1284 			 * conversion expands src before shrinking again
1285 			 * due to the assignment, delete conversion so
1286 			 * code generator can create optimal code.
1287 			 */
1288 			if (wdest == wconv ||
1289 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1290 				p->in.right = r->in.left;
1291 				r->in.op = FREE;
1292 			}
1293 		}
1294 		return;
1295 	}
1296 # endif
1297 }
1298 
1299 struct functbl {
1300 	int fop;
1301 	TWORD ftype;
1302 	char *func;
1303 	} opfunc[] = {
1304 	DIV,		TANY,	"udiv",
1305 	MOD,		TANY,	"urem",
1306 	ASG DIV,	TANY,	"audiv",
1307 	ASG MOD,	TANY,	"aurem",
1308 	0,	0,	0 };
1309 
1310 hardops(p)  register NODE *p; {
1311 	/* change hard to do operators into function calls.  */
1312 	register NODE *q;
1313 	register struct functbl *f;
1314 	register o;
1315 	NODE *old,*temp;
1316 
1317 	o = p->in.op;
1318 	if( ! (optype(o)==BITYPE &&
1319 	       (ISUNSIGNED(p->in.left->in.type) ||
1320 		ISUNSIGNED(p->in.right->in.type))) )
1321 		return;
1322 
1323 	for( f=opfunc; f->fop; f++ ) {
1324 		if( o==f->fop ) goto convert;
1325 		}
1326 	return;
1327 
1328 	convert:
1329 	if( asgop( o ) ) {
1330 		old = NIL;
1331 		switch( p->in.left->in.op ){
1332 		case FLD:
1333 			q = p->in.left->in.left;
1334 			/*
1335 			 * rewrite (lval.fld /= rval); as
1336 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1337 			 * else the compiler will evaluate lval twice.
1338 			 */
1339 			if( q->in.op == UNARY MUL ){
1340 				/* first allocate a temp storage */
1341 				temp = talloc();
1342 				temp->in.op = OREG;
1343 				temp->tn.rval = TMPREG;
1344 				temp->tn.lval = BITOOR(freetemp(1));
1345 				temp->in.type = INCREF(p->in.type);
1346 #ifdef FLEXNAMES
1347 				temp->in.name = "";
1348 #else
1349 				temp->in.name[0] = '\0';
1350 #endif
1351 				old = q->in.left;
1352 				q->in.left = temp;
1353 			}
1354 			/* fall thru ... */
1355 
1356 		case REG:
1357 		case NAME:
1358 		case OREG:
1359 			/* change ASG OP to a simple OP */
1360 			q = talloc();
1361 			q->in.op = NOASG p->in.op;
1362 			q->in.rall = NOPREF;
1363 			q->in.type = p->in.type;
1364 			q->in.left = tcopy(p->in.left);
1365 			q->in.right = p->in.right;
1366 			p->in.op = ASSIGN;
1367 			p->in.right = q;
1368 			p = q;
1369 			f -= 2; /* Note: this depends on the table order */
1370 			/* on the right side only - replace *temp with
1371 			 *(temp = &lval), build the assignment node */
1372 			if( old ){
1373 				temp = q->in.left->in.left; /* the "*" node */
1374 				q = talloc();
1375 				q->in.op = ASSIGN;
1376 				q->in.left = temp->in.left;
1377 				q->in.right = old;
1378 				q->in.type = old->in.type;
1379 #ifdef FLEXNAMES
1380 				q->in.name = "";
1381 #else
1382 				q->in.name[0] = '\0';
1383 #endif
1384 				temp->in.left = q;
1385 			}
1386 			break;
1387 
1388 		case UNARY MUL:
1389 			/* avoid doing side effects twice */
1390 			q = p->in.left;
1391 			p->in.left = q->in.left;
1392 			q->in.op = FREE;
1393 			break;
1394 
1395 		default:
1396 			cerror( "hardops: can't compute & LHS" );
1397 			}
1398 		}
1399 
1400 	/* build comma op for args to function */
1401 	q = talloc();
1402 	q->in.op = CM;
1403 	q->in.rall = NOPREF;
1404 	q->in.type = INT;
1405 	q->in.left = p->in.left;
1406 	q->in.right = p->in.right;
1407 	p->in.op = CALL;
1408 	p->in.right = q;
1409 
1410 	/* put function name in left node of call */
1411 	p->in.left = q = talloc();
1412 	q->in.op = ICON;
1413 	q->in.rall = NOPREF;
1414 	q->in.type = INCREF( FTN + p->in.type );
1415 #ifndef FLEXNAMES
1416 	strcpy( q->in.name, f->func );
1417 #else
1418 	q->in.name = f->func;
1419 #endif
1420 	q->tn.lval = 0;
1421 	q->tn.rval = 0;
1422 
1423 	}
1424 
1425 zappost(p) NODE *p; {
1426 	/* look for ++ and -- operators and remove them */
1427 
1428 	register int o, ty;
1429 	register NODE *q;
1430 	o = p->in.op;
1431 	ty = optype( o );
1432 
1433 	switch( o ){
1434 
1435 	case INCR:
1436 	case DECR:
1437 			q = p->in.left;
1438 			p->in.right->in.op = FREE;  /* zap constant */
1439 			ncopy( p, q );
1440 			q->in.op = FREE;
1441 			return;
1442 
1443 		}
1444 
1445 	if( ty == BITYPE ) zappost( p->in.right );
1446 	if( ty != LTYPE ) zappost( p->in.left );
1447 }
1448 
1449 fixpre(p) NODE *p; {
1450 
1451 	register int o, ty;
1452 	o = p->in.op;
1453 	ty = optype( o );
1454 
1455 	switch( o ){
1456 
1457 	case ASG PLUS:
1458 			p->in.op = PLUS;
1459 			break;
1460 	case ASG MINUS:
1461 			p->in.op = MINUS;
1462 			break;
1463 		}
1464 
1465 	if( ty == BITYPE ) fixpre( p->in.right );
1466 	if( ty != LTYPE ) fixpre( p->in.left );
1467 }
1468 
1469 NODE * addroreg(l) NODE *l;
1470 				/* OREG was built in clocal()
1471 				 * for an auto or formal parameter
1472 				 * now its address is being taken
1473 				 * local code must unwind it
1474 				 * back to PLUS/MINUS REG ICON
1475 				 * according to local conventions
1476 				 */
1477 {
1478 	cerror("address of OREG taken");
1479 }
1480 
1481 # ifndef ONEPASS
1482 main( argc, argv ) char *argv[]; {
1483 	return( mainp2( argc, argv ) );
1484 	}
1485 # endif
1486 
1487 strip(p) register NODE *p; {
1488 	NODE *q;
1489 
1490 	/* strip nodes off the top when no side effects occur */
1491 	for( ; ; ) {
1492 		switch( p->in.op ) {
1493 		case SCONV:			/* remove lint tidbits */
1494 			q = p->in.left;
1495 			ncopy( p, q );
1496 			q->in.op = FREE;
1497 			break;
1498 		/* could probably add a few more here */
1499 		default:
1500 			return;
1501 			}
1502 		}
1503 	}
1504 
1505 myreader(p) register NODE *p; {
1506 	strip( p );		/* strip off operations with no side effects */
1507 	walkf( p, hardops );	/* convert ops to function calls */
1508 	canon( p );		/* expands r-vals for fileds */
1509 	walkf( p, optim2 );
1510 	}
1511