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