xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32874)
1 #ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.12 (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 'A':	/* assignment and load (integer only) */
200 		{
201 		register NODE *l, *r;
202 
203 		if (xdebug) eprint(p, 0, &val, &val);
204 		r = getlr(p, 'R');
205 		if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) {
206 			l = resc;
207 			l->in.type = INT;
208 		} else
209 			l = getlr(p, 'L');
210 		if(r->in.type==FLOAT || r->in.type==DOUBLE
211 		 || l->in.type==FLOAT || l->in.type==DOUBLE)
212 			cerror("float in ZA");
213 		if (r->in.op == ICON)
214 			if(r->in.name[0] == '\0') {
215 				if (r->tn.lval == 0) {
216 					putstr("clr");
217 					prtype(l);
218 					putchar('\t');
219 					adrput(l);
220 					return;
221 				}
222 				if (r->tn.lval < 0 && r->tn.lval >= -63) {
223 					putstr("mneg");
224 					prtype(l);
225 					r->tn.lval = -r->tn.lval;
226 					goto ops;
227 				}
228 #ifdef MOVAFASTER
229 			} else {
230 				putstr("movab\t");
231 				acon(r);
232 				putchar(',');
233 				adrput(l);
234 				return;
235 #endif MOVAFASTER
236 			}
237 
238 		if (l->in.op == REG) {
239 			if( tlen(l) < tlen(r) ) {
240 				putstr(!ISUNSIGNED(l->in.type)?
241 					"cvt": "movz");
242 				prtype(l);
243 				putchar('l');
244 				goto ops;
245 			} else
246 				l->in.type = INT;
247 		}
248 		if (tlen(l) == tlen(r)) {
249 			putstr("mov");
250 			prtype(l);
251 			goto ops;
252 		} else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
253 			putstr("movz");
254 		else
255 			putstr("cvt");
256 		prtype(r);
257 		prtype(l);
258 	ops:
259 		putchar('\t');
260 		adrput(r);
261 		putchar(',');
262 		adrput(l);
263 		return;
264 		}
265 
266 	case 'B':	/* get oreg value in temp register for shift */
267 		{
268 		register NODE *r;
269 		if (xdebug) eprint(p, 0, &val, &val);
270 		r = p->in.right;
271 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
272 			putstr("movl");
273 		else {
274 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
275 			prtype(r);
276 			putchar('l');
277 			}
278 		return;
279 		}
280 
281 	case 'C':	/* num bytes pushed on arg stack */
282 		{
283 		extern int gc_numbytes;
284 		extern int xdebug;
285 
286 		if (xdebug) printf("->%d<-",gc_numbytes);
287 
288 		printf("call%c	$%d",
289 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
290 		 gc_numbytes+4);
291 		/* dont change to double (here's the only place to catch it) */
292 		if(p->in.type == FLOAT)
293 			rtyflg = 1;
294 		return;
295 		}
296 
297 	case 'D':	/* INCR and DECR */
298 		zzzcode(p->in.left, 'A');
299 		putstr("\n	");
300 
301 	case 'E':	/* INCR and DECR, FOREFF */
302  		if (p->in.right->tn.lval == 1)
303 			{
304 			putstr(p->in.op == INCR ? "inc" : "dec");
305 			prtype(p->in.left);
306 			putchar('\t');
307 			adrput(p->in.left);
308 			return;
309 			}
310 		putstr(p->in.op == INCR ? "add" : "sub");
311 		prtype(p->in.left);
312 		putstr("2	");
313 		adrput(p->in.right);
314 		putchar(',');
315 		adrput(p->in.left);
316 		return;
317 
318 	case 'F':	/* masked constant for fields */
319 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
320 		return;
321 
322 	case 'H':	/* opcode for shift */
323 		if(p->in.op == LS || p->in.op == ASG LS)
324 			putstr("shll");
325 		else if(ISUNSIGNED(p->in.left->in.type))
326 			putstr("shrl");
327 		else
328 			putstr("shar");
329 		return;
330 
331 	case 'L':	/* type of left operand */
332 	case 'R':	/* type of right operand */
333 		{
334 		register NODE *n;
335 		extern int xdebug;
336 
337 		n = getlr ( p, c);
338 		if (xdebug) printf("->%d<-", n->in.type);
339 
340 		prtype(n);
341 		return;
342 		}
343 
344 	case 'M': {  /* initiate ediv for mod and unsigned div */
345 		register char *r;
346 		m = getlr(p, '1')->tn.rval;
347 		r = rname(m);
348 		printf("\tclrl\t%s\n\tmovl\t", r);
349 		adrput(p->in.left);
350 		printf(",%s\n", rname(m+1));
351 		if(!ISUNSIGNED(p->in.type)) { 	/* should be MOD */
352 			m = getlab();
353 			printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
354 			deflab(m);
355 		}
356 		return;
357 	}
358 
359 	case 'T': {	/* rounded structure length for arguments */
360 		int size = p->stn.stsize;
361 		SETOFF( size, 4);
362 		printf("movab	-%d(sp),sp", size);
363 		return;
364 	}
365 
366 	case 'S':  /* structure assignment */
367 		stasg(p);
368 		break;
369 
370 	case 'X':	/* multiplication for short and char */
371 		if (ISUNSIGNED(p->in.left->in.type))
372 			printf("\tmovz");
373 		else
374 			printf("\tcvt");
375 		zzzcode(p, 'L');
376 		printf("l\t");
377 		adrput(p->in.left);
378 		printf(",");
379 		adrput(&resc[0]);
380 		printf("\n");
381 		if (ISUNSIGNED(p->in.right->in.type))
382 			printf("\tmovz");
383 		else
384 			printf("\tcvt");
385 		zzzcode(p, 'R');
386 		printf("l\t");
387 		adrput(p->in.right);
388 		printf(",");
389 		adrput(&resc[1]);
390 		printf("\n");
391 		return;
392 
393 	case 'U':		/* SCONV */
394 	case 'V':		/* SCONV with FORCC */
395 		sconv(p, c == 'V');
396 		break;
397 
398 	case 'Z':
399 		p = p->in.right;
400 		switch (p->in.type) {
401 		case SHORT: {
402 			short w = p->tn.lval;
403 			p->tn.lval = w;
404 			break;
405 		}
406 		case CHAR: {
407 			char c = p->tn.lval;
408 			p->tn.lval = c;
409 			break;
410 		}
411 		}
412 		printf("$%d", p->tn.lval);
413 		break;
414 
415 	default:
416 		cerror( "illegal zzzcode" );
417 	}
418 }
419 
420 #define	MOVB(dst, src, off) { \
421 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
422 	upput(dst, off); putchar('\n'); \
423 }
424 #define	MOVW(dst, src, off) { \
425 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
426 	upput(dst, off); putchar('\n'); \
427 }
428 #define	MOVL(dst, src, off) { \
429 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
430 	upput(dst, off); putchar('\n'); \
431 }
432 /*
433  * Generate code for a structure assignment.
434  */
435 stasg(p)
436 	register NODE *p;
437 {
438 	register NODE *l, *r;
439 	register int size;
440 
441 	switch (p->in.op) {
442 	case STASG:			/* regular assignment */
443 		l = p->in.left;
444 		r = p->in.right;
445 		break;
446 	case STARG:			/* place arg on the stack */
447 		l = getlr(p, '3');
448 		r = p->in.left;
449 		break;
450 	default:
451 		cerror("STASG bad");
452 		/*NOTREACHED*/
453 	}
454 	/*
455 	 * Pun source for use in code generation.
456 	 */
457 	switch (r->in.op) {
458 	case ICON:
459 		r->in.op = NAME;
460 		break;
461 	case REG:
462 		r->in.op = OREG;
463 		break;
464 	default:
465 		cerror( "STASG-r" );
466 		/*NOTREACHED*/
467 	}
468 	size = p->stn.stsize;
469 	if (size <= 0 || size > 65535)
470 		cerror("structure size out of range");
471 	/*
472 	 * Generate optimized code based on structure size
473 	 * and alignment properties....
474 	 */
475 	switch (size) {
476 
477 	case 1:
478 		putstr("\tmovb\t");
479 	optimized:
480 		adrput(r);
481 		putchar(',');
482 		adrput(l);
483 		putchar('\n');
484 		break;
485 
486 	case 2:
487 		if (p->stn.stalign != 2) {
488 			MOVB(l, r, SZCHAR);
489 			putstr("\tmovb\t");
490 		} else
491 			putstr("\tmovw\t");
492 		goto optimized;
493 
494 	case 4:
495 		if (p->stn.stalign != 4) {
496 			if (p->stn.stalign != 2) {
497 				MOVB(l, r, 3*SZCHAR);
498 				MOVB(l, r, 2*SZCHAR);
499 				MOVB(l, r, 1*SZCHAR);
500 				putstr("\tmovb\t");
501 			} else {
502 				MOVW(l, r, SZSHORT);
503 				putstr("\tmovw\t");
504 			}
505 		} else
506 			putstr("\tmovl\t");
507 		goto optimized;
508 
509 	case 6:
510 		if (p->stn.stalign != 2)
511 			goto movblk;
512 		MOVW(l, r, 2*SZSHORT);
513 		MOVW(l, r, 1*SZSHORT);
514 		putstr("\tmovw\t");
515 		goto optimized;
516 
517 	case 8:
518 		if (p->stn.stalign == 4) {
519 			MOVL(l, r, SZLONG);
520 			putstr("\tmovl\t");
521 			goto optimized;
522 		}
523 		/* fall thru...*/
524 
525 	default:
526 	movblk:
527 		/*
528 		 * Can we ever get a register conflict with R1 here?
529 		 */
530 		putstr("\tmovab\t");
531 		adrput(l);
532 		putstr(",r1\n\tmovab\t");
533 		adrput(r);
534 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
535 		rname(R2);
536 		break;
537 	}
538 	/*
539 	 * Reverse above pun for reclaim.
540 	 */
541 	if (r->in.op == NAME)
542 		r->in.op = ICON;
543 	else if (r->in.op == OREG)
544 		r->in.op = REG;
545 }
546 
547 /*
548  * Output the address of the second item in the
549  * pair pointed to by p.
550  */
551 upput(p, size)
552 	register NODE *p;
553 {
554 	CONSZ save;
555 
556 	if (p->in.op == FLD)
557 		p = p->in.left;
558 	switch (p->in.op) {
559 
560 	case NAME:
561 	case OREG:
562 		save = p->tn.lval;
563 		p->tn.lval += size/SZCHAR;
564 		adrput(p);
565 		p->tn.lval = save;
566 		break;
567 
568 	case REG:
569 		if (size == SZLONG) {
570 			putstr(rname(p->tn.rval+1));
571 			break;
572 		}
573 		/* fall thru... */
574 
575 	default:
576 		cerror("illegal upper address op %s size %d",
577 		    opst[p->tn.op], size);
578 		/*NOTREACHED*/
579 	}
580 }
581 
582 /*
583  * Generate code for integral scalar conversions.
584  * Many work-arounds for brain-damaged Tahoe register behavior.
585  */
586 sconv(p, forcc)
587 	NODE *p;
588 	int forcc;
589 {
590 	register NODE *src, *dst;
591 	register NODE *tmp;
592 	register int srclen, dstlen;
593 	int srctype, dsttype;
594 	int val;
595 
596 	if (p->in.op == ASSIGN) {
597 		src = getlr(p, 'R');
598 		dst = getlr(p, 'L');
599 		dstlen = tlen(dst);
600 		dsttype = dst->in.type;
601 	} else /* if (p->in.op == SCONV || optype(p->in.op) == LTYPE) */ {
602 		src = getlr(p, 'L');
603 		dst = getlr(p, '1');
604 		dstlen = tlen(p);
605 		dsttype = p->in.type;
606 	}
607 
608 	srclen = tlen(src);
609 	srctype = src->in.op == REG ?
610 		ISUNSIGNED(src->in.type) ? UNSIGNED : INT :
611 		src->in.type;
612 
613 	if (srclen < dstlen) {
614 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
615 			/* (unsigned short) c; => sign extend to 16 bits */
616 			putstr("cvtbl\t");
617 			adrput(src);
618 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
619 			adrput(dst);
620 			putstr("\n\tmovab\t4(sp),sp");
621 			if (forcc) {
622 				/* inverted test */
623 				putstr("\n\tcmpl\t$0,");
624 				adrput(dst);
625 			}
626 			return;
627 		}
628 		genconv(ISUNSIGNED(srctype),
629 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
630 			src, dst);
631 		return;
632 	}
633 
634 	if (srclen > dstlen && dst->in.op == REG) {
635 		if (src->in.op == REG) {
636 			if (ISUNSIGNED(dsttype)) {
637 				val = (1 << dstlen * SZCHAR) - 1;
638 				if (src->tn.rval == dst->tn.rval)
639 					/* conversion in place */
640 					printf("andl2\t$%#x,", val);
641 				else {
642 					printf("andl3\t$%#x,", val);
643 					adrput(src);
644 					putchar(',');
645 				}
646 				adrput(dst);
647 				return;
648 			}
649 			val = SZINT - srclen * SZCHAR;
650 			printf("shll\t$%d,", val);
651 			adrput(src);
652 			putchar(',');
653 			adrput(dst);
654 			printf("\n\tshar\t$%d,", val);
655 			adrput(dst);
656 			putchar(',');
657 			adrput(dst);
658 			return;
659 		}
660 		tmp = talloc();
661 		if ((src->in.op == UNARY MUL &&
662 		    ((src->in.left->in.op == NAME ||
663 		     (src->in.left->in.op == ICON)))) ||
664 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
665 			/* we can increment src's address & pun it */
666 			*tmp = *src;
667 			tmp->tn.lval += srclen - dstlen;
668 		} else {
669 			/* we must store src's address */
670 			*tmp = *dst;
671 			putstr("movab\t");
672 			adrput(src);
673 			putchar(',');
674 			adrput(tmp);
675 			putstr("\n\t");
676 			tmp->tn.op = OREG;
677 			tmp->tn.lval = srclen - dstlen;
678 		}
679 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
680 		tmp->in.op = FREE;
681 		return;
682 	}
683 
684 	genconv(ISUNSIGNED(dsttype),
685 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
686 		src, dst);
687 }
688 
689 genconv(usrc, srclen, dstlen, src, dst)
690 	int usrc, srclen, dstlen;
691 	NODE *src, *dst;
692 {
693 	static char convtab[SZINT/SZCHAR + 1] = {
694 		'?', 'b', 'w', '?', 'l'
695 	};
696 
697 	if (srclen != dstlen) {
698 		if (usrc && srclen < dstlen)
699 			putstr("movz");
700 		else
701 			putstr("cvt");
702 		putchar(convtab[srclen]);
703 	} else
704 		putstr("mov");
705 	putchar(convtab[dstlen]);
706 	putchar('\t');
707 	adrput(src);
708 	putchar(',');
709 	adrput(dst);
710 }
711 
712 rmove( rt, rs, t ) TWORD t;{
713 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
714 	if(t==DOUBLE)
715 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
716 	}
717 
718 struct respref
719 respref[] = {
720 	INTAREG|INTBREG,	INTAREG|INTBREG,
721 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
722 	INTEMP,	INTEMP,
723 	FORARG,	FORARG,
724 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
725 	0,	0 };
726 
727 setregs(){ /* set up temporary registers */
728 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
729 	}
730 
731 #ifndef szty
732 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
733 	return(t==DOUBLE ? 2 : 1 );
734 	}
735 #endif
736 
737 rewfld( p ) NODE *p; {
738 	return(1);
739 	}
740 
741 callreg(p) NODE *p; {
742 	return( R0 );
743 	}
744 
745 base( p ) register NODE *p; {
746 	register int o = p->in.op;
747 
748 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
749 	if( o==REG ) return( p->tn.rval );
750     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
751 		return( p->in.left->tn.rval );
752     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
753 		return( p->tn.rval + 0200*1 );
754 	return( -1 );
755 	}
756 
757 offset( p, tyl ) register NODE *p; int tyl; {
758 
759 	if(tyl > 8) return( -1 );
760 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
761 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
762 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
763 	      && (1<<p->in.right->tn.lval)==tyl))
764 		return( p->in.left->tn.rval );
765 	return( -1 );
766 	}
767 
768 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
769 	register NODE *t;
770 	register int i;
771 	NODE *f;
772 
773 	p->in.op = OREG;
774 	f = p->in.left; 	/* have to free this subtree later */
775 
776 	/* init base */
777 	switch (q->in.op) {
778 		case ICON:
779 		case REG:
780 		case OREG:
781 			t = q;
782 			break;
783 
784 		case MINUS:
785 			q->in.right->tn.lval = -q->in.right->tn.lval;
786 		case PLUS:
787 			t = q->in.right;
788 			break;
789 
790 		case UNARY MUL:
791 			t = q->in.left->in.left;
792 			break;
793 
794 		default:
795 			cerror("illegal makeor2");
796 	}
797 
798 	p->tn.lval = t->tn.lval;
799 #ifndef FLEXNAMES
800 	for(i=0; i<NCHNAM; ++i)
801 		p->in.name[i] = t->in.name[i];
802 #else
803 	p->in.name = t->in.name;
804 #endif
805 
806 	/* init offset */
807 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
808 
809 	tfree(f);
810 	return;
811 	}
812 
813 canaddr( p ) NODE *p; {
814 	register int o = p->in.op;
815 
816 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
817 	return(0);
818 	}
819 
820 #ifndef shltype
821 shltype( o, p ) register NODE *p; {
822 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
823 	}
824 #endif
825 
826 flshape( p ) NODE *p; {
827 	register int o = p->in.op;
828 
829 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
830 	return(0);
831 	}
832 
833 shtemp( p ) register NODE *p; {
834 	if( p->in.op == STARG ) p = p->in.left;
835 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
836 	}
837 
838 shumul( p ) register NODE *p; {
839 	register int o;
840 	extern int xdebug;
841 
842 	if (xdebug) {
843 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
844 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
845 		}
846 
847 	o = p->in.op;
848 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
849 	 && p->in.type != PTR+DOUBLE)
850 		return( STARNM );
851 
852 	return( 0 );
853 	}
854 
855 special( p, shape ) register NODE *p; {
856 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
857 	else return(0);
858 }
859 
860 adrcon( val ) CONSZ val; {
861 	printf(ACONFMT, val);
862 	}
863 
864 conput( p ) register NODE *p; {
865 	switch( p->in.op ){
866 
867 	case ICON:
868 		acon( p );
869 		return;
870 
871 	case REG:
872 		putstr(rname(p->tn.rval));
873 		return;
874 
875 	default:
876 		cerror( "illegal conput" );
877 		}
878 	}
879 
880 insput( p ) NODE *p; {
881 	cerror( "insput" );
882 	}
883 
884 adrput( p ) register NODE *p; {
885 	register int r;
886 	/* output an address, with offsets, from p */
887 
888 	if( p->in.op == FLD ){
889 		p = p->in.left;
890 		}
891 	switch( p->in.op ){
892 
893 	case NAME:
894 		acon( p );
895 		return;
896 
897 	case ICON:
898 		/* addressable value of the constant */
899 		putchar('$');
900 		acon( p );
901 		return;
902 
903 	case REG:
904 		putstr(rname(p->tn.rval));
905 		if(p->in.type == DOUBLE)	/* for entry mask */
906 			(void) rname(p->tn.rval+1);
907 		return;
908 
909 	case OREG:
910 		r = p->tn.rval;
911 		if( R2TEST(r) ){ /* double indexing */
912 			register int flags;
913 
914 			flags = R2UPK3(r);
915 			if( flags & 1 ) putchar('*');
916 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
917 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
918 			printf( "[%s]", rname(R2UPK2(r)) );
919 			return;
920 			}
921 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
922 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
923 			printf( CONFMT, p->tn.lval );
924 			putstr( "(fp)" );
925 			return;
926 			}
927 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
928 		printf( "(%s)", rname(p->tn.rval) );
929 		return;
930 
931 	case UNARY MUL:
932 		/* STARNM or STARREG found */
933 		if( tshape(p, STARNM) ) {
934 			putchar( '*' );
935 			adrput( p->in.left);
936 			}
937 		return;
938 
939 	default:
940 		cerror( "illegal address" );
941 		return;
942 
943 		}
944 
945 	}
946 
947 acon( p ) register NODE *p; { /* print out a constant */
948 
949 	if( p->in.name[0] == '\0' ){
950 		printf( CONFMT, p->tn.lval);
951 		return;
952 	} else {
953 #ifndef FLEXNAMES
954 		printf( "%.8s", p->in.name );
955 #else
956 		putstr(p->in.name);
957 #endif
958 		if (p->tn.lval != 0) {
959 			putchar('+');
960 			printf(CONFMT, p->tn.lval);
961 		}
962 	}
963 	}
964 
965 genscall( p, cookie ) register NODE *p; {
966 	/* structure valued call */
967 	return( gencall( p, cookie ) );
968 	}
969 
970 genfcall( p, cookie ) register NODE *p; {
971 	register NODE *p1;
972 	register int m;
973 	static char *funcops[6] = {
974 		"sin", "cos", "sqrt", "exp", "log", "atan"
975 	};
976 
977 	/* generate function opcodes */
978 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
979 	 (p1 = p->in.left)->in.op==ICON &&
980 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
981 #ifdef FLEXNAMES
982 		p1->in.name++;
983 #else
984 		strcpy(p1->in.name, p1->in.name[1]);
985 #endif
986 		for(m=0; m<6; m++)
987 			if(!strcmp(p1->in.name, funcops[m]))
988 				break;
989 		if(m >= 6)
990 			uerror("no opcode for fortarn function %s", p1->in.name);
991 	} else
992 		uerror("illegal type of fortarn function");
993 	p1 = p->in.right;
994 	p->in.op = FORTCALL;
995 	if(!canaddr(p1))
996 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
997 	m = match( p, INTAREG|INTBREG );
998 	return(m != MDONE);
999 }
1000 
1001 /* tbl */
1002 int gc_numbytes;
1003 /* tbl */
1004 
1005 gencall( p, cookie ) register NODE *p; {
1006 	/* generate the call given by p */
1007 	register NODE *p1, *ptemp;
1008 	register int temp, temp1;
1009 	register int m;
1010 
1011 	if( p->in.right ) temp = argsize( p->in.right );
1012 	else temp = 0;
1013 
1014 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1015 		/* set aside room for structure return */
1016 
1017 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1018 		else temp1 = temp;
1019 		}
1020 
1021 	if( temp > maxargs ) maxargs = temp;
1022 	SETOFF(temp1,4);
1023 
1024 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1025 		ptemp = talloc();
1026 		ptemp->in.op = OREG;
1027 		ptemp->tn.lval = -1;
1028 		ptemp->tn.rval = SP;
1029 #ifndef FLEXNAMES
1030 		ptemp->in.name[0] = '\0';
1031 #else
1032 		ptemp->in.name = "";
1033 #endif
1034 		ptemp->in.rall = NOPREF;
1035 		ptemp->in.su = 0;
1036 		genargs( p->in.right, ptemp );
1037 		ptemp->in.op = FREE;
1038 		}
1039 
1040 	p1 = p->in.left;
1041 	if( p1->in.op != ICON ){
1042 		if( p1->in.op != REG ){
1043 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1044 				if( p1->in.op != NAME ){
1045 					order( p1, INAREG );
1046 					}
1047 				}
1048 			}
1049 		}
1050 
1051 /* tbl
1052 	setup gc_numbytes so reference to ZC works */
1053 
1054 	gc_numbytes = temp&(0x3ff);
1055 
1056 	p->in.op = UNARY CALL;
1057 	m = match( p, INTAREG|INTBREG );
1058 
1059 	return(m != MDONE);
1060 	}
1061 
1062 /* tbl */
1063 char *
1064 ccbranches[] = {
1065 	"eql",
1066 	"neq",
1067 	"leq",
1068 	"lss",
1069 	"geq",
1070 	"gtr",
1071 	"lequ",
1072 	"lssu",
1073 	"gequ",
1074 	"gtru",
1075 	};
1076 /* tbl */
1077 
1078 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1079 
1080 		if(o != 0 && (o < EQ || o > UGT ))
1081 			cerror( "bad conditional branch: %s", opst[o] );
1082 		printf( "	j%s	L%d\n",
1083 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
1084 	}
1085 
1086 nextcook( p, cookie ) NODE *p; {
1087 	/* we have failed to match p with cookie; try another */
1088 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1089 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1090 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1091 	return( FORREW );
1092 	}
1093 
1094 lastchance( p, cook ) NODE *p; {
1095 	/* forget it! */
1096 	return(0);
1097 	}
1098 
1099 optim2( p ) register NODE *p; {
1100 # ifdef ONEPASS
1101 	/* do local tree transformations and optimizations */
1102 # define RV(p) p->in.right->tn.lval
1103 # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
1104 	register int o, i;
1105 	register NODE *l, *r;
1106 
1107 	switch (o = p->in.op) {
1108 
1109 	case DIV: case ASG DIV:
1110 	case MOD: case ASG MOD:
1111 		/*
1112 		 * Change unsigned mods and divs to
1113 		 * logicals (mul is done in mip & c2)
1114 		 */
1115 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1116 		    (i = ispow2(RV(p))) >= 0) {
1117 			if (o == DIV || o == ASG DIV) {
1118 				p->in.op = RS;
1119 				RV(p) = i;
1120 			} else {
1121 				p->in.op = AND;
1122 				RV(p)--;
1123 			}
1124 			if (asgop(o))
1125 				p->in.op = ASG p->in.op;
1126 		}
1127 		return;
1128 
1129 	case SCONV:
1130 		l = p->in.left;
1131 		/* clobber conversions w/o side effects */
1132 		if (!anyfloat(p, l) && l->in.op != PCONV &&
1133 		    tlen(p) == tlen(l)) {
1134 			if (l->in.op != FLD)
1135 				l->in.type = p->in.type;
1136 			ncopy(p, l);
1137 			l->in.op = FREE;
1138 		}
1139 		return;
1140 
1141 	case ASSIGN:
1142 		/*
1143 		 * Try to zap storage conversions of non-float items.
1144 		 */
1145 		r = p->in.right;
1146 		if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
1147 			int wdest, wconv, wsrc;
1148 			wdest = tlen(p->in.left);
1149 			wconv = tlen(r);
1150 			/*
1151 			 * If size doesn't change across assignment or
1152 			 * conversion expands src before shrinking again
1153 			 * due to the assignment, delete conversion so
1154 			 * code generator can create optimal code.
1155 			 */
1156 			if (wdest == wconv ||
1157 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1158 				p->in.right = r->in.left;
1159 				r->in.op = FREE;
1160 			}
1161 		}
1162 		return;
1163 	}
1164 # endif
1165 }
1166 
1167 struct functbl {
1168 	int fop;
1169 	char *func;
1170 } opfunc[] = {
1171 	DIV,		"udiv",
1172 	ASG DIV,	"udiv",
1173 	0
1174 };
1175 
1176 hardops(p)  register NODE *p; {
1177 	/* change hard to do operators into function calls.  */
1178 	register NODE *q;
1179 	register struct functbl *f;
1180 	register int o;
1181 	register TWORD t, t1, t2;
1182 
1183 	o = p->in.op;
1184 
1185 	for( f=opfunc; f->fop; f++ ) {
1186 		if( o==f->fop ) goto convert;
1187 	}
1188 	return;
1189 
1190 	convert:
1191 	t = p->in.type;
1192 	t1 = p->in.left->in.type;
1193 	t2 = p->in.right->in.type;
1194 
1195 	if (!((ISUNSIGNED(t1) && !(ISUNSIGNED(t2))) ||
1196 	     ( t2 == UNSIGNED))) return;
1197 
1198 	/* need to rewrite tree for ASG OP */
1199 	/* must change ASG OP to a simple OP */
1200 	if( asgop( o ) ) {
1201 		q = talloc();
1202 		q->in.op = NOASG ( o );
1203 		q->in.rall = NOPREF;
1204 		q->in.type = p->in.type;
1205 		q->in.left = tcopy(p->in.left);
1206 		q->in.right = p->in.right;
1207 		p->in.op = ASSIGN;
1208 		p->in.right = q;
1209 		zappost(q->in.left); /* remove post-INCR(DECR) from new node */
1210 		fixpre(q->in.left);	/* change pre-INCR(DECR) to +/-	*/
1211 		p = q;
1212 
1213 	}
1214 	/* turn logicals to compare 0 */
1215 	else if( logop( o ) ) {
1216 		ncopy(q = talloc(), p);
1217 		p->in.left = q;
1218 		p->in.right = q = talloc();
1219 		q->in.op = ICON;
1220 		q->in.type = INT;
1221 #ifndef FLEXNAMES
1222 		q->in.name[0] = '\0';
1223 #else
1224 		q->in.name = "";
1225 #endif
1226 		q->tn.lval = 0;
1227 		q->tn.rval = 0;
1228 		p = p->in.left;
1229 	}
1230 
1231 	/* build comma op for args to function */
1232 	t1 = p->in.left->in.type;
1233 	t2 = 0;
1234 	if ( optype(p->in.op) == BITYPE) {
1235 		q = talloc();
1236 		q->in.op = CM;
1237 		q->in.rall = NOPREF;
1238 		q->in.type = INT;
1239 		q->in.left = p->in.left;
1240 		q->in.right = p->in.right;
1241 		t2 = p->in.right->in.type;
1242 	} else
1243 		q = p->in.left;
1244 
1245 	p->in.op = CALL;
1246 	p->in.right = q;
1247 
1248 	/* put function name in left node of call */
1249 	p->in.left = q = talloc();
1250 	q->in.op = ICON;
1251 	q->in.rall = NOPREF;
1252 	q->in.type = INCREF( FTN + p->in.type );
1253 #ifndef FLEXNAMES
1254 		strcpy( q->in.name, f->func );
1255 #else
1256 		q->in.name = f->func;
1257 #endif
1258 	q->tn.lval = 0;
1259 	q->tn.rval = 0;
1260 
1261 	}
1262 
1263 zappost(p) NODE *p; {
1264 	/* look for ++ and -- operators and remove them */
1265 
1266 	register int o, ty;
1267 	register NODE *q;
1268 	o = p->in.op;
1269 	ty = optype( o );
1270 
1271 	switch( o ){
1272 
1273 	case INCR:
1274 	case DECR:
1275 			q = p->in.left;
1276 			p->in.right->in.op = FREE;  /* zap constant */
1277 			ncopy( p, q );
1278 			q->in.op = FREE;
1279 			return;
1280 
1281 		}
1282 
1283 	if( ty == BITYPE ) zappost( p->in.right );
1284 	if( ty != LTYPE ) zappost( p->in.left );
1285 }
1286 
1287 fixpre(p) NODE *p; {
1288 
1289 	register int o, ty;
1290 	o = p->in.op;
1291 	ty = optype( o );
1292 
1293 	switch( o ){
1294 
1295 	case ASG PLUS:
1296 			p->in.op = PLUS;
1297 			break;
1298 	case ASG MINUS:
1299 			p->in.op = MINUS;
1300 			break;
1301 		}
1302 
1303 	if( ty == BITYPE ) fixpre( p->in.right );
1304 	if( ty != LTYPE ) fixpre( p->in.left );
1305 }
1306 
1307 NODE * addroreg(l) NODE *l;
1308 				/* OREG was built in clocal()
1309 				 * for an auto or formal parameter
1310 				 * now its address is being taken
1311 				 * local code must unwind it
1312 				 * back to PLUS/MINUS REG ICON
1313 				 * according to local conventions
1314 				 */
1315 {
1316 	cerror("address of OREG taken");
1317 }
1318 
1319 # ifndef ONEPASS
1320 main( argc, argv ) char *argv[]; {
1321 	return( mainp2( argc, argv ) );
1322 	}
1323 # endif
1324 
1325 strip(p) register NODE *p; {
1326 	NODE *q;
1327 
1328 	/* strip nodes off the top when no side effects occur */
1329 	for( ; ; ) {
1330 		switch( p->in.op ) {
1331 		case SCONV:			/* remove lint tidbits */
1332 			q = p->in.left;
1333 			ncopy( p, q );
1334 			q->in.op = FREE;
1335 			break;
1336 		/* could probably add a few more here */
1337 		default:
1338 			return;
1339 			}
1340 		}
1341 	}
1342 
1343 myreader(p) register NODE *p; {
1344 	strip( p );		/* strip off operations with no side effects */
1345 	walkf( p, hardops );	/* convert ops to function calls */
1346 	canon( p );		/* expands r-vals for fileds */
1347 	walkf( p, optim2 );
1348 	}
1349