xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32939)
1 # ifndef lint
2 static char *sccsid ="@(#)local2.c	1.33 (Berkeley) 12/11/87";
3 # endif
4 
5 # include "pass2.h"
6 # include <ctype.h>
7 
8 # define putstr(s)	fputs((s), stdout)
9 
10 # ifdef FORT
11 int ftlab1, ftlab2;
12 # endif
13 /* a lot of the machine dependent parts of the second pass */
14 
15 # define BITMASK(n) ((1L<<n)-1)
16 
17 /*ARGSUSED*/
18 where(c){
19 	fprintf( stderr, "%s, line %d: ", filename, lineno );
20 	}
21 
22 lineid( l, fn ) char *fn; {
23 	/* identify line l and file fn */
24 	printf( "#	line %d, file %s\n", l, fn );
25 	}
26 
27 
28 eobl2(){
29 	register OFFSZ spoff;	/* offset from stack pointer */
30 #ifndef FORT
31 	extern int ftlab1, ftlab2;
32 #endif
33 
34 	spoff = maxoff;
35 	if( spoff >= AUTOINIT ) spoff -= AUTOINIT;
36 	spoff /= SZCHAR;
37 	SETOFF(spoff,4);
38 #ifdef FORT
39 #ifndef FLEXNAMES
40 	printf( "	.set	.F%d,%ld\n", ftnno, spoff );
41 #else
42 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
43 	printf( "	.set	LF%d,%ld\n", ftnno, spoff );
44 #endif
45 #else
46 	printf( "L%d:\n", ftlab1);
47 	if( spoff!=0 )
48 		if( spoff < 64 )
49 			printf( "	subl2	$%ld,sp\n", spoff);
50 		else
51 			printf( "	movab	-%ld(sp),sp\n", spoff);
52 	printf( "	jbr 	L%d\n", ftlab2);
53 #endif
54 	maxargs = -1;
55 	}
56 
57 struct hoptab { int opmask; char * opstring; } ioptab[] = {
58 
59 	PLUS,	"add",
60 	MINUS,	"sub",
61 	MUL,	"mul",
62 	DIV,	"div",
63 	OR,	"bis",
64 	ER,	"xor",
65 	AND,	"bic",
66 	-1, ""    };
67 
68 hopcode( f, o ){
69 	/* output the appropriate string from the above table */
70 
71 	register struct hoptab *q;
72 
73 	if(asgop(o))
74 		o = NOASG o;
75 	for( q = ioptab;  q->opmask>=0; ++q ){
76 		if( q->opmask == o ){
77 			printf( "%s%c", q->opstring, tolower(f));
78 			return;
79 			}
80 		}
81 	cerror( "no hoptab for %s", opst[o] );
82 	}
83 
84 char *
85 rnames[] = {  /* keyed to register number tokens */
86 
87 	"r0", "r1",
88 	"r2", "r3", "r4", "r5",
89 	"r6", "r7", "r8", "r9", "r10", "r11",
90 	"ap", "fp", "sp", "pc",
91 	};
92 
93 int rstatus[] = {
94 	SAREG|STAREG, SAREG|STAREG,
95 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
96 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
97 	SAREG, SAREG, SAREG, SAREG,
98 	};
99 
100 tlen(p) NODE *p;
101 {
102 	switch(p->in.type) {
103 		case CHAR:
104 		case UCHAR:
105 			return(1);
106 
107 		case SHORT:
108 		case USHORT:
109 			return(SZSHORT/SZCHAR);
110 
111 		case DOUBLE:
112 			return(SZDOUBLE/SZCHAR);
113 
114 		default:
115 			return(SZINT/SZCHAR);
116 		}
117 }
118 
119 mixtypes(p, q) NODE *p, *q;
120 {
121 	register TWORD tp, tq;
122 
123 	tp = p->in.type;
124 	tq = q->in.type;
125 
126 	return( (tp==FLOAT || tp==DOUBLE) !=
127 		(tq==FLOAT || tq==DOUBLE) );
128 }
129 
130 prtype(n) NODE *n;
131 {
132 	switch (n->in.type)
133 		{
134 
135 		case DOUBLE:
136 			putchar('d');
137 			return;
138 
139 		case FLOAT:
140 			putchar('f');
141 			return;
142 
143 		case LONG:
144 		case ULONG:
145 		case INT:
146 		case UNSIGNED:
147 			putchar('l');
148 			return;
149 
150 		case SHORT:
151 		case USHORT:
152 			putchar('w');
153 			return;
154 
155 		case CHAR:
156 		case UCHAR:
157 			putchar('b');
158 			return;
159 
160 		default:
161 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
162 			else {
163 				putchar('l');
164 				return;
165 				}
166 		}
167 }
168 
169 zzzcode( p, c ) register NODE *p; {
170 	register int m;
171 	int val;
172 	switch( c ){
173 
174 	case 'N':  /* logical ops, turned into 0-1 */
175 		/* use register given by register 1 */
176 		cbgen( 0, m=getlab(), 'I' );
177 		deflab( p->bn.label );
178 		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->tn.rval] );
179 		deflab( m );
180 		return;
181 
182 	case 'P':
183 		cbgen( p->in.op, p->bn.label, c );
184 		return;
185 
186 	case 'A':
187 	case 'V':
188 		sconv( p, c == 'V' );
189 		return;
190 
191 	case 'G':	/* i *= f; asgops with int lhs and float rhs */
192 		{
193 		register NODE *l, *r, *s;
194 		int rt;
195 
196 		l = p->in.left;
197 		r = p->in.right;
198 		s = talloc();
199 		rt = r->in.type;
200 
201 		s->in.op = SCONV;
202 		s->in.left = l;
203 		s->in.type = rt;
204 		zzzcode(s, 'A');
205 		putstr("\n\t");
206 
207 		hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
208 		putstr("2\t");
209 		adrput(r);
210 		putchar(',');
211 		adrput(resc);
212 		putstr("\n\t");
213 
214 		s->in.op = ASSIGN;
215 		s->in.left = l;
216 		s->in.right = resc;
217 		s->in.type = l->in.type;
218 		zzzcode(s, 'A');
219 
220 		s->in.op = FREE;
221 		return;
222 		}
223 
224 	case 'J':	/* unsigned DIV/MOD with constant divisors */
225 		{
226 		register int ck = INAREG;
227 		int label1, label2;
228 
229 		/* case constant <= 1 is handled by optim() in pass 1 */
230 		/* case constant < 0x80000000 is handled in table */
231 		switch( p->in.op ) {
232 		/* case DIV: handled in optim2() */
233 		case MOD:
234 			if( p->in.left->in.op == REG &&
235 			    p->in.left->tn.rval == resc->tn.rval )
236 				goto asgmod;
237 			label1 = getlab();
238 			expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
239 			printf("\tjlssu\tL%d\n", label1);
240 			expand(p, ck, "\tsubl2\tAR,A1\n");
241 			printf("L%d:", label1);
242 			break;
243 		case ASG DIV:
244 			label1 = getlab();
245 			label2 = getlab();
246 			expand(p, ck, "cmpl\tAL,AR\n");
247 			printf("\tjgequ\tL%d\n", label1);
248 			expand(p, ck, "\tmovl\t$1,AL\n");
249 			printf("\tjbr\tL%d\nL%d:\n", label2, label1);
250 			expand(p, ck, "\tclrl\tAL\n");
251 			printf("L%d:", label2);
252 			break;
253 		case ASG MOD:
254 		asgmod:
255 			label1 = getlab();
256 			expand(p, ck, "cmpl\tAL,AR\n");
257 			printf("\tjlssu\tL%d\n", label1);
258 			expand(p, ck, "\tsubl2\tAR,AL\n");
259 			printf("L%d:", label1);
260 			break;
261 			}
262 		return;
263 		}
264 
265 	case 'B':	/* get oreg value in temp register for left shift */
266 		{
267 		register NODE *r;
268 		if (xdebug) eprint(p, 0, &val, &val);
269 		r = p->in.right;
270 		if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
271 			putstr("movl");
272 		else {
273 			putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
274 			prtype(r);
275 			putchar('l');
276 			}
277 		return;
278 		}
279 
280 	case 'C':	/* num words pushed on arg stack */
281 		{
282 		extern int gc_numbytes;
283 		extern int xdebug;
284 
285 		if (xdebug) printf("->%d<-",gc_numbytes);
286 
287 		printf("$%d", gc_numbytes/(SZLONG/SZCHAR) );
288 		return;
289 		}
290 
291 	case 'D':	/* INCR and DECR */
292 		zzzcode(p->in.left, 'A');
293 		putchar('\n');
294 		putchar('\t');
295 
296 	case 'E':	/* INCR and DECR, FOREFF */
297 		if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1)
298 			{
299 			putstr(p->in.op == INCR ? "inc" : "dec");
300 			prtype(p->in.left);
301 			putchar('\t');
302 			adrput(p->in.left);
303 			return;
304 			}
305 		putstr(p->in.op == INCR ? "add" : "sub");
306 		prtype(p->in.left);
307 		putchar('2');
308 		putchar('\t');
309 		adrput(p->in.right);
310 		putchar(',');
311 		adrput(p->in.left);
312 		return;
313 
314 	case 'F':	/* register type of right operand */
315 		{
316 		register NODE *n;
317 		extern int xdebug;
318 		register int ty;
319 
320 		n = getlr( p, 'R' );
321 		ty = n->in.type;
322 
323 		if (xdebug) printf("->%d<-", ty);
324 
325 		if ( ty==DOUBLE) putchar('d');
326 		else if ( ty==FLOAT ) putchar('f');
327 		else putchar('l');
328 		return;
329 		}
330 
331 	case 'L':	/* type of left operand */
332 	case 'R':	/* type of right operand */
333 		{
334 		register NODE *n;
335 		extern int xdebug;
336 
337 		n = getlr( p, c );
338 		if (xdebug) printf("->%d<-", n->in.type);
339 
340 		prtype(n);
341 		return;
342 		}
343 
344 	case 'Z':	/* AND for CC with ICON -- lval is complemented */
345 		{
346 		register NODE *l, *r;
347 
348 		l = getlr( p, 'L' );
349 		r = getlr( p, 'R' );
350 		m = (1 << tlen(l) * SZCHAR) - 1;
351 		r->tn.lval = ~r->tn.lval;
352 		if( (l->in.type == CHAR || l->in.type == SHORT) &&
353 		    (r->tn.lval & ~m) ) {
354 			putstr("cvt");
355 			prtype(l);
356 			putstr("l\t");
357 			adrput(l);
358 			putchar(',');
359 			adrput(resc);
360 			putstr("\n\t");
361 			resc->tn.type = INT;
362 			l = resc;
363 			}
364 		else if( l->in.type == UCHAR || l->in.type == USHORT )
365 			/* remove trash left over from complementing */
366 			r->tn.lval &= m;
367 		putstr("bit");
368 		prtype(l);
369 		printf("\t$%ld", r->tn.lval);
370 		putchar(',');
371 		adrput(l);
372 		return;
373 		}
374 
375 	case 'U':	/* 32 - n, for unsigned right shifts */
376 		printf("$%d", 32 - p->in.right->tn.lval );
377 		return;
378 
379 	case 'T':	/* rounded structure length for arguments */
380 		{
381 		int size;
382 
383 		size = p->stn.stsize;
384 		SETOFF( size, 4);
385 		printf("$%d", size);
386 		return;
387 		}
388 
389 	case 'S':  /* structure assignment */
390 		stasg(p);
391 		break;
392 
393 	default:
394 		cerror( "illegal zzzcode" );
395 		}
396 	}
397 
398 stasg(p)
399 	register NODE *p;
400 {
401 	register NODE *l, *r;
402 	register size;
403 
404 	if( p->in.op == STASG ){
405 		l = p->in.left;
406 		r = p->in.right;
407 
408 		}
409 	else if( p->in.op == STARG ){  /* store an arg into a temporary */
410 		r = p->in.left;
411 		}
412 	else cerror( "STASG bad" );
413 
414 	if( r->in.op == ICON ) r->in.op = NAME;
415 	else if( r->in.op == REG ) r->in.op = OREG;
416 	else if( r->in.op != OREG ) cerror( "STASG-r" );
417 
418 	size = p->stn.stsize;
419 
420 	if( size <= 0 || size > 65535 )
421 		cerror("structure size <0=0 or >65535");
422 
423 	switch(size) {
424 		case 1:
425 			putstr("	movb	");
426 			break;
427 		case 2:
428 			putstr("	movw	");
429 			break;
430 		case 4:
431 			putstr("	movl	");
432 			break;
433 		case 8:
434 			putstr("	movq	");
435 			break;
436 		default:
437 			printf("	movc3	$%d,", size);
438 			break;
439 	}
440 	adrput(r);
441 	if( p->in.op == STASG ){
442 		putchar(',');
443 		adrput(l);
444 		putchar('\n');
445 		}
446 	else
447 		putstr(",(sp)\n");
448 
449 	if( r->in.op == NAME ) r->in.op = ICON;
450 	else if( r->in.op == OREG ) r->in.op = REG;
451 	}
452 
453 NODE *makearg( ty ) int ty; {
454 	register NODE *p, *q;
455 
456 	/* build a -(sp) operand */
457 	p = talloc();
458 	p->in.op = REG;
459 	/* the type needn't be right, just consistent */
460 	p->in.type = INCREF(ty);
461 	p->tn.rval = SP;
462 	p->tn.lval = 0;
463 	q = talloc();
464 	q->in.op = ASG MINUS;
465 	q->in.type = INCREF(ty);
466 	q->in.left = p;
467 	p = talloc();
468 	p->in.op = ICON;
469 	p->in.type = INT;
470 	p->tn.name = "";
471 	p->tn.lval = szty(ty) * (SZINT/SZCHAR);
472 	q->in.right = p;
473 	p = talloc();
474 	p->in.op = UNARY MUL;
475 	p->in.left = q;
476 	return( p );
477 	}
478 
479 sconv( p, forarg ) register NODE *p; {
480 	register NODE *l, *r;
481 	int m, val;
482 
483 	if (xdebug) eprint(p, 0, &val, &val);
484 	r = getlr(p, 'R');
485 	if (p->in.op == ASSIGN)
486 		l = getlr(p, 'L');
487 	else if (p->in.op == SCONV) {
488 #if defined(FORT) || defined(SPRECC)
489 		m = r->in.type;
490 #else
491 		m = r->in.type==FLOAT ? DOUBLE : r->in.type;
492 #endif
493 		if (forarg)
494 			l = makearg( m );
495 		else
496 			l = resc;
497 		l->in.type = m;
498 		r = getlr(p, 'L');
499 		}
500 	else {		/* OPLTYPE */
501 #if defined(FORT) || defined(SPRECC)
502 		m = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT);
503 #else
504 		m = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT);
505 #endif
506 		if (forarg)
507 			l = makearg( m );
508 		else
509 			l = resc;
510 		l->in.type = m;
511 		}
512 	if (r->in.op == ICON)
513 		if (r->in.name[0] == '\0') {
514 			if (r->tn.lval == 0 && !forarg) {
515 				putstr("clr");
516 				prtype(l);
517 				putchar('\t');
518 				adrput(l);
519 				goto cleanup;
520 				}
521 			if (r->tn.lval < 0 && r->tn.lval >= -63) {
522 				putstr("mneg");
523 				prtype(l);
524 				r->tn.lval = -r->tn.lval;
525 				goto ops;
526 				}
527 			if (r->tn.lval < 0)
528 				r->in.type = r->tn.lval >= -128 ? CHAR
529 					: (r->tn.lval >= -32768 ? SHORT
530 					: INT);
531 			else if (l->in.type == FLOAT ||
532 			    l->in.type == DOUBLE)
533 				r->in.type = r->tn.lval <= 63 ? INT
534 					: (r->tn.lval <= 127 ? CHAR
535 					: (r->tn.lval <= 32767 ? SHORT
536 					: INT));
537 			else
538 				r->in.type = r->tn.lval <= 63 ? INT
539 					: (r->tn.lval <= 127 ? CHAR
540 					: (r->tn.lval <= 255 ? UCHAR
541 					: (r->tn.lval <= 32767 ? SHORT
542 					: (r->tn.lval <= 65535 ? USHORT
543 					: INT))));
544 			if (forarg && r->in.type == INT) {
545 				putstr("pushl\t");
546 				adrput(r);
547 				goto cleanup;
548 				}
549 			}
550 		else {
551 			if (forarg && tlen(r) == SZINT/SZCHAR) {
552 				putstr("pushl\t");
553 				adrput(r);
554 				goto cleanup;
555 				}
556 			putstr("moval\t");
557 			acon(r);
558 			putchar(',');
559 			adrput(l);
560 			goto cleanup;
561 			}
562 
563 	if (p->in.op == SCONV &&
564 	    !(l->in.type == FLOAT || l->in.type == DOUBLE) &&
565 	    !mixtypes(l, r)) {
566 		/*
567 		 * Because registers must always contain objects
568 		 * of the same width as INTs, we may have to
569 		 * perform two conversions to get an INT.  Can
570 		 * the conversions be collapsed into one?
571 		 */
572 		if (m = collapsible(l, r))
573 			r->in.type = m;
574 		else {
575 			/*
576 			 * Two steps are required.
577 			 */
578 			NODE *x = &resc[1];
579 
580 			*x = *l;
581 			if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type))
582 				putstr("movz");
583 			else
584 				putstr("cvt");
585 			prtype(r);
586 			prtype(x);
587 			putchar('\t');
588 			adrput(r);
589 			putchar(',');
590 			adrput(x);
591 			putchar('\n');
592 			putchar('\t');
593 			r = x;
594 			}
595 		l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT);
596 		}
597 
598 	if ((r->in.type == UNSIGNED || r->in.type == ULONG) &&
599 	    mixtypes(l, r)) {
600 		int label1, label2;
601 
602 		label1 = getlab();
603 		label2 = getlab();
604 
605 		putstr("movl\t");
606 		adrput(r);
607 		putchar(',');
608 		adrput(l);
609 		putstr("\n\tjbsc\t$31,");
610 		adrput(l);
611 		printf(",L%d\n\tcvtl", label1);
612 		prtype(l);
613 		putchar('\t');
614 		adrput(l);
615 		putchar(',');
616 		adrput(l);
617 		printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1);
618 		prtype(l);
619 		putchar('\t');
620 		adrput(l);
621 		putchar(',');
622 		adrput(l);
623 		putstr("\n\tadd");
624 		prtype(l);
625 		putstr("2\t$0");
626 		prtype(l);
627 		putstr("2.147483648e9,");
628 		adrput(l);
629 		printf("\nL%d:", label2);
630 
631 		goto cleanup;
632 		}
633 
634 	if (!mixtypes(l,r)) {
635 		if (tlen(l) == tlen(r)) {
636 			if (forarg && tlen(l) == SZINT/SZCHAR) {
637 				putstr("pushl\t");
638 				adrput(r);
639 				goto cleanup;
640 				}
641 			putstr("mov");
642 #ifdef FORT
643 			if (Oflag)
644 				prtype(l);
645 			else {
646 				if (l->in.type == DOUBLE)
647 					putchar('q');
648 				else if(l->in.type == FLOAT)
649 					putchar('l');
650 				else
651 					prtype(l);
652 				}
653 #else
654 			prtype(l);
655 #endif FORT
656 			goto ops;
657 			}
658 		else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
659 			putstr("movz");
660 		else
661 			putstr("cvt");
662 		}
663 	else
664 		putstr("cvt");
665 	prtype(r);
666 	prtype(l);
667 ops:
668 	putchar('\t');
669 	adrput(r);
670 	putchar(',');
671 	adrput(l);
672 
673 cleanup:
674 	if (forarg)
675 		tfree(l);
676 	}
677 
678 /*
679  * collapsible(dest, src) -- if a conversion with a register destination
680  *	can be accomplished in one instruction, return the type of src
681  *	that will do the job correctly; otherwise return 0.  Note that
682  *	a register must always end up having type INT or UNSIGNED.
683  */
684 int
685 collapsible(dest, src)
686 NODE *dest, *src;
687 {
688 	int st = src->in.type;
689 	int dt = dest->in.type;
690 	int newt = 0;
691 
692 	/*
693 	 * Are there side effects of evaluating src?
694 	 * If the derived type will not be the same size as src,
695 	 * we may have to use two steps.
696 	 */
697 	if (tlen(src) > tlen(dest)) {
698 		if (tshape(src, STARREG))
699 			return (0);
700 		if (src->in.op == OREG && R2TEST(src->tn.rval))
701 			return (0);
702 		}
703 
704 	/*
705 	 * Can we get an object of dest's type by punning src?
706 	 * Praises be to great Cthulhu for little-endian machines...
707 	 */
708 	if (st == CHAR && dt == USHORT)
709 		/*
710 		 * Special case -- we must sign-extend to 16 bits.
711 		 */
712 		return (0);
713 
714 	if (tlen(src) < tlen(dest))
715 		newt = st;
716 	else
717 		newt = dt;
718 
719 	return (newt);
720 	}
721 
722 rmove( rt, rs, t ) TWORD t; {
723 	printf( "	%s	%s,%s\n",
724 #ifdef FORT
725 		!Oflag ? (t==DOUBLE ? "movq" : "movl") :
726 #endif
727 		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
728 		rnames[rs], rnames[rt] );
729 	}
730 
731 struct respref
732 respref[] = {
733 	INTAREG|INTBREG,	INTAREG|INTBREG,
734 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
735 	INTEMP,	INTEMP,
736 	FORARG,	FORARG,
737 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
738 	0,	0 };
739 
740 setregs(){ /* set up temporary registers */
741 	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
742 	}
743 
744 /*ARGSUSED*/
745 rewfld( p ) NODE *p; {
746 	return(1);
747 	}
748 
749 /*ARGSUSED*/
750 callreg(p) NODE *p; {
751 	return( R0 );
752 	}
753 
754 base( p ) register NODE *p; {
755 	register int o = p->in.op;
756 
757 	if( o==ICON && p->tn.name[0] != '\0' ) return( 100 ); /* ie no base reg */
758 	if( o==REG ) return( p->tn.rval );
759     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
760 		return( p->in.left->tn.rval );
761     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
762 		return( p->tn.rval + 0200*1 );
763 	if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 );
764 	if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 );
765 	if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG
766 	  && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
767 		return( p->in.left->in.left->tn.rval + 0200*(1+2) );
768 	if( o==NAME ) return( 100 + 0200*1 );
769 	return( -1 );
770 	}
771 
772 offset( p, tyl ) register NODE *p; int tyl; {
773 
774 	if( tyl==1 &&
775 	    p->in.op==REG &&
776 	    (p->in.type==INT || p->in.type==UNSIGNED) )
777 		return( p->tn.rval );
778 	if( p->in.op==LS &&
779 	    p->in.left->in.op==REG &&
780 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
781 	    p->in.right->in.op==ICON &&
782 	    p->in.right->in.name[0]=='\0' &&
783 	    (1<<p->in.right->tn.lval)==tyl)
784 		return( p->in.left->tn.rval );
785 	if( tyl==2 &&
786 	    p->in.op==PLUS &&
787 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
788 	    p->in.left->in.op==REG &&
789 	    p->in.right->in.op==REG &&
790 	    p->in.left->tn.rval==p->in.right->tn.rval )
791 		return( p->in.left->tn.rval );
792 	return( -1 );
793 	}
794 
795 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
796 	register NODE *t;
797 	NODE *f;
798 
799 	p->in.op = OREG;
800 	f = p->in.left; 	/* have to free this subtree later */
801 
802 	/* init base */
803 	switch (q->in.op) {
804 		case ICON:
805 		case REG:
806 		case OREG:
807 		case NAME:
808 			t = q;
809 			break;
810 
811 		case MINUS:
812 			q->in.right->tn.lval = -q->in.right->tn.lval;
813 		case PLUS:
814 			t = q->in.right;
815 			break;
816 
817 		case INCR:
818 		case ASG MINUS:
819 			t = q->in.left;
820 			break;
821 
822 		case UNARY MUL:
823 			t = q->in.left->in.left;
824 			break;
825 
826 		default:
827 			cerror("illegal makeor2");
828 	}
829 
830 	p->tn.lval = t->tn.lval;
831 #ifndef FLEXNAMES
832 	{
833 		register int i;
834 		for(i=0; i<NCHNAM; ++i)
835 			p->in.name[i] = t->in.name[i];
836 	}
837 #else
838 	p->in.name = t->in.name;
839 #endif
840 
841 	/* init offset */
842 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
843 
844 	tfree(f);
845 	return;
846 	}
847 
848 canaddr( p ) NODE *p; {
849 	register int o = p->in.op;
850 
851 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
852 	return(0);
853 	}
854 
855 flshape( p ) NODE *p; {
856 	register int o = p->in.op;
857 
858 	return( o == REG || o == NAME || o == ICON ||
859 		(o == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
860 	}
861 
862 /* INTEMP shapes must not contain any temporary registers */
863 shtemp( p ) register NODE *p; {
864 	int r;
865 
866 	if( p->in.op == STARG ) p = p->in.left;
867 
868 	switch (p->in.op) {
869 	case REG:
870 		return( !istreg(p->tn.rval) );
871 	case OREG:
872 		r = p->tn.rval;
873 		if( R2TEST(r) ) {
874 			if( istreg(R2UPK1(r)) )
875 				return(0);
876 			r = R2UPK2(r);
877 			}
878 		return( !istreg(r) );
879 	case UNARY MUL:
880 		p = p->in.left;
881 		return( p->in.op != UNARY MUL && shtemp(p) );
882 		}
883 
884 	if( optype( p->in.op ) != LTYPE ) return(0);
885 	return(1);
886 	}
887 
888 shumul( p ) register NODE *p; {
889 	register int o;
890 	extern int xdebug;
891 
892 	if (xdebug) {
893 		int val;
894 		printf("shumul:\n");
895 		eprint(p, 0, &val, &val);
896 		}
897 
898 	o = p->in.op;
899 	if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
900 
901 	if( ( o == INCR || o == ASG MINUS ) &&
902 	    ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) &&
903 	    p->in.right->in.name[0] == '\0' )
904 		{
905 		switch (p->in.type)
906 			{
907 			case CHAR|PTR:
908 			case UCHAR|PTR:
909 				o = 1;
910 				break;
911 
912 			case SHORT|PTR:
913 			case USHORT|PTR:
914 				o = 2;
915 				break;
916 
917 			case INT|PTR:
918 			case UNSIGNED|PTR:
919 			case LONG|PTR:
920 			case ULONG|PTR:
921 			case FLOAT|PTR:
922 				o = 4;
923 				break;
924 
925 			case DOUBLE|PTR:
926 				o = 8;
927 				break;
928 
929 			default:
930 				if ( ISPTR(p->in.type) &&
931 				     ISPTR(DECREF(p->in.type)) ) {
932 					o = 4;
933 					break;
934 					}
935 				else return(0);
936 			}
937 		return( p->in.right->tn.lval == o ? STARREG : 0);
938 		}
939 
940 	return( 0 );
941 	}
942 
943 adrcon( val ) CONSZ val; {
944 	putchar( '$' );
945 	printf( CONFMT, val );
946 	}
947 
948 conput( p ) register NODE *p; {
949 	switch( p->in.op ){
950 
951 	case ICON:
952 		acon( p );
953 		return;
954 
955 	case REG:
956 		putstr( rnames[p->tn.rval] );
957 		return;
958 
959 	default:
960 		cerror( "illegal conput" );
961 		}
962 	}
963 
964 /*ARGSUSED*/
965 insput( p ) NODE *p; {
966 	cerror( "insput" );
967 	}
968 
969 upput( p, size ) NODE *p; int size; {
970 	if( size == SZLONG && p->in.op == REG ) {
971 		putstr( rnames[p->tn.rval + 1] );
972 		return;
973 		}
974 	cerror( "upput" );
975 	}
976 
977 adrput( p ) register NODE *p; {
978 	register int r;
979 	/* output an address, with offsets, from p */
980 
981 	if( p->in.op == FLD ){
982 		p = p->in.left;
983 		}
984 	switch( p->in.op ){
985 
986 	case NAME:
987 		acon( p );
988 		return;
989 
990 	case ICON:
991 		/* addressable value of the constant */
992 		putchar( '$' );
993 		acon( p );
994 		return;
995 
996 	case REG:
997 		putstr( rnames[p->tn.rval] );
998 		return;
999 
1000 	case OREG:
1001 		r = p->tn.rval;
1002 		if( R2TEST(r) ){ /* double indexing */
1003 			register int flags;
1004 
1005 			flags = R2UPK3(r);
1006 			if( flags & 1 ) putchar('*');
1007 			if( flags & 4 ) putchar('-');
1008 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1009 			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
1010 			if( flags & 2 ) putchar('+');
1011 			printf( "[%s]", rnames[R2UPK2(r)] );
1012 			return;
1013 			}
1014 		if( r == AP ){  /* in the argument region */
1015 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1016 			printf( CONFMT, p->tn.lval );
1017 			putstr( "(ap)" );
1018 			return;
1019 			}
1020 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1021 		printf( "(%s)", rnames[p->tn.rval] );
1022 		return;
1023 
1024 	case UNARY MUL:
1025 		/* STARNM or STARREG found */
1026 		if( tshape(p, STARNM) ) {
1027 			putchar( '*' );
1028 			adrput( p->in.left);
1029 			}
1030 		else {	/* STARREG - really auto inc or dec */
1031 			register NODE *q;
1032 
1033 			q = p->in.left;
1034 			if( q->in.right->tn.lval != tlen(p) )
1035 				cerror("adrput: bad auto-increment/decrement");
1036 			printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
1037 				rnames[q->in.left->tn.rval],
1038 				(q->in.op==INCR ? "+" : "") );
1039 			p->in.op = OREG;
1040 			p->tn.rval = q->in.left->tn.rval;
1041 			p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0);
1042 #ifndef FLEXNAMES
1043 			p->in.name[0] = '\0';
1044 #else
1045 			p->in.name = "";
1046 #endif
1047 			tfree(q);
1048 		}
1049 		return;
1050 
1051 	default:
1052 		cerror( "illegal address" );
1053 		return;
1054 
1055 		}
1056 
1057 	}
1058 
1059 acon( p ) register NODE *p; { /* print out a constant */
1060 
1061 	if( p->in.name[0] == '\0' )
1062 		printf( CONFMT, p->tn.lval);
1063 	else {
1064 #ifndef FLEXNAMES
1065 		printf( "%.8s", p->in.name );
1066 #else
1067 		putstr( p->in.name );
1068 #endif
1069 		if( p->tn.lval != 0 ) {
1070 			putchar( '+' );
1071 			printf( CONFMT, p->tn.lval );
1072 			}
1073 		}
1074 	}
1075 
1076 genscall( p, cookie ) register NODE *p; {
1077 	/* structure valued call */
1078 	return( gencall( p, cookie ) );
1079 	}
1080 
1081 /* tbl */
1082 int gc_numbytes;
1083 /* tbl */
1084 
1085 /*ARGSUSED*/
1086 gencall( p, cookie ) register NODE *p; {
1087 	/* generate the call given by p */
1088 	register NODE *p1;
1089 	register int temp, temp1;
1090 	register int m;
1091 
1092 	if( p->in.right ) temp = argsize( p->in.right );
1093 	else temp = 0;
1094 
1095 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1096 		/* set aside room for structure return */
1097 
1098 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1099 		else temp1 = temp;
1100 		}
1101 
1102 	if( temp > maxargs ) maxargs = temp;
1103 	SETOFF(temp1,4);
1104 
1105 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1106 		genargs( p->in.right );
1107 		}
1108 
1109 	p1 = p->in.left;
1110 	if( p1->in.op != ICON ){
1111 		if( p1->in.op != REG ){
1112 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1113 				if( p1->in.op != NAME ){
1114 					order( p1, INAREG );
1115 					}
1116 				}
1117 			}
1118 		}
1119 
1120 /* tbl
1121 	setup gc_numbytes so reference to ZC works */
1122 
1123 	gc_numbytes = temp&(0x3ff);
1124 /* tbl */
1125 
1126 	p->in.op = UNARY CALL;
1127 	m = match( p, INTAREG|INTBREG );
1128 
1129 	/* compensate for deficiency in 'ret' instruction ... wah,kre */
1130 	/* (plus in assignment to gc_numbytes above, for neatness only) */
1131 	if (temp >= 1024)
1132 		printf("	addl2	$%d,sp\n", (temp&(~0x3ff)));
1133 
1134 	return(m != MDONE);
1135 	}
1136 
1137 /* tbl */
1138 char *
1139 ccbranches[] = {
1140 	"eql",
1141 	"neq",
1142 	"leq",
1143 	"lss",
1144 	"geq",
1145 	"gtr",
1146 	"lequ",
1147 	"lssu",
1148 	"gequ",
1149 	"gtru",
1150 	};
1151 /* tbl */
1152 
1153 /*ARGSUSED*/
1154 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1155 
1156 	if( o != 0 && ( o < EQ || o > UGT ) )
1157 		cerror( "bad conditional branch: %s", opst[o] );
1158 	printf( "	j%s	L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
1159 	}
1160 
1161 nextcook( p, cookie ) NODE *p; {
1162 	/* we have failed to match p with cookie; try another */
1163 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1164 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1165 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1166 	return( FORREW );
1167 	}
1168 
1169 /*ARGSUSED*/
1170 lastchance( p, cook ) NODE *p; {
1171 	/* forget it! */
1172 	return(0);
1173 	}
1174 
1175 optim2( p ) register NODE *p; {
1176 	/* do local tree transformations and optimizations */
1177 
1178 	int o;
1179 	int i, mask;
1180 	register NODE *l, *r;
1181 
1182 	switch( o = p->in.op ) {
1183 
1184 	case AND:
1185 		/* commute L and R to eliminate complements and constants */
1186 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
1187 		    l->in.op == COMPL ) {
1188 			p->in.left = p->in.right;
1189 			p->in.right = l;
1190 			}
1191 	case ASG AND:
1192 		/* change meaning of AND to ~R&L - bic on pdp11 */
1193 		r = p->in.right;
1194 		if( r->in.op==ICON && r->in.name[0]==0 ) {
1195 			/* check for degenerate operations */
1196 			l = p->in.left;
1197 			mask = (1 << tlen(l) * SZCHAR) - 1;
1198 			if( ISUNSIGNED(r->in.type) ) {
1199 				i = (~r->tn.lval & mask);
1200 				if( i == 0 ) {
1201 					r->in.op = FREE;
1202 					ncopy(p, l);
1203 					l->in.op = FREE;
1204 					break;
1205 					}
1206 				else if( i == mask )
1207 					goto zero;
1208 				else
1209 					r->tn.lval = i;
1210 				break;
1211 				}
1212 			else if( r->tn.lval == mask &&
1213 				 tlen(l) < SZINT/SZCHAR ) {
1214 				r->in.op = SCONV;
1215 				r->in.left = l;
1216 				r->in.right = 0;
1217 				r->in.type = ENUNSIGN(l->in.type);
1218 				r->in.su = l->in.su > 1 ? l->in.su : 1;
1219 				ncopy(p, r);
1220 				p->in.left = r;
1221 				p->in.type = INT;
1222 				break;
1223 				}
1224 			/* complement constant */
1225 			r->tn.lval = ~r->tn.lval;
1226 			}
1227 		else if( r->in.op==COMPL ) { /* ~~A => A */
1228 			r->in.op = FREE;
1229 			p->in.right = r->in.left;
1230 			}
1231 		else { /* insert complement node */
1232 			p->in.right = l = talloc();
1233 			l->in.op = COMPL;
1234 			l->in.rall = NOPREF;
1235 			l->in.type = r->in.type;
1236 			l->in.left = r;
1237 			l->in.right = NULL;
1238 			}
1239 		break;
1240 
1241 	case SCONV:
1242 		l = p->in.left;
1243 		if( (l->in.type == UCHAR || l->in.type == USHORT) &&
1244 		    (p->in.type == DOUBLE || p->in.type == FLOAT) ) {
1245 			/* we can convert to INT without loss of significance */
1246 			r = talloc();
1247 			*r = *p;
1248 			r->in.type = INT;
1249 			p->in.left = r;
1250 #if !defined(FORT) && !defined(SPRECC)
1251 			/* nothing to be 'gained' by a FLOAT conversion */
1252 			p->in.type = DOUBLE;
1253 #endif
1254 			return;
1255 			}
1256 #if defined(FORT) || defined(SPRECC)
1257 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1258 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1259 			return;
1260 #else
1261 		if( mixtypes(p, l) ) return;
1262 #endif
1263 		if( l->in.op == PCONV )
1264 			return;
1265 		if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
1266 		    l->in.type != INT && l->in.type != UNSIGNED )
1267 			return;
1268 
1269 		/* Only trust it to get it right if the size is the same */
1270 		if( tlen(p) != tlen(l) )
1271 			return;
1272 
1273 		/* clobber conversion */
1274 		if( l->in.op != FLD )
1275 			l->in.type = p->in.type;
1276 		ncopy( p, l );
1277 		l->in.op = FREE;
1278 
1279 		break;
1280 
1281 	case ASSIGN:
1282 		/*
1283 		 * Conversions are equivalent to assignments;
1284 		 * when the two operations are combined,
1285 		 * we can sometimes zap the conversion.
1286 		 */
1287 		r = p->in.right;
1288 		l = p->in.left;
1289 		if ( r->in.op == SCONV &&
1290 		     !mixtypes(l, r) &&
1291 		     l->in.op != FLD &&
1292 		     tlen(l) == tlen(r) ) {
1293 				p->in.right = r->in.left;
1294 				r->in.op = FREE;
1295 			}
1296 		else if( (r->in.type == UCHAR || r->in.type == USHORT) &&
1297 			 (p->in.type == DOUBLE || p->in.type == FLOAT) ) {
1298 			/* we can convert to INT without loss of significance */
1299 			l = talloc();
1300 			l->in.op = SCONV;
1301 			l->in.rall = NOPREF;
1302 			l->in.left = r;
1303 			l->in.right = NULL;
1304 			l->in.type = INT;
1305 			p->in.right = r;
1306 			return;
1307 			}
1308 		break;
1309 
1310 	case ULE:
1311 	case ULT:
1312 	case UGE:
1313 	case UGT:
1314 		p->in.op -= (UGE-GE);
1315 		if( degenerate(p) )
1316 			break;
1317 		p->in.op += (UGE-GE);
1318 		break;
1319 
1320 	case EQ:
1321 	case NE:
1322 	case LE:
1323 	case LT:
1324 	case GE:
1325 	case GT:
1326 		if( p->in.left->in.op == SCONV &&
1327 		    p->in.right->in.op == SCONV ) {
1328 			l = p->in.left;
1329 			r = p->in.right;
1330 			if( l->in.type == DOUBLE &&
1331 			    l->in.left->in.type == FLOAT &&
1332 			    r->in.left->in.type == FLOAT ) {
1333 				/* nuke the conversions */
1334 				p->in.left = l->in.left;
1335 				p->in.right = r->in.left;
1336 				l->in.op = FREE;
1337 				r->in.op = FREE;
1338 				}
1339 			/* more? */
1340 			}
1341 		(void) degenerate(p);
1342 		break;
1343 
1344 	case DIV:
1345 		if( p->in.right->in.op == ICON &&
1346 		    p->in.right->tn.name[0] == '\0' &&
1347 		    ISUNSIGNED(p->in.right->in.type) &&
1348 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1349 			/* easy to do here, harder to do in zzzcode() */
1350 			p->in.op = UGE;
1351 			break;
1352 			}
1353 	case MOD:
1354 	case ASG DIV:
1355 	case ASG MOD:
1356 		/*
1357 		 * optimize DIV and MOD
1358 		 *
1359 		 * basically we spot UCHAR and USHORT and try to do them
1360 		 * as signed ints...  apparently div+mul+sub is always
1361 		 * faster than ediv for finding MOD on the VAX, when
1362 		 * full unsigned MOD isn't needed.
1363 		 *
1364 		 * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub
1365 		 * are faster for unsigned dividend and a constant divisor
1366 		 * in the right range (.5 to 1 of dividend's range for the
1367 		 * first, .333+ to .5 for the second).  full unsigned is
1368 		 * already done cmp+sub in the appropriate case; the
1369 		 * other cases are less common and require more ambition.
1370 		 */
1371 		if( degenerate(p) )
1372 			break;
1373 		l = p->in.left;
1374 		r = p->in.right;
1375 		if( !ISUNSIGNED(r->in.type) ||
1376 		    tlen(l) >= SZINT/SZCHAR ||
1377 		    !(tlen(r) < SZINT/SZCHAR ||
1378 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
1379 			break;
1380 		if( r->in.op == ICON )
1381 			r->tn.type = INT;
1382 		else {
1383 			NODE *t = talloc();
1384 			t->in.left = r;
1385 			r = t;
1386 			r->in.op = SCONV;
1387 			r->in.type = INT;
1388 			r->in.right = 0;
1389 			p->in.right = r;
1390 			}
1391 		if( o == DIV || o == MOD ) {
1392 			NODE *t = talloc();
1393 			t->in.left = l;
1394 			l = t;
1395 			l->in.op = SCONV;
1396 			l->in.type = INT;
1397 			l->in.right = 0;
1398 			p->in.left = l;
1399 			}
1400 		/* handle asgops in table */
1401 		break;
1402 
1403 	case RS:
1404 	case ASG RS:
1405 	case LS:
1406 	case ASG LS:
1407 		/* pick up degenerate shifts */
1408 		l = p->in.left;
1409 		r = p->in.right;
1410 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
1411 			break;
1412 		i = r->tn.lval;
1413 		if( i < 0 )
1414 			/* front end 'fixes' this? */
1415 			if( o == LS || o == ASG LS )
1416 				o += (RS-LS);
1417 			else
1418 				o += (LS-RS);
1419 		if( (o == RS || o == ASG RS) &&
1420 		    !ISUNSIGNED(l->in.type) )
1421 			/* can't optimize signed right shifts */
1422 			break;
1423 		if( o == LS ) {
1424 			if( i < SZINT )
1425 				break;
1426 			}
1427 		else {
1428 			if( i < tlen(l) * SZCHAR )
1429 				break;
1430 			}
1431 	zero:
1432 		if( !asgop( o ) )
1433 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1434 				/* no side effects */
1435 				tfree(l);
1436 				ncopy(p, r);
1437 				r->in.op = FREE;
1438 				p->tn.lval = 0;
1439 				}
1440 			else {
1441 				p->in.op = COMOP;
1442 				r->tn.lval = 0;
1443 				}
1444 		else {
1445 			p->in.op = ASSIGN;
1446 			r->tn.lval = 0;
1447 			}
1448 		break;
1449 		}
1450 	}
1451 
1452 degenerate(p) register NODE *p; {
1453 	int o;
1454 	int result, i;
1455 	int lower, upper;
1456 	register NODE *l, *r;
1457 
1458 	/*
1459 	 * try to keep degenerate comparisons with constants
1460 	 * out of the table.
1461 	 */
1462 	r = p->in.right;
1463 	l = p->in.left;
1464 	if( r->in.op != ICON ||
1465 	    r->tn.name[0] != '\0' ||
1466 	    tlen(l) >= tlen(r) )
1467 		return (0);
1468 	switch( l->in.type ) {
1469 	case CHAR:
1470 		lower = -(1 << SZCHAR - 1);
1471 		upper = (1 << SZCHAR - 1) - 1;
1472 		break;
1473 	case UCHAR:
1474 		lower = 0;
1475 		upper = (1 << SZCHAR) - 1;
1476 		break;
1477 	case SHORT:
1478 		lower = -(1 << SZSHORT - 1);
1479 		upper = (1 << SZSHORT - 1) - 1;
1480 		break;
1481 	case USHORT:
1482 		lower = 0;
1483 		upper = (1 << SZSHORT) - 1;
1484 		break;
1485 	default:
1486 		cerror("unsupported type in degenerate()");
1487 		}
1488 	i = r->tn.lval;
1489 	switch( o = p->in.op ) {
1490 	case DIV:
1491 	case ASG DIV:
1492 	case MOD:
1493 	case ASG MOD:
1494 		/* DIV and MOD work like EQ */
1495 	case EQ:
1496 	case NE:
1497 		if( lower == 0 && (unsigned) i > upper )
1498 			result = o == NE;
1499 		else if( i < lower || i > upper )
1500 			result = o == NE;
1501 		else
1502 			return (0);
1503 		break;
1504 	case LT:
1505 	case GE:
1506 		if( lower == 0 && (unsigned) i > upper )
1507 			result = o == LT;
1508 		else if( i <= lower )
1509 			result = o != LT;
1510 		else if( i > upper )
1511 			result = o == LT;
1512 		else
1513 			return (0);
1514 		break;
1515 	case LE:
1516 	case GT:
1517 		if( lower == 0 && (unsigned) i >= upper )
1518 			result = o == LE;
1519 		else if( i < lower )
1520 			result = o != LE;
1521 		else if( i >= upper )
1522 			result = o == LE;
1523 		else
1524 			return (0);
1525 		break;
1526 	default:
1527 		cerror("unknown op in degenerate()");
1528 		}
1529 
1530 	if( o == MOD || o == ASG MOD ) {
1531 		r->in.op = FREE;
1532 		ncopy(p, l);
1533 		l->in.op = FREE;
1534 		}
1535 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1536 		/* no side effects */
1537 		tfree(l);
1538 		ncopy(p, r);
1539 		r->in.op = FREE;
1540 		p->tn.lval = result;
1541 		}
1542 	else {
1543 		if( o == ASG DIV )
1544 			p->in.op = ASSIGN;
1545 		else {
1546 			p->in.op = COMOP;
1547 			r->tn.type = INT;
1548 			}
1549 		r->tn.lval = result;
1550 		}
1551 	if( logop(o) )
1552 		p->in.type = INT;
1553 
1554 	return (1);
1555 	}
1556 
1557 /* added by jwf */
1558 struct functbl {
1559 	int fop;
1560 	TWORD ftype;
1561 	char *func;
1562 	} opfunc[] = {
1563 	DIV,		TANY,	"udiv",
1564 	MOD,		TANY,	"urem",
1565 	ASG DIV,	TANY,	"audiv",
1566 	ASG MOD,	TANY,	"aurem",
1567 	0,	0,	0 };
1568 
1569 hardops(p)  register NODE *p; {
1570 	/* change hard to do operators into function calls.  */
1571 	register NODE *q;
1572 	register struct functbl *f;
1573 	register o;
1574 	NODE *old,*temp;
1575 
1576 	o = p->in.op;
1577 	if( ! (optype(o)==BITYPE &&
1578 	       (ISUNSIGNED(p->in.left->in.type) ||
1579 		ISUNSIGNED(p->in.right->in.type))) )
1580 		return;
1581 
1582 	for( f=opfunc; f->fop; f++ ) {
1583 		if( o==f->fop ) goto convert;
1584 		}
1585 	return;
1586 
1587 	convert:
1588 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1589 		/* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */
1590 		/* save a subroutine call -- use at most 5 instructions */
1591 		return;
1592 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1593 		/* optim2() will modify the op into an ordinary int op */
1594 		return;
1595 	if( asgop( o ) ) {
1596 		old = NIL;
1597 		switch( p->in.left->in.op ){
1598 		case FLD:
1599 			q = p->in.left->in.left;
1600 			/*
1601 			 * rewrite (lval.fld /= rval); as
1602 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1603 			 * else the compiler will evaluate lval twice.
1604 			 */
1605 			if( q->in.op == UNARY MUL ){
1606 				/* first allocate a temp storage */
1607 				temp = talloc();
1608 				temp->in.op = OREG;
1609 				temp->tn.rval = TMPREG;
1610 				temp->tn.lval = BITOOR(freetemp(1));
1611 				temp->in.type = INCREF(p->in.type);
1612 #ifdef FLEXNAMES
1613 				temp->in.name = "";
1614 #else
1615 				temp->in.name[0] = '\0';
1616 #endif
1617 				old = q->in.left;
1618 				q->in.left = temp;
1619 			}
1620 			/* fall thru ... */
1621 
1622 		case REG:
1623 		case NAME:
1624 		case OREG:
1625 			/* change ASG OP to a simple OP */
1626 			q = talloc();
1627 			q->in.op = NOASG p->in.op;
1628 			q->in.rall = NOPREF;
1629 			q->in.type = p->in.type;
1630 			q->in.left = tcopy(p->in.left);
1631 			q->in.right = p->in.right;
1632 			p->in.op = ASSIGN;
1633 			p->in.right = q;
1634 			p = q;
1635 			f -= 2; /* Note: this depends on the table order */
1636 			/* on the right side only - replace *temp with
1637 			 *(temp = &lval), build the assignment node */
1638 			if( old ){
1639 				temp = q->in.left->in.left; /* the "*" node */
1640 				q = talloc();
1641 				q->in.op = ASSIGN;
1642 				q->in.left = temp->in.left;
1643 				q->in.right = old;
1644 				q->in.type = old->in.type;
1645 #ifdef FLEXNAMES
1646 				q->in.name = "";
1647 #else
1648 				q->in.name[0] = '\0';
1649 #endif
1650 				temp->in.left = q;
1651 			}
1652 			break;
1653 
1654 		case UNARY MUL:
1655 			/* avoid doing side effects twice */
1656 			q = p->in.left;
1657 			p->in.left = q->in.left;
1658 			q->in.op = FREE;
1659 			break;
1660 
1661 		default:
1662 			cerror( "hardops: can't compute & LHS" );
1663 			}
1664 		}
1665 
1666 	/* build comma op for args to function */
1667 	q = talloc();
1668 	q->in.op = CM;
1669 	q->in.rall = NOPREF;
1670 	q->in.type = INT;
1671 	q->in.left = p->in.left;
1672 	q->in.right = p->in.right;
1673 	p->in.op = CALL;
1674 	p->in.right = q;
1675 
1676 	/* put function name in left node of call */
1677 	p->in.left = q = talloc();
1678 	q->in.op = ICON;
1679 	q->in.rall = NOPREF;
1680 	q->in.type = INCREF( FTN + p->in.type );
1681 #ifndef FLEXNAMES
1682 	strcpy( q->in.name, f->func );
1683 #else
1684 	q->in.name = f->func;
1685 #endif
1686 	q->tn.lval = 0;
1687 	q->tn.rval = 0;
1688 
1689 	}
1690 
1691 zappost(p) NODE *p; {
1692 	/* look for ++ and -- operators and remove them */
1693 
1694 	register int o, ty;
1695 	register NODE *q;
1696 	o = p->in.op;
1697 	ty = optype( o );
1698 
1699 	switch( o ){
1700 
1701 	case INCR:
1702 	case DECR:
1703 			q = p->in.left;
1704 			p->in.right->in.op = FREE;  /* zap constant */
1705 			ncopy( p, q );
1706 			q->in.op = FREE;
1707 			return;
1708 
1709 		}
1710 
1711 	if( ty == BITYPE ) zappost( p->in.right );
1712 	if( ty != LTYPE ) zappost( p->in.left );
1713 }
1714 
1715 fixpre(p) NODE *p; {
1716 
1717 	register int o, ty;
1718 	o = p->in.op;
1719 	ty = optype( o );
1720 
1721 	switch( o ){
1722 
1723 	case ASG PLUS:
1724 			p->in.op = PLUS;
1725 			break;
1726 	case ASG MINUS:
1727 			p->in.op = MINUS;
1728 			break;
1729 		}
1730 
1731 	if( ty == BITYPE ) fixpre( p->in.right );
1732 	if( ty != LTYPE ) fixpre( p->in.left );
1733 }
1734 
1735 /*ARGSUSED*/
1736 NODE * addroreg(l) NODE *l;
1737 				/* OREG was built in clocal()
1738 				 * for an auto or formal parameter
1739 				 * now its address is being taken
1740 				 * local code must unwind it
1741 				 * back to PLUS/MINUS REG ICON
1742 				 * according to local conventions
1743 				 */
1744 {
1745 	cerror("address of OREG taken");
1746 	/*NOTREACHED*/
1747 }
1748 
1749 
1750 
1751 # ifndef ONEPASS
1752 main( argc, argv ) char *argv[]; {
1753 	return( mainp2( argc, argv ) );
1754 	}
1755 # endif
1756 
1757 strip(p) register NODE *p; {
1758 	NODE *q;
1759 
1760 	/* strip nodes off the top when no side effects occur */
1761 	for( ; ; ) {
1762 		switch( p->in.op ) {
1763 		case SCONV:			/* remove lint tidbits */
1764 			q = p->in.left;
1765 			ncopy( p, q );
1766 			q->in.op = FREE;
1767 			break;
1768 		/* could probably add a few more here */
1769 		default:
1770 			return;
1771 			}
1772 		}
1773 	}
1774 
1775 myreader(p) register NODE *p; {
1776 	strip( p );		/* strip off operations with no side effects */
1777 	canon( p );		/* expands r-vals for fields */
1778 	walkf( p, hardops );	/* convert ops to function calls */
1779 	walkf( p, optim2 );
1780 	}
1781