xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32880)
1 #ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.18 (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 or ASSIGN float/double => unsigned */
396 		NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
397 
398 		putstr("ld");
399 		prtype(src);
400 		putchar('\t');
401 		adrput(src);
402 		putstr("\n\t");
403 		float_to_unsigned(p);
404 		break;
405 	}
406 
407 	case 'Y':		/* SCONV or ASSIGN unsigned => float/double */
408 		unsigned_to_float(p);	/* stores into accumulator */
409 		putstr("\n\tst");
410 		prtype(p);
411 		putchar('\t');
412 		if (p->in.op == SCONV)
413 			adrput(resc);
414 		else
415 			adrput(p->in.left);
416 		rtyflg = 1;
417 		break;
418 
419 	case 'Z':
420 		p = p->in.right;
421 		switch (p->in.type) {
422 		case SHORT: {
423 			short w = p->tn.lval;
424 			p->tn.lval = w;
425 			break;
426 		}
427 		case CHAR: {
428 			char c = p->tn.lval;
429 			p->tn.lval = c;
430 			break;
431 		}
432 		}
433 		printf("$%d", p->tn.lval);
434 		break;
435 
436 	default:
437 		cerror( "illegal zzzcode" );
438 	}
439 }
440 
441 #define	MOVB(dst, src, off) { \
442 	putstr("\tmovb\t"); upput(src, off); putchar(','); \
443 	upput(dst, off); putchar('\n'); \
444 }
445 #define	MOVW(dst, src, off) { \
446 	putstr("\tmovw\t"); upput(src, off); putchar(','); \
447 	upput(dst, off); putchar('\n'); \
448 }
449 #define	MOVL(dst, src, off) { \
450 	putstr("\tmovl\t"); upput(src, off); putchar(','); \
451 	upput(dst, off); putchar('\n'); \
452 }
453 /*
454  * Generate code for a structure assignment.
455  */
456 stasg(p)
457 	register NODE *p;
458 {
459 	register NODE *l, *r;
460 	register int size;
461 
462 	switch (p->in.op) {
463 	case STASG:			/* regular assignment */
464 		l = p->in.left;
465 		r = p->in.right;
466 		break;
467 	case STARG:			/* place arg on the stack */
468 		l = getlr(p, '3');
469 		r = p->in.left;
470 		break;
471 	default:
472 		cerror("STASG bad");
473 		/*NOTREACHED*/
474 	}
475 	/*
476 	 * Pun source for use in code generation.
477 	 */
478 	switch (r->in.op) {
479 	case ICON:
480 		r->in.op = NAME;
481 		break;
482 	case REG:
483 		r->in.op = OREG;
484 		break;
485 	default:
486 		cerror( "STASG-r" );
487 		/*NOTREACHED*/
488 	}
489 	size = p->stn.stsize;
490 	if (size <= 0 || size > 65535)
491 		cerror("structure size out of range");
492 	/*
493 	 * Generate optimized code based on structure size
494 	 * and alignment properties....
495 	 */
496 	switch (size) {
497 
498 	case 1:
499 		putstr("\tmovb\t");
500 	optimized:
501 		adrput(r);
502 		putchar(',');
503 		adrput(l);
504 		putchar('\n');
505 		break;
506 
507 	case 2:
508 		if (p->stn.stalign != 2) {
509 			MOVB(l, r, SZCHAR);
510 			putstr("\tmovb\t");
511 		} else
512 			putstr("\tmovw\t");
513 		goto optimized;
514 
515 	case 4:
516 		if (p->stn.stalign != 4) {
517 			if (p->stn.stalign != 2) {
518 				MOVB(l, r, 3*SZCHAR);
519 				MOVB(l, r, 2*SZCHAR);
520 				MOVB(l, r, 1*SZCHAR);
521 				putstr("\tmovb\t");
522 			} else {
523 				MOVW(l, r, SZSHORT);
524 				putstr("\tmovw\t");
525 			}
526 		} else
527 			putstr("\tmovl\t");
528 		goto optimized;
529 
530 	case 6:
531 		if (p->stn.stalign != 2)
532 			goto movblk;
533 		MOVW(l, r, 2*SZSHORT);
534 		MOVW(l, r, 1*SZSHORT);
535 		putstr("\tmovw\t");
536 		goto optimized;
537 
538 	case 8:
539 		if (p->stn.stalign == 4) {
540 			MOVL(l, r, SZLONG);
541 			putstr("\tmovl\t");
542 			goto optimized;
543 		}
544 		/* fall thru...*/
545 
546 	default:
547 	movblk:
548 		/*
549 		 * Can we ever get a register conflict with R1 here?
550 		 */
551 		putstr("\tmovab\t");
552 		adrput(l);
553 		putstr(",r1\n\tmovab\t");
554 		adrput(r);
555 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
556 		rname(R2);
557 		break;
558 	}
559 	/*
560 	 * Reverse above pun for reclaim.
561 	 */
562 	if (r->in.op == NAME)
563 		r->in.op = ICON;
564 	else if (r->in.op == OREG)
565 		r->in.op = REG;
566 }
567 
568 /*
569  * Output the address of the second item in the
570  * pair pointed to by p.
571  */
572 upput(p, size)
573 	register NODE *p;
574 {
575 	CONSZ save;
576 
577 	if (p->in.op == FLD)
578 		p = p->in.left;
579 	switch (p->in.op) {
580 
581 	case NAME:
582 	case OREG:
583 		save = p->tn.lval;
584 		p->tn.lval += size/SZCHAR;
585 		adrput(p);
586 		p->tn.lval = save;
587 		break;
588 
589 	case REG:
590 		if (size == SZLONG) {
591 			putstr(rname(p->tn.rval+1));
592 			break;
593 		}
594 		/* fall thru... */
595 
596 	default:
597 		cerror("illegal upper address op %s size %d",
598 		    opst[p->tn.op], size);
599 		/*NOTREACHED*/
600 	}
601 }
602 
603 /*
604  * Convert a float or double in the accumulator into an unsigned int.
605  * Unlike the vax, the tahoe stores 0 into the destination
606  *	on a conversion of > 2 ** 31, so we compensate.
607  */
608 float_to_unsigned(p)
609 	NODE *p;
610 {
611 	register NODE *l = p->in.left;
612 	int label1 = getlab();
613 	int label2 = getlab();
614 	int label3 = getlab();
615 	NODE *src, *dst;
616 
617 	if (p->in.op == SCONV) {
618 		src = p->in.left;
619 		dst = resc;
620 	} else {
621 		src = p->in.right;
622 		dst = p->in.left;
623 	}
624 
625 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
626 	if (src->in.type == DOUBLE)
627 		putstr(", 0x00000000 # .double");
628 	else
629 		putstr(" # .float");
630 	putstr(" 2147483648\n\t.text\n\tcmp");
631 	prtype(src);
632 	printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
633 	prtype(src);
634 	printf("\tL%d\n\tcv", label1);
635 	prtype(src);
636 	putstr("l\t");
637 	adrput(dst);
638 	putstr("\n\taddl2\t$-2147483648,");
639 	adrput(dst);
640 	printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
641 	prtype(src);
642 	putstr("l\t");
643 	adrput(dst);
644 	printf("\nL%d:", label3);
645 }
646 
647 /*
648  * Convert an unsigned int into a float or double, leaving the result
649  *	in the accumulator.
650  */
651 unsigned_to_float(p)
652 	register NODE *p;
653 {
654 	int label1 = getlab();
655 	int label2 = getlab();
656 	NODE *src, *dst;
657 
658 	if (p->in.op == SCONV) {
659 		src = p->in.left;
660 		dst = resc;
661 	} else {
662 		src = p->in.right;
663 		dst = p->in.left;
664 	}
665 
666 	printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
667 	if (p->in.type == DOUBLE)
668 		putstr(", 0x00000000 # .double");
669 	else
670 		putstr(" # .float");
671 	putstr(" 4294967296\n\t.text\n\tmovl\t");
672 	adrput(src);
673 	putchar(',');
674 	adrput(dst);
675 	putstr("\n\tcvl");
676 	prtype(p);
677 	putchar('\t');
678 	adrput(dst);
679 	printf("\n\tjgeq\tL%d\n\tadd", label1);
680 	prtype(p);
681 	printf("\tL%d\nL%d:", label2, label1);
682 }
683 
684 /*
685  * Prlen() is a cheap prtype()...
686  */
687 static char convtab[SZINT/SZCHAR + 1] = {
688 	'?', 'b', 'w', '?', 'l'
689 };
690 #define	prlen(len)	putchar(convtab[len])
691 
692 
693 /*
694  * Generate code for integral scalar conversions.
695  * Some of this code is designed to work around a tahoe misfeature
696  *	that causes sign- and zero- extension to be defeated in
697  *	certain circumstances.
698  * Basically if the source operand of a CVT or MOVZ instruction is
699  *	shorter than the destination, and the source is a register
700  *	or an immediate constant, sign- and zero- extension are
701  *	ignored and the high bits of the source are copied.  (Note
702  *	that zero-extension is not a problem for immediate
703  *	constants.)
704  */
705 sconv(p, forcc)
706 	NODE *p;
707 	int forcc;
708 {
709 	register NODE *src, *dst;
710 	register NODE *tmp;
711 	register int srclen, dstlen;
712 	int srctype, dsttype;
713 	int val;
714 
715 	if (p->in.op == ASSIGN) {
716 		src = p->in.right;
717 		dst = p->in.left;
718 		dstlen = tlen(dst);
719 		dsttype = dst->in.type;
720 	} else if (p->in.op == SCONV) {
721 		src = p->in.left;
722 		dst = resc;
723 		dstlen = tlen(p);
724 		dsttype = p->in.type;
725 	} else /* if (p->in.op == OPLEAF) */ {
726 		src = p;
727 		dst = resc;
728 		dstlen = SZINT/SZCHAR;
729 		dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
730 	}
731 
732 	if (src->in.op == REG) {
733 		srclen = SZINT/SZCHAR;
734 		srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
735 	} else {
736 		srclen = tlen(src);
737 		srctype = src->in.type;
738 	}
739 
740 	if (src->in.op == ICON) {
741 		if (src->tn.lval == 0) {
742 			putstr("clr");
743 			prtype(dst);
744 			putchar('\t');
745 			adrput(dst);
746 			return;
747 		}
748 		if (dstlen < srclen) {
749 			switch (dsttype) {
750 			case CHAR:
751 				src->tn.lval = (char) src->tn.lval;
752 				break;
753 			case UCHAR:
754 				src->tn.lval = (unsigned char) src->tn.lval;
755 				break;
756 			case SHORT:
757 				src->tn.lval = (short) src->tn.lval;
758 				break;
759 			case USHORT:
760 				src->tn.lval = (unsigned short) src->tn.lval;
761 				break;
762 			}
763 		}
764 		if (dst->in.op == REG) {
765 			dsttype = INT;
766 			dstlen = SZINT/SZCHAR;
767 		}
768 		srctype = dsttype;
769 		srclen = dstlen;
770 	}
771 
772 	if (srclen < dstlen) {
773 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
774 			/* (unsigned short) c; => sign extend to 16 bits */
775 			putstr("cvtbl\t");
776 			adrput(src);
777 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
778 			adrput(dst);
779 			putstr("\n\tmovab\t4(sp),sp");
780 			if (forcc) {
781 				/* inverted test */
782 				putstr("\n\tcmpl\t$0,");
783 				adrput(dst);
784 			}
785 			return;
786 		}
787 		genconv(ISUNSIGNED(srctype),
788 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
789 			src, dst);
790 		return;
791 	}
792 
793 	if (srclen > dstlen && dst->in.op == REG) {
794 		/* if dst is a register, the result must look like an int */
795 		if (src->in.op == REG) {
796 			if (ISUNSIGNED(dsttype)) {
797 				val = (1 << dstlen * SZCHAR) - 1;
798 				if (src->tn.rval == dst->tn.rval)
799 					/* conversion in place */
800 					printf("andl2\t$%#x,", val);
801 				else {
802 					printf("andl3\t$%#x,", val);
803 					adrput(src);
804 					putchar(',');
805 				}
806 				adrput(dst);
807 				return;
808 			}
809 			/*
810 			 * Sign extension in register can also be
811 			 * accomplished by shifts, but unfortunately
812 			 * shifts are extremely slow, due to the lack
813 			 * of a barrel shifter.
814 			 */
815 			putstr("pushl\t");
816 			adrput(src);
817 			putstr("\n\tcvt");
818 			prlen(dstlen);
819 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
820 			adrput(dst);
821 			putstr("\n\tmovab\t4(sp),sp");
822 			if (forcc) {
823 				/* inverted test */
824 				putstr("\n\tcmpl\t$0,");
825 				adrput(dst);
826 			}
827 			return;
828 		}
829 		tmp = talloc();
830 		if ((src->in.op == UNARY MUL &&
831 		    ((src->in.left->in.op == NAME ||
832 		     (src->in.left->in.op == ICON)))) ||
833 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
834 			/* we can increment src's address & pun it */
835 			*tmp = *src;
836 			tmp->tn.lval += srclen - dstlen;
837 		} else {
838 			/* we must store src's address */
839 			*tmp = *dst;
840 			putstr("mova");
841 			prlen(srclen);
842 			putchar('\t');
843 			adrput(src);
844 			putchar(',');
845 			adrput(tmp);
846 			putstr("\n\t");
847 			tmp->tn.op = OREG;
848 			tmp->tn.lval = srclen - dstlen;
849 		}
850 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
851 		tmp->in.op = FREE;
852 		return;
853 	}
854 
855 	genconv(ISUNSIGNED(dsttype),
856 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
857 		src, dst);
858 }
859 
860 genconv(usrc, srclen, dstlen, src, dst)
861 	int usrc;
862 	register int srclen, dstlen;
863 	NODE *src, *dst;
864 {
865 	if (srclen != dstlen) {
866 		if (usrc && srclen < dstlen)
867 			putstr("movz");
868 		else
869 			putstr("cvt");
870 		prlen(srclen);
871 	} else
872 		putstr("mov");
873 	prlen(dstlen);
874 	putchar('\t');
875 	adrput(src);
876 	putchar(',');
877 	adrput(dst);
878 }
879 
880 rmove( rt, rs, t ) TWORD t;{
881 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
882 	if(t==DOUBLE)
883 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
884 	}
885 
886 struct respref
887 respref[] = {
888 	INTAREG|INTBREG,	INTAREG|INTBREG,
889 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
890 	INTEMP,	INTEMP,
891 	FORARG,	FORARG,
892 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
893 	0,	0 };
894 
895 setregs(){ /* set up temporary registers */
896 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
897 	}
898 
899 #ifndef szty
900 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
901 	return(t==DOUBLE ? 2 : 1 );
902 	}
903 #endif
904 
905 rewfld( p ) NODE *p; {
906 	return(1);
907 	}
908 
909 callreg(p) NODE *p; {
910 	return( R0 );
911 	}
912 
913 base( p ) register NODE *p; {
914 	register int o = p->in.op;
915 
916 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
917 	if( o==REG ) return( p->tn.rval );
918     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
919 		return( p->in.left->tn.rval );
920     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
921 		return( p->tn.rval + 0200*1 );
922 	return( -1 );
923 	}
924 
925 offset( p, tyl ) register NODE *p; int tyl; {
926 
927 	if(tyl > 8) return( -1 );
928 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
929 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
930 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
931 	      && (1<<p->in.right->tn.lval)==tyl))
932 		return( p->in.left->tn.rval );
933 	return( -1 );
934 	}
935 
936 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
937 	register NODE *t;
938 	register int i;
939 	NODE *f;
940 
941 	p->in.op = OREG;
942 	f = p->in.left; 	/* have to free this subtree later */
943 
944 	/* init base */
945 	switch (q->in.op) {
946 		case ICON:
947 		case REG:
948 		case OREG:
949 			t = q;
950 			break;
951 
952 		case MINUS:
953 			q->in.right->tn.lval = -q->in.right->tn.lval;
954 		case PLUS:
955 			t = q->in.right;
956 			break;
957 
958 		case UNARY MUL:
959 			t = q->in.left->in.left;
960 			break;
961 
962 		default:
963 			cerror("illegal makeor2");
964 	}
965 
966 	p->tn.lval = t->tn.lval;
967 #ifndef FLEXNAMES
968 	for(i=0; i<NCHNAM; ++i)
969 		p->in.name[i] = t->in.name[i];
970 #else
971 	p->in.name = t->in.name;
972 #endif
973 
974 	/* init offset */
975 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
976 
977 	tfree(f);
978 	return;
979 	}
980 
981 canaddr( p ) NODE *p; {
982 	register int o = p->in.op;
983 
984 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
985 	return(0);
986 	}
987 
988 #ifndef shltype
989 shltype( o, p ) register NODE *p; {
990 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
991 	}
992 #endif
993 
994 flshape( p ) NODE *p; {
995 	register int o = p->in.op;
996 
997 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
998 	return(0);
999 	}
1000 
1001 shtemp( p ) register NODE *p; {
1002 	if( p->in.op == STARG ) p = p->in.left;
1003 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
1004 	}
1005 
1006 shumul( p ) register NODE *p; {
1007 	register int o;
1008 	extern int xdebug;
1009 
1010 	if (xdebug) {
1011 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1012 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1013 		}
1014 
1015 	o = p->in.op;
1016 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1017 	 && p->in.type != PTR+DOUBLE)
1018 		return( STARNM );
1019 
1020 	return( 0 );
1021 	}
1022 
1023 special( p, shape ) register NODE *p; {
1024 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
1025 	else return(0);
1026 }
1027 
1028 adrcon( val ) CONSZ val; {
1029 	printf(ACONFMT, val);
1030 	}
1031 
1032 conput( p ) register NODE *p; {
1033 	switch( p->in.op ){
1034 
1035 	case ICON:
1036 		acon( p );
1037 		return;
1038 
1039 	case REG:
1040 		putstr(rname(p->tn.rval));
1041 		return;
1042 
1043 	default:
1044 		cerror( "illegal conput" );
1045 		}
1046 	}
1047 
1048 insput( p ) NODE *p; {
1049 	cerror( "insput" );
1050 	}
1051 
1052 adrput( p ) register NODE *p; {
1053 	register int r;
1054 	/* output an address, with offsets, from p */
1055 
1056 	if( p->in.op == FLD ){
1057 		p = p->in.left;
1058 		}
1059 	switch( p->in.op ){
1060 
1061 	case NAME:
1062 		acon( p );
1063 		return;
1064 
1065 	case ICON:
1066 		/* addressable value of the constant */
1067 		putchar('$');
1068 		acon( p );
1069 		return;
1070 
1071 	case REG:
1072 		putstr(rname(p->tn.rval));
1073 		if(p->in.type == DOUBLE)	/* for entry mask */
1074 			(void) rname(p->tn.rval+1);
1075 		return;
1076 
1077 	case OREG:
1078 		r = p->tn.rval;
1079 		if( R2TEST(r) ){ /* double indexing */
1080 			register int flags;
1081 
1082 			flags = R2UPK3(r);
1083 			if( flags & 1 ) putchar('*');
1084 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1085 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1086 			printf( "[%s]", rname(R2UPK2(r)) );
1087 			return;
1088 			}
1089 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
1090 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1091 			printf( CONFMT, p->tn.lval );
1092 			putstr( "(fp)" );
1093 			return;
1094 			}
1095 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1096 		printf( "(%s)", rname(p->tn.rval) );
1097 		return;
1098 
1099 	case UNARY MUL:
1100 		/* STARNM or STARREG found */
1101 		if( tshape(p, STARNM) ) {
1102 			putchar( '*' );
1103 			adrput( p->in.left);
1104 			}
1105 		return;
1106 
1107 	default:
1108 		cerror( "illegal address" );
1109 		return;
1110 
1111 		}
1112 
1113 	}
1114 
1115 acon( p ) register NODE *p; { /* print out a constant */
1116 
1117 	if( p->in.name[0] == '\0' ){
1118 		printf( CONFMT, p->tn.lval);
1119 		return;
1120 	} else {
1121 #ifndef FLEXNAMES
1122 		printf( "%.8s", p->in.name );
1123 #else
1124 		putstr(p->in.name);
1125 #endif
1126 		if (p->tn.lval != 0) {
1127 			putchar('+');
1128 			printf(CONFMT, p->tn.lval);
1129 		}
1130 	}
1131 	}
1132 
1133 genscall( p, cookie ) register NODE *p; {
1134 	/* structure valued call */
1135 	return( gencall( p, cookie ) );
1136 	}
1137 
1138 genfcall( p, cookie ) register NODE *p; {
1139 	register NODE *p1;
1140 	register int m;
1141 	static char *funcops[6] = {
1142 		"sin", "cos", "sqrt", "exp", "log", "atan"
1143 	};
1144 
1145 	/* generate function opcodes */
1146 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1147 	 (p1 = p->in.left)->in.op==ICON &&
1148 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1149 #ifdef FLEXNAMES
1150 		p1->in.name++;
1151 #else
1152 		strcpy(p1->in.name, p1->in.name[1]);
1153 #endif
1154 		for(m=0; m<6; m++)
1155 			if(!strcmp(p1->in.name, funcops[m]))
1156 				break;
1157 		if(m >= 6)
1158 			uerror("no opcode for fortarn function %s", p1->in.name);
1159 	} else
1160 		uerror("illegal type of fortarn function");
1161 	p1 = p->in.right;
1162 	p->in.op = FORTCALL;
1163 	if(!canaddr(p1))
1164 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1165 	m = match( p, INTAREG|INTBREG );
1166 	return(m != MDONE);
1167 }
1168 
1169 /* tbl */
1170 int gc_numbytes;
1171 /* tbl */
1172 
1173 gencall( p, cookie ) register NODE *p; {
1174 	/* generate the call given by p */
1175 	register NODE *p1, *ptemp;
1176 	register int temp, temp1;
1177 	register int m;
1178 
1179 	if( p->in.right ) temp = argsize( p->in.right );
1180 	else temp = 0;
1181 
1182 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1183 		/* set aside room for structure return */
1184 
1185 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1186 		else temp1 = temp;
1187 		}
1188 
1189 	if( temp > maxargs ) maxargs = temp;
1190 	SETOFF(temp1,4);
1191 
1192 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1193 		ptemp = talloc();
1194 		ptemp->in.op = OREG;
1195 		ptemp->tn.lval = -1;
1196 		ptemp->tn.rval = SP;
1197 #ifndef FLEXNAMES
1198 		ptemp->in.name[0] = '\0';
1199 #else
1200 		ptemp->in.name = "";
1201 #endif
1202 		ptemp->in.rall = NOPREF;
1203 		ptemp->in.su = 0;
1204 		genargs( p->in.right, ptemp );
1205 		ptemp->in.op = FREE;
1206 		}
1207 
1208 	p1 = p->in.left;
1209 	if( p1->in.op != ICON ){
1210 		if( p1->in.op != REG ){
1211 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1212 				if( p1->in.op != NAME ){
1213 					order( p1, INAREG );
1214 					}
1215 				}
1216 			}
1217 		}
1218 
1219 /* tbl
1220 	setup gc_numbytes so reference to ZC works */
1221 
1222 	gc_numbytes = temp&(0x3ff);
1223 
1224 	p->in.op = UNARY CALL;
1225 	m = match( p, INTAREG|INTBREG );
1226 
1227 	return(m != MDONE);
1228 	}
1229 
1230 /* tbl */
1231 char *
1232 ccbranches[] = {
1233 	"eql",
1234 	"neq",
1235 	"leq",
1236 	"lss",
1237 	"geq",
1238 	"gtr",
1239 	"lequ",
1240 	"lssu",
1241 	"gequ",
1242 	"gtru",
1243 	};
1244 /* tbl */
1245 
1246 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1247 
1248 		if(o != 0 && (o < EQ || o > UGT ))
1249 			cerror( "bad conditional branch: %s", opst[o] );
1250 		printf( "	j%s	L%d\n",
1251 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
1252 	}
1253 
1254 nextcook( p, cookie ) NODE *p; {
1255 	/* we have failed to match p with cookie; try another */
1256 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1257 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1258 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1259 	return( FORREW );
1260 	}
1261 
1262 lastchance( p, cook ) NODE *p; {
1263 	/* forget it! */
1264 	return(0);
1265 	}
1266 
1267 optim2( p ) register NODE *p; {
1268 # ifdef ONEPASS
1269 	/* do local tree transformations and optimizations */
1270 # define RV(p) p->in.right->tn.lval
1271 # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
1272 	register int o, i;
1273 	register NODE *l, *r;
1274 
1275 	switch (o = p->in.op) {
1276 
1277 	case DIV: case ASG DIV:
1278 	case MOD: case ASG MOD:
1279 		/*
1280 		 * Change unsigned mods and divs to
1281 		 * logicals (mul is done in mip & c2)
1282 		 */
1283 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1284 		    (i = ispow2(RV(p))) >= 0) {
1285 			if (o == DIV || o == ASG DIV) {
1286 				p->in.op = RS;
1287 				RV(p) = i;
1288 			} else {
1289 				p->in.op = AND;
1290 				RV(p)--;
1291 			}
1292 			if (asgop(o))
1293 				p->in.op = ASG p->in.op;
1294 		}
1295 		return;
1296 
1297 	case SCONV:
1298 		l = p->in.left;
1299 		if (anyfloat(p, l)) {
1300 			/* save some labor later */
1301 			NODE *t = talloc();
1302 
1303 			if (p->in.type == UCHAR || p->in.type == USHORT) {
1304 				*t = *p;
1305 				t->in.type = UNSIGNED;
1306 				p->in.left = t;
1307 			} else if (l->in.type == UCHAR || l->in.type == USHORT) {
1308 				*t = *p;
1309 				t->in.type = INT;
1310 				p->in.left = t;
1311 			}
1312 		} else if (l->in.op != PCONV &&
1313 		    l->in.op != CALL && l->in.op != UNARY CALL &&
1314 		    tlen(p) == tlen(l)) {
1315 			/* clobber conversions w/o side effects */
1316 			if (l->in.op != FLD)
1317 				l->in.type = p->in.type;
1318 			ncopy(p, l);
1319 			l->in.op = FREE;
1320 		}
1321 		return;
1322 
1323 	case ASSIGN:
1324 		/*
1325 		 * Try to zap storage conversions of non-float items.
1326 		 */
1327 		r = p->in.right;
1328 		if (r->in.op == SCONV) {
1329 			int wdest, wconv, wsrc;
1330 
1331 			if (anyfloat(r, r->in.left)) {
1332 				/* let the code table handle two cases */
1333 				if (p->in.left->in.type == UNSIGNED &&
1334 					   r->in.type == UNSIGNED) {
1335 					p->in.right = r->in.left;
1336 					r->in.op = FREE;
1337 				} else if ((p->in.left->in.type == FLOAT ||
1338 					    p->in.left->in.type == DOUBLE) &&
1339 					   p->in.left->in.type == r->in.type &&
1340 					   r->in.left->in.type == UNSIGNED) {
1341 					p->in.right = r->in.left;
1342 					r->in.op = FREE;
1343 				}
1344 				return;
1345 			}
1346 			wdest = tlen(p->in.left);
1347 			wconv = tlen(r);
1348 			/*
1349 			 * If size doesn't change across assignment or
1350 			 * conversion expands src before shrinking again
1351 			 * due to the assignment, delete conversion so
1352 			 * code generator can create optimal code.
1353 			 */
1354 			if (wdest == wconv ||
1355 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1356 				p->in.right = r->in.left;
1357 				r->in.op = FREE;
1358 			}
1359 		}
1360 		return;
1361 	}
1362 # endif
1363 }
1364 
1365 struct functbl {
1366 	int fop;
1367 	TWORD ftype;
1368 	char *func;
1369 	} opfunc[] = {
1370 	DIV,		TANY,	"udiv",
1371 	MOD,		TANY,	"urem",
1372 	ASG DIV,	TANY,	"audiv",
1373 	ASG MOD,	TANY,	"aurem",
1374 	0,	0,	0 };
1375 
1376 hardops(p)  register NODE *p; {
1377 	/* change hard to do operators into function calls.  */
1378 	register NODE *q;
1379 	register struct functbl *f;
1380 	register o;
1381 	NODE *old,*temp;
1382 
1383 	o = p->in.op;
1384 	if( ! (optype(o)==BITYPE &&
1385 	       (ISUNSIGNED(p->in.left->in.type) ||
1386 		ISUNSIGNED(p->in.right->in.type))) )
1387 		return;
1388 
1389 	for( f=opfunc; f->fop; f++ ) {
1390 		if( o==f->fop ) goto convert;
1391 		}
1392 	return;
1393 
1394 	convert:
1395 	if( asgop( o ) ) {
1396 		old = NIL;
1397 		switch( p->in.left->in.op ){
1398 		case FLD:
1399 			q = p->in.left->in.left;
1400 			/*
1401 			 * rewrite (lval.fld /= rval); as
1402 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1403 			 * else the compiler will evaluate lval twice.
1404 			 */
1405 			if( q->in.op == UNARY MUL ){
1406 				/* first allocate a temp storage */
1407 				temp = talloc();
1408 				temp->in.op = OREG;
1409 				temp->tn.rval = TMPREG;
1410 				temp->tn.lval = BITOOR(freetemp(1));
1411 				temp->in.type = INCREF(p->in.type);
1412 #ifdef FLEXNAMES
1413 				temp->in.name = "";
1414 #else
1415 				temp->in.name[0] = '\0';
1416 #endif
1417 				old = q->in.left;
1418 				q->in.left = temp;
1419 			}
1420 			/* fall thru ... */
1421 
1422 		case REG:
1423 		case NAME:
1424 		case OREG:
1425 			/* change ASG OP to a simple OP */
1426 			q = talloc();
1427 			q->in.op = NOASG p->in.op;
1428 			q->in.rall = NOPREF;
1429 			q->in.type = p->in.type;
1430 			q->in.left = tcopy(p->in.left);
1431 			q->in.right = p->in.right;
1432 			p->in.op = ASSIGN;
1433 			p->in.right = q;
1434 			p = q;
1435 			f -= 2; /* Note: this depends on the table order */
1436 			/* on the right side only - replace *temp with
1437 			 *(temp = &lval), build the assignment node */
1438 			if( old ){
1439 				temp = q->in.left->in.left; /* the "*" node */
1440 				q = talloc();
1441 				q->in.op = ASSIGN;
1442 				q->in.left = temp->in.left;
1443 				q->in.right = old;
1444 				q->in.type = old->in.type;
1445 #ifdef FLEXNAMES
1446 				q->in.name = "";
1447 #else
1448 				q->in.name[0] = '\0';
1449 #endif
1450 				temp->in.left = q;
1451 			}
1452 			break;
1453 
1454 		case UNARY MUL:
1455 			/* avoid doing side effects twice */
1456 			q = p->in.left;
1457 			p->in.left = q->in.left;
1458 			q->in.op = FREE;
1459 			break;
1460 
1461 		default:
1462 			cerror( "hardops: can't compute & LHS" );
1463 			}
1464 		}
1465 
1466 	/* build comma op for args to function */
1467 	q = talloc();
1468 	q->in.op = CM;
1469 	q->in.rall = NOPREF;
1470 	q->in.type = INT;
1471 	q->in.left = p->in.left;
1472 	q->in.right = p->in.right;
1473 	p->in.op = CALL;
1474 	p->in.right = q;
1475 
1476 	/* put function name in left node of call */
1477 	p->in.left = q = talloc();
1478 	q->in.op = ICON;
1479 	q->in.rall = NOPREF;
1480 	q->in.type = INCREF( FTN + p->in.type );
1481 #ifndef FLEXNAMES
1482 	strcpy( q->in.name, f->func );
1483 #else
1484 	q->in.name = f->func;
1485 #endif
1486 	q->tn.lval = 0;
1487 	q->tn.rval = 0;
1488 
1489 	}
1490 
1491 zappost(p) NODE *p; {
1492 	/* look for ++ and -- operators and remove them */
1493 
1494 	register int o, ty;
1495 	register NODE *q;
1496 	o = p->in.op;
1497 	ty = optype( o );
1498 
1499 	switch( o ){
1500 
1501 	case INCR:
1502 	case DECR:
1503 			q = p->in.left;
1504 			p->in.right->in.op = FREE;  /* zap constant */
1505 			ncopy( p, q );
1506 			q->in.op = FREE;
1507 			return;
1508 
1509 		}
1510 
1511 	if( ty == BITYPE ) zappost( p->in.right );
1512 	if( ty != LTYPE ) zappost( p->in.left );
1513 }
1514 
1515 fixpre(p) NODE *p; {
1516 
1517 	register int o, ty;
1518 	o = p->in.op;
1519 	ty = optype( o );
1520 
1521 	switch( o ){
1522 
1523 	case ASG PLUS:
1524 			p->in.op = PLUS;
1525 			break;
1526 	case ASG MINUS:
1527 			p->in.op = MINUS;
1528 			break;
1529 		}
1530 
1531 	if( ty == BITYPE ) fixpre( p->in.right );
1532 	if( ty != LTYPE ) fixpre( p->in.left );
1533 }
1534 
1535 NODE * addroreg(l) NODE *l;
1536 				/* OREG was built in clocal()
1537 				 * for an auto or formal parameter
1538 				 * now its address is being taken
1539 				 * local code must unwind it
1540 				 * back to PLUS/MINUS REG ICON
1541 				 * according to local conventions
1542 				 */
1543 {
1544 	cerror("address of OREG taken");
1545 }
1546 
1547 # ifndef ONEPASS
1548 main( argc, argv ) char *argv[]; {
1549 	return( mainp2( argc, argv ) );
1550 	}
1551 # endif
1552 
1553 strip(p) register NODE *p; {
1554 	NODE *q;
1555 
1556 	/* strip nodes off the top when no side effects occur */
1557 	for( ; ; ) {
1558 		switch( p->in.op ) {
1559 		case SCONV:			/* remove lint tidbits */
1560 			q = p->in.left;
1561 			ncopy( p, q );
1562 			q->in.op = FREE;
1563 			break;
1564 		/* could probably add a few more here */
1565 		default:
1566 			return;
1567 			}
1568 		}
1569 	}
1570 
1571 myreader(p) register NODE *p; {
1572 	strip( p );		/* strip off operations with no side effects */
1573 	walkf( p, hardops );	/* convert ops to function calls */
1574 	canon( p );		/* expands r-vals for fileds */
1575 	walkf( p, optim2 );
1576 	}
1577