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