xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 32881)
1 #ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.19 (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 #ifdef FLEXNAMES
742 	    (src->tn.name == NULL || *src->tn.name == '\0')
743 #else
744 	    src->tn.name[0] == '\0'
745 #endif
746 	) {
747 		if (src->tn.lval == 0) {
748 			putstr("clr");
749 			prtype(dst);
750 			putchar('\t');
751 			adrput(dst);
752 			return;
753 		}
754 		if (dstlen < srclen) {
755 			switch (dsttype) {
756 			case CHAR:
757 				src->tn.lval = (char) src->tn.lval;
758 				break;
759 			case UCHAR:
760 				src->tn.lval = (unsigned char) src->tn.lval;
761 				break;
762 			case SHORT:
763 				src->tn.lval = (short) src->tn.lval;
764 				break;
765 			case USHORT:
766 				src->tn.lval = (unsigned short) src->tn.lval;
767 				break;
768 			}
769 		}
770 		if (dst->in.op == REG) {
771 			dsttype = INT;
772 			dstlen = SZINT/SZCHAR;
773 		}
774 		srctype = dsttype;
775 		srclen = dstlen;
776 	}
777 
778 	if (srclen < dstlen) {
779 		if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
780 			/* (unsigned short) c; => sign extend to 16 bits */
781 			putstr("cvtbl\t");
782 			adrput(src);
783 			putstr(",-(sp)\n\tmovzwl\t2(sp),");
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 		genconv(ISUNSIGNED(srctype),
794 			srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
795 			src, dst);
796 		return;
797 	}
798 
799 	if (srclen > dstlen && dst->in.op == REG) {
800 		/* if dst is a register, the result must look like an int */
801 		if (src->in.op == REG) {
802 			if (ISUNSIGNED(dsttype)) {
803 				val = (1 << dstlen * SZCHAR) - 1;
804 				if (src->tn.rval == dst->tn.rval)
805 					/* conversion in place */
806 					printf("andl2\t$%#x,", val);
807 				else {
808 					printf("andl3\t$%#x,", val);
809 					adrput(src);
810 					putchar(',');
811 				}
812 				adrput(dst);
813 				return;
814 			}
815 			/*
816 			 * Sign extension in register can also be
817 			 * accomplished by shifts, but unfortunately
818 			 * shifts are extremely slow, due to the lack
819 			 * of a barrel shifter.
820 			 */
821 			putstr("pushl\t");
822 			adrput(src);
823 			putstr("\n\tcvt");
824 			prlen(dstlen);
825 			printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
826 			adrput(dst);
827 			putstr("\n\tmovab\t4(sp),sp");
828 			if (forcc) {
829 				/* inverted test */
830 				putstr("\n\tcmpl\t$0,");
831 				adrput(dst);
832 			}
833 			return;
834 		}
835 		tmp = talloc();
836 		if ((src->in.op == UNARY MUL &&
837 		    ((src->in.left->in.op == NAME ||
838 		     (src->in.left->in.op == ICON)))) ||
839 		    (src->in.op == OREG && !R2TEST(src->tn.rval))) {
840 			/* we can increment src's address & pun it */
841 			*tmp = *src;
842 			tmp->tn.lval += srclen - dstlen;
843 		} else {
844 			/* we must store src's address */
845 			*tmp = *dst;
846 			putstr("mova");
847 			prlen(srclen);
848 			putchar('\t');
849 			adrput(src);
850 			putchar(',');
851 			adrput(tmp);
852 			putstr("\n\t");
853 			tmp->tn.op = OREG;
854 			tmp->tn.lval = srclen - dstlen;
855 		}
856 		genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
857 		tmp->in.op = FREE;
858 		return;
859 	}
860 
861 	genconv(ISUNSIGNED(dsttype),
862 		srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
863 		src, dst);
864 }
865 
866 genconv(usrc, srclen, dstlen, src, dst)
867 	int usrc;
868 	register int srclen, dstlen;
869 	NODE *src, *dst;
870 {
871 	if (srclen != dstlen) {
872 		if (usrc && srclen < dstlen)
873 			putstr("movz");
874 		else
875 			putstr("cvt");
876 		prlen(srclen);
877 	} else
878 		putstr("mov");
879 	prlen(dstlen);
880 	putchar('\t');
881 	adrput(src);
882 	putchar(',');
883 	adrput(dst);
884 }
885 
886 rmove( rt, rs, t ) TWORD t;{
887 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
888 	if(t==DOUBLE)
889 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
890 	}
891 
892 struct respref
893 respref[] = {
894 	INTAREG|INTBREG,	INTAREG|INTBREG,
895 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
896 	INTEMP,	INTEMP,
897 	FORARG,	FORARG,
898 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
899 	0,	0 };
900 
901 setregs(){ /* set up temporary registers */
902 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
903 	}
904 
905 #ifndef szty
906 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
907 	return(t==DOUBLE ? 2 : 1 );
908 	}
909 #endif
910 
911 rewfld( p ) NODE *p; {
912 	return(1);
913 	}
914 
915 callreg(p) NODE *p; {
916 	return( R0 );
917 	}
918 
919 base( p ) register NODE *p; {
920 	register int o = p->in.op;
921 
922 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
923 	if( o==REG ) return( p->tn.rval );
924     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
925 		return( p->in.left->tn.rval );
926     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
927 		return( p->tn.rval + 0200*1 );
928 	return( -1 );
929 	}
930 
931 offset( p, tyl ) register NODE *p; int tyl; {
932 
933 	if(tyl > 8) return( -1 );
934 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
935 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
936 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
937 	      && (1<<p->in.right->tn.lval)==tyl))
938 		return( p->in.left->tn.rval );
939 	return( -1 );
940 	}
941 
942 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
943 	register NODE *t;
944 	register int i;
945 	NODE *f;
946 
947 	p->in.op = OREG;
948 	f = p->in.left; 	/* have to free this subtree later */
949 
950 	/* init base */
951 	switch (q->in.op) {
952 		case ICON:
953 		case REG:
954 		case OREG:
955 			t = q;
956 			break;
957 
958 		case MINUS:
959 			q->in.right->tn.lval = -q->in.right->tn.lval;
960 		case PLUS:
961 			t = q->in.right;
962 			break;
963 
964 		case UNARY MUL:
965 			t = q->in.left->in.left;
966 			break;
967 
968 		default:
969 			cerror("illegal makeor2");
970 	}
971 
972 	p->tn.lval = t->tn.lval;
973 #ifndef FLEXNAMES
974 	for(i=0; i<NCHNAM; ++i)
975 		p->in.name[i] = t->in.name[i];
976 #else
977 	p->in.name = t->in.name;
978 #endif
979 
980 	/* init offset */
981 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
982 
983 	tfree(f);
984 	return;
985 	}
986 
987 canaddr( p ) NODE *p; {
988 	register int o = p->in.op;
989 
990 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
991 	return(0);
992 	}
993 
994 #ifndef shltype
995 shltype( o, p ) register NODE *p; {
996 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
997 	}
998 #endif
999 
1000 flshape( p ) NODE *p; {
1001 	register int o = p->in.op;
1002 
1003 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1004 	return(0);
1005 	}
1006 
1007 shtemp( p ) register NODE *p; {
1008 	if( p->in.op == STARG ) p = p->in.left;
1009 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
1010 	}
1011 
1012 shumul( p ) register NODE *p; {
1013 	register int o;
1014 	extern int xdebug;
1015 
1016 	if (xdebug) {
1017 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1018 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1019 		}
1020 
1021 	o = p->in.op;
1022 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1023 	 && p->in.type != PTR+DOUBLE)
1024 		return( STARNM );
1025 
1026 	return( 0 );
1027 	}
1028 
1029 special( p, shape ) register NODE *p; {
1030 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
1031 	else return(0);
1032 }
1033 
1034 adrcon( val ) CONSZ val; {
1035 	printf(ACONFMT, val);
1036 	}
1037 
1038 conput( p ) register NODE *p; {
1039 	switch( p->in.op ){
1040 
1041 	case ICON:
1042 		acon( p );
1043 		return;
1044 
1045 	case REG:
1046 		putstr(rname(p->tn.rval));
1047 		return;
1048 
1049 	default:
1050 		cerror( "illegal conput" );
1051 		}
1052 	}
1053 
1054 insput( p ) NODE *p; {
1055 	cerror( "insput" );
1056 	}
1057 
1058 adrput( p ) register NODE *p; {
1059 	register int r;
1060 	/* output an address, with offsets, from p */
1061 
1062 	if( p->in.op == FLD ){
1063 		p = p->in.left;
1064 		}
1065 	switch( p->in.op ){
1066 
1067 	case NAME:
1068 		acon( p );
1069 		return;
1070 
1071 	case ICON:
1072 		/* addressable value of the constant */
1073 		putchar('$');
1074 		acon( p );
1075 		return;
1076 
1077 	case REG:
1078 		putstr(rname(p->tn.rval));
1079 		if(p->in.type == DOUBLE)	/* for entry mask */
1080 			(void) rname(p->tn.rval+1);
1081 		return;
1082 
1083 	case OREG:
1084 		r = p->tn.rval;
1085 		if( R2TEST(r) ){ /* double indexing */
1086 			register int flags;
1087 
1088 			flags = R2UPK3(r);
1089 			if( flags & 1 ) putchar('*');
1090 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1091 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1092 			printf( "[%s]", rname(R2UPK2(r)) );
1093 			return;
1094 			}
1095 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
1096 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1097 			printf( CONFMT, p->tn.lval );
1098 			putstr( "(fp)" );
1099 			return;
1100 			}
1101 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1102 		printf( "(%s)", rname(p->tn.rval) );
1103 		return;
1104 
1105 	case UNARY MUL:
1106 		/* STARNM or STARREG found */
1107 		if( tshape(p, STARNM) ) {
1108 			putchar( '*' );
1109 			adrput( p->in.left);
1110 			}
1111 		return;
1112 
1113 	default:
1114 		cerror( "illegal address" );
1115 		return;
1116 
1117 		}
1118 
1119 	}
1120 
1121 acon( p ) register NODE *p; { /* print out a constant */
1122 
1123 	if( p->in.name[0] == '\0' ){
1124 		printf( CONFMT, p->tn.lval);
1125 		return;
1126 	} else {
1127 #ifndef FLEXNAMES
1128 		printf( "%.8s", p->in.name );
1129 #else
1130 		putstr(p->in.name);
1131 #endif
1132 		if (p->tn.lval != 0) {
1133 			putchar('+');
1134 			printf(CONFMT, p->tn.lval);
1135 		}
1136 	}
1137 	}
1138 
1139 genscall( p, cookie ) register NODE *p; {
1140 	/* structure valued call */
1141 	return( gencall( p, cookie ) );
1142 	}
1143 
1144 genfcall( p, cookie ) register NODE *p; {
1145 	register NODE *p1;
1146 	register int m;
1147 	static char *funcops[6] = {
1148 		"sin", "cos", "sqrt", "exp", "log", "atan"
1149 	};
1150 
1151 	/* generate function opcodes */
1152 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1153 	 (p1 = p->in.left)->in.op==ICON &&
1154 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1155 #ifdef FLEXNAMES
1156 		p1->in.name++;
1157 #else
1158 		strcpy(p1->in.name, p1->in.name[1]);
1159 #endif
1160 		for(m=0; m<6; m++)
1161 			if(!strcmp(p1->in.name, funcops[m]))
1162 				break;
1163 		if(m >= 6)
1164 			uerror("no opcode for fortarn function %s", p1->in.name);
1165 	} else
1166 		uerror("illegal type of fortarn function");
1167 	p1 = p->in.right;
1168 	p->in.op = FORTCALL;
1169 	if(!canaddr(p1))
1170 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1171 	m = match( p, INTAREG|INTBREG );
1172 	return(m != MDONE);
1173 }
1174 
1175 /* tbl */
1176 int gc_numbytes;
1177 /* tbl */
1178 
1179 gencall( p, cookie ) register NODE *p; {
1180 	/* generate the call given by p */
1181 	register NODE *p1, *ptemp;
1182 	register int temp, temp1;
1183 	register int m;
1184 
1185 	if( p->in.right ) temp = argsize( p->in.right );
1186 	else temp = 0;
1187 
1188 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1189 		/* set aside room for structure return */
1190 
1191 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1192 		else temp1 = temp;
1193 		}
1194 
1195 	if( temp > maxargs ) maxargs = temp;
1196 	SETOFF(temp1,4);
1197 
1198 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1199 		ptemp = talloc();
1200 		ptemp->in.op = OREG;
1201 		ptemp->tn.lval = -1;
1202 		ptemp->tn.rval = SP;
1203 #ifndef FLEXNAMES
1204 		ptemp->in.name[0] = '\0';
1205 #else
1206 		ptemp->in.name = "";
1207 #endif
1208 		ptemp->in.rall = NOPREF;
1209 		ptemp->in.su = 0;
1210 		genargs( p->in.right, ptemp );
1211 		ptemp->in.op = FREE;
1212 		}
1213 
1214 	p1 = p->in.left;
1215 	if( p1->in.op != ICON ){
1216 		if( p1->in.op != REG ){
1217 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1218 				if( p1->in.op != NAME ){
1219 					order( p1, INAREG );
1220 					}
1221 				}
1222 			}
1223 		}
1224 
1225 /* tbl
1226 	setup gc_numbytes so reference to ZC works */
1227 
1228 	gc_numbytes = temp&(0x3ff);
1229 
1230 	p->in.op = UNARY CALL;
1231 	m = match( p, INTAREG|INTBREG );
1232 
1233 	return(m != MDONE);
1234 	}
1235 
1236 /* tbl */
1237 char *
1238 ccbranches[] = {
1239 	"eql",
1240 	"neq",
1241 	"leq",
1242 	"lss",
1243 	"geq",
1244 	"gtr",
1245 	"lequ",
1246 	"lssu",
1247 	"gequ",
1248 	"gtru",
1249 	};
1250 /* tbl */
1251 
1252 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1253 
1254 		if(o != 0 && (o < EQ || o > UGT ))
1255 			cerror( "bad conditional branch: %s", opst[o] );
1256 		printf( "	j%s	L%d\n",
1257 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
1258 	}
1259 
1260 nextcook( p, cookie ) NODE *p; {
1261 	/* we have failed to match p with cookie; try another */
1262 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1263 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1264 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1265 	return( FORREW );
1266 	}
1267 
1268 lastchance( p, cook ) NODE *p; {
1269 	/* forget it! */
1270 	return(0);
1271 	}
1272 
1273 optim2( p ) register NODE *p; {
1274 # ifdef ONEPASS
1275 	/* do local tree transformations and optimizations */
1276 # define RV(p) p->in.right->tn.lval
1277 # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
1278 	register int o, i;
1279 	register NODE *l, *r;
1280 
1281 	switch (o = p->in.op) {
1282 
1283 	case DIV: case ASG DIV:
1284 	case MOD: case ASG MOD:
1285 		/*
1286 		 * Change unsigned mods and divs to
1287 		 * logicals (mul is done in mip & c2)
1288 		 */
1289 		if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1290 		    (i = ispow2(RV(p))) >= 0) {
1291 			if (o == DIV || o == ASG DIV) {
1292 				p->in.op = RS;
1293 				RV(p) = i;
1294 			} else {
1295 				p->in.op = AND;
1296 				RV(p)--;
1297 			}
1298 			if (asgop(o))
1299 				p->in.op = ASG p->in.op;
1300 		}
1301 		return;
1302 
1303 	case SCONV:
1304 		l = p->in.left;
1305 		if (anyfloat(p, l)) {
1306 			/* save some labor later */
1307 			NODE *t = talloc();
1308 
1309 			if (p->in.type == UCHAR || p->in.type == USHORT) {
1310 				*t = *p;
1311 				t->in.type = UNSIGNED;
1312 				p->in.left = t;
1313 			} else if (l->in.type == UCHAR || l->in.type == USHORT) {
1314 				*t = *p;
1315 				t->in.type = INT;
1316 				p->in.left = t;
1317 			}
1318 		} else if (l->in.op != PCONV &&
1319 		    l->in.op != CALL && l->in.op != UNARY CALL &&
1320 		    tlen(p) == tlen(l)) {
1321 			/* clobber conversions w/o side effects */
1322 			if (l->in.op != FLD)
1323 				l->in.type = p->in.type;
1324 			ncopy(p, l);
1325 			l->in.op = FREE;
1326 		}
1327 		return;
1328 
1329 	case ASSIGN:
1330 		/*
1331 		 * Try to zap storage conversions of non-float items.
1332 		 */
1333 		r = p->in.right;
1334 		if (r->in.op == SCONV) {
1335 			int wdest, wconv, wsrc;
1336 
1337 			if (anyfloat(r, r->in.left)) {
1338 				/* let the code table handle two cases */
1339 				if (p->in.left->in.type == UNSIGNED &&
1340 					   r->in.type == UNSIGNED) {
1341 					p->in.right = r->in.left;
1342 					r->in.op = FREE;
1343 				} else if ((p->in.left->in.type == FLOAT ||
1344 					    p->in.left->in.type == DOUBLE) &&
1345 					   p->in.left->in.type == r->in.type &&
1346 					   r->in.left->in.type == UNSIGNED) {
1347 					p->in.right = r->in.left;
1348 					r->in.op = FREE;
1349 				}
1350 				return;
1351 			}
1352 			wdest = tlen(p->in.left);
1353 			wconv = tlen(r);
1354 			/*
1355 			 * If size doesn't change across assignment or
1356 			 * conversion expands src before shrinking again
1357 			 * due to the assignment, delete conversion so
1358 			 * code generator can create optimal code.
1359 			 */
1360 			if (wdest == wconv ||
1361 			 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1362 				p->in.right = r->in.left;
1363 				r->in.op = FREE;
1364 			}
1365 		}
1366 		return;
1367 	}
1368 # endif
1369 }
1370 
1371 struct functbl {
1372 	int fop;
1373 	TWORD ftype;
1374 	char *func;
1375 	} opfunc[] = {
1376 	DIV,		TANY,	"udiv",
1377 	MOD,		TANY,	"urem",
1378 	ASG DIV,	TANY,	"audiv",
1379 	ASG MOD,	TANY,	"aurem",
1380 	0,	0,	0 };
1381 
1382 hardops(p)  register NODE *p; {
1383 	/* change hard to do operators into function calls.  */
1384 	register NODE *q;
1385 	register struct functbl *f;
1386 	register o;
1387 	NODE *old,*temp;
1388 
1389 	o = p->in.op;
1390 	if( ! (optype(o)==BITYPE &&
1391 	       (ISUNSIGNED(p->in.left->in.type) ||
1392 		ISUNSIGNED(p->in.right->in.type))) )
1393 		return;
1394 
1395 	for( f=opfunc; f->fop; f++ ) {
1396 		if( o==f->fop ) goto convert;
1397 		}
1398 	return;
1399 
1400 	convert:
1401 	if( asgop( o ) ) {
1402 		old = NIL;
1403 		switch( p->in.left->in.op ){
1404 		case FLD:
1405 			q = p->in.left->in.left;
1406 			/*
1407 			 * rewrite (lval.fld /= rval); as
1408 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1409 			 * else the compiler will evaluate lval twice.
1410 			 */
1411 			if( q->in.op == UNARY MUL ){
1412 				/* first allocate a temp storage */
1413 				temp = talloc();
1414 				temp->in.op = OREG;
1415 				temp->tn.rval = TMPREG;
1416 				temp->tn.lval = BITOOR(freetemp(1));
1417 				temp->in.type = INCREF(p->in.type);
1418 #ifdef FLEXNAMES
1419 				temp->in.name = "";
1420 #else
1421 				temp->in.name[0] = '\0';
1422 #endif
1423 				old = q->in.left;
1424 				q->in.left = temp;
1425 			}
1426 			/* fall thru ... */
1427 
1428 		case REG:
1429 		case NAME:
1430 		case OREG:
1431 			/* change ASG OP to a simple OP */
1432 			q = talloc();
1433 			q->in.op = NOASG p->in.op;
1434 			q->in.rall = NOPREF;
1435 			q->in.type = p->in.type;
1436 			q->in.left = tcopy(p->in.left);
1437 			q->in.right = p->in.right;
1438 			p->in.op = ASSIGN;
1439 			p->in.right = q;
1440 			p = q;
1441 			f -= 2; /* Note: this depends on the table order */
1442 			/* on the right side only - replace *temp with
1443 			 *(temp = &lval), build the assignment node */
1444 			if( old ){
1445 				temp = q->in.left->in.left; /* the "*" node */
1446 				q = talloc();
1447 				q->in.op = ASSIGN;
1448 				q->in.left = temp->in.left;
1449 				q->in.right = old;
1450 				q->in.type = old->in.type;
1451 #ifdef FLEXNAMES
1452 				q->in.name = "";
1453 #else
1454 				q->in.name[0] = '\0';
1455 #endif
1456 				temp->in.left = q;
1457 			}
1458 			break;
1459 
1460 		case UNARY MUL:
1461 			/* avoid doing side effects twice */
1462 			q = p->in.left;
1463 			p->in.left = q->in.left;
1464 			q->in.op = FREE;
1465 			break;
1466 
1467 		default:
1468 			cerror( "hardops: can't compute & LHS" );
1469 			}
1470 		}
1471 
1472 	/* build comma op for args to function */
1473 	q = talloc();
1474 	q->in.op = CM;
1475 	q->in.rall = NOPREF;
1476 	q->in.type = INT;
1477 	q->in.left = p->in.left;
1478 	q->in.right = p->in.right;
1479 	p->in.op = CALL;
1480 	p->in.right = q;
1481 
1482 	/* put function name in left node of call */
1483 	p->in.left = q = talloc();
1484 	q->in.op = ICON;
1485 	q->in.rall = NOPREF;
1486 	q->in.type = INCREF( FTN + p->in.type );
1487 #ifndef FLEXNAMES
1488 	strcpy( q->in.name, f->func );
1489 #else
1490 	q->in.name = f->func;
1491 #endif
1492 	q->tn.lval = 0;
1493 	q->tn.rval = 0;
1494 
1495 	}
1496 
1497 zappost(p) NODE *p; {
1498 	/* look for ++ and -- operators and remove them */
1499 
1500 	register int o, ty;
1501 	register NODE *q;
1502 	o = p->in.op;
1503 	ty = optype( o );
1504 
1505 	switch( o ){
1506 
1507 	case INCR:
1508 	case DECR:
1509 			q = p->in.left;
1510 			p->in.right->in.op = FREE;  /* zap constant */
1511 			ncopy( p, q );
1512 			q->in.op = FREE;
1513 			return;
1514 
1515 		}
1516 
1517 	if( ty == BITYPE ) zappost( p->in.right );
1518 	if( ty != LTYPE ) zappost( p->in.left );
1519 }
1520 
1521 fixpre(p) NODE *p; {
1522 
1523 	register int o, ty;
1524 	o = p->in.op;
1525 	ty = optype( o );
1526 
1527 	switch( o ){
1528 
1529 	case ASG PLUS:
1530 			p->in.op = PLUS;
1531 			break;
1532 	case ASG MINUS:
1533 			p->in.op = MINUS;
1534 			break;
1535 		}
1536 
1537 	if( ty == BITYPE ) fixpre( p->in.right );
1538 	if( ty != LTYPE ) fixpre( p->in.left );
1539 }
1540 
1541 NODE * addroreg(l) NODE *l;
1542 				/* OREG was built in clocal()
1543 				 * for an auto or formal parameter
1544 				 * now its address is being taken
1545 				 * local code must unwind it
1546 				 * back to PLUS/MINUS REG ICON
1547 				 * according to local conventions
1548 				 */
1549 {
1550 	cerror("address of OREG taken");
1551 }
1552 
1553 # ifndef ONEPASS
1554 main( argc, argv ) char *argv[]; {
1555 	return( mainp2( argc, argv ) );
1556 	}
1557 # endif
1558 
1559 strip(p) register NODE *p; {
1560 	NODE *q;
1561 
1562 	/* strip nodes off the top when no side effects occur */
1563 	for( ; ; ) {
1564 		switch( p->in.op ) {
1565 		case SCONV:			/* remove lint tidbits */
1566 			q = p->in.left;
1567 			ncopy( p, q );
1568 			q->in.op = FREE;
1569 			break;
1570 		/* could probably add a few more here */
1571 		default:
1572 			return;
1573 			}
1574 		}
1575 	}
1576 
1577 myreader(p) register NODE *p; {
1578 	strip( p );		/* strip off operations with no side effects */
1579 	walkf( p, hardops );	/* convert ops to function calls */
1580 	canon( p );		/* expands r-vals for fileds */
1581 	walkf( p, optim2 );
1582 	}
1583