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