xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32931)
1 # ifndef lint
2 static char *sccsid ="@(#)local2.c	1.25 (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->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 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
829 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
830 		}
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;
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 			if( (i = (r->tn.lval & (1 << tlen(l) * SZCHAR) - 1)) == 0 )
1203 				goto zero;
1204 			else if( i == (1 << tlen(l) * SZCHAR) - 1 ) {
1205 				r->in.op = FREE;
1206 				ncopy(p, l);
1207 				l->in.op = FREE;
1208 				break;
1209 				}
1210 			/* complement constant */
1211 			r->tn.lval = ~r->tn.lval;
1212 			}
1213 		else if( r->in.op==COMPL ) { /* ~~A => A */
1214 			r->in.op = FREE;
1215 			p->in.right = r->in.left;
1216 			}
1217 		else { /* insert complement node */
1218 			p->in.right = l = talloc();
1219 			l->in.op = COMPL;
1220 			l->in.rall = NOPREF;
1221 			l->in.type = r->in.type;
1222 			l->in.left = r;
1223 			l->in.right = NULL;
1224 			}
1225 		break;
1226 
1227 	case SCONV:
1228 		l = p->in.left;
1229 #if defined(FORT) || defined(SPRECC)
1230 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1231 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1232 			return;
1233 #else
1234 		if( mixtypes(p, l) ) return;
1235 #endif
1236 		if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
1237 			return;
1238 
1239 		/* Only trust it to get it right if the size is the same */
1240 		if( tlen(p) != tlen(l) )
1241 			return;
1242 
1243 		/* clobber conversion */
1244 		if( l->in.op != FLD )
1245 			l->in.type = p->in.type;
1246 		ncopy( p, l );
1247 		l->in.op = FREE;
1248 
1249 		break;
1250 
1251 	case ASSIGN:
1252 		/*
1253 		 * Conversions are equivalent to assignments;
1254 		 * when the two operations are combined,
1255 		 * we can sometimes zap the conversion.
1256 		 */
1257 		r = p->in.right;
1258 		l = p->in.left;
1259 		if ( r->in.op == SCONV &&
1260 		     !mixtypes(l, r) &&
1261 		     l->in.op != FLD &&
1262 		     tlen(l) == tlen(r) ) {
1263 				p->in.right = r->in.left;
1264 				r->in.op = FREE;
1265 			}
1266 		break;
1267 
1268 	case ULE:
1269 	case ULT:
1270 	case UGE:
1271 	case UGT:
1272 		p->in.op -= (UGE-GE);
1273 		if( degenerate(p) )
1274 			break;
1275 		p->in.op += (UGE-GE);
1276 		break;
1277 
1278 	case EQ:
1279 	case NE:
1280 	case LE:
1281 	case LT:
1282 	case GE:
1283 	case GT:
1284 		(void) degenerate(p);
1285 		break;
1286 
1287 	case DIV:
1288 		if( p->in.right->in.op == ICON &&
1289 		    p->in.right->tn.name[0] == '\0' &&
1290 		    ISUNSIGNED(p->in.right->in.type) &&
1291 		    (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1292 			/* easy to do here, harder to do in zzzcode() */
1293 			p->in.op = UGE;
1294 			break;
1295 			}
1296 	case MOD:
1297 	case ASG DIV:
1298 	case ASG MOD:
1299 		/*
1300 		 * optimize DIV and MOD
1301 		 *
1302 		 * basically we spot UCHAR and USHORT and try to do them
1303 		 * as signed ints...  apparently div+mul+sub is always
1304 		 * faster than ediv for finding MOD on the VAX, when
1305 		 * full unsigned MOD isn't needed.
1306 		 *
1307 		 * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub
1308 		 * are faster for unsigned dividend and a constant divisor
1309 		 * in the right range (.5 to 1 of dividend's range for the
1310 		 * first, .333+ to .5 for the second).  full unsigned is
1311 		 * already done cmp+sub in the appropriate case; the
1312 		 * other cases are less common and require more ambition.
1313 		 */
1314 		if( degenerate(p) )
1315 			break;
1316 		l = p->in.left;
1317 		r = p->in.right;
1318 		if( !ISUNSIGNED(r->in.type) ||
1319 		    tlen(l) >= SZINT/SZCHAR ||
1320 		    !(tlen(r) < SZINT/SZCHAR ||
1321 		      (r->in.op == ICON && r->tn.name[0] == '\0')) )
1322 			break;
1323 		if( r->in.op == ICON )
1324 			r->tn.type = INT;
1325 		else {
1326 			NODE *t = talloc();
1327 			t->in.left = r;
1328 			r = t;
1329 			r->in.op = SCONV;
1330 			r->in.type = INT;
1331 			r->in.right = 0;
1332 			p->in.right = r;
1333 			}
1334 		if( o == DIV || o == MOD ) {
1335 			NODE *t = talloc();
1336 			t->in.left = l;
1337 			l = t;
1338 			l->in.op = SCONV;
1339 			l->in.type = INT;
1340 			l->in.right = 0;
1341 			p->in.left = l;
1342 			}
1343 		/* handle asgops in table */
1344 		break;
1345 
1346 	case RS:
1347 	case ASG RS:
1348 	case LS:
1349 	case ASG LS:
1350 		/* pick up degenerate shifts */
1351 		l = p->in.left;
1352 		r = p->in.right;
1353 		if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
1354 			break;
1355 		i = r->tn.lval;
1356 		if( i < 0 )
1357 			/* front end 'fixes' this? */
1358 			if( o == LS || o == ASG LS )
1359 				o += (RS-LS);
1360 			else
1361 				o += (LS-RS);
1362 		if( (o == RS || o == ASG RS) &&
1363 		    !ISUNSIGNED(l->in.type) )
1364 			/* can't optimize signed right shifts */
1365 			break;
1366 		if( i < tlen(l) * SZCHAR )
1367 			break;
1368 	zero:
1369 		if( !asgop( o ) )
1370 			if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1371 				/* no side effects */
1372 				l->in.op = FREE;
1373 				ncopy(p, r);
1374 				r->in.op = FREE;
1375 				p->tn.lval = 0;
1376 				}
1377 			else {
1378 				p->in.op = COMOP;
1379 				r->in.lval = 0;
1380 				}
1381 		else {
1382 			p->in.op = ASSIGN;
1383 			r->tn.lval = 0;
1384 			}
1385 		break;
1386 		}
1387 	}
1388 
1389 degenerate(p) register NODE *p; {
1390 	int o;
1391 	int result, i;
1392 	int lower, upper;
1393 	register NODE *l, *r;
1394 
1395 	/*
1396 	 * try to keep degenerate comparisons with constants
1397 	 * out of the table.
1398 	 */
1399 	r = p->in.right;
1400 	l = p->in.left;
1401 	if( r->in.op != ICON ||
1402 	    r->tn.name[0] != '\0' ||
1403 	    tlen(l) >= tlen(r) )
1404 		return (0);
1405 	switch( l->in.type ) {
1406 	case CHAR:
1407 		lower = -(1 << SZCHAR - 1);
1408 		upper = (1 << SZCHAR - 1) - 1;
1409 		break;
1410 	case UCHAR:
1411 		lower = 0;
1412 		upper = (1 << SZCHAR) - 1;
1413 		break;
1414 	case SHORT:
1415 		lower = -(1 << SZSHORT - 1);
1416 		upper = (1 << SZSHORT - 1) - 1;
1417 		break;
1418 	case USHORT:
1419 		lower = 0;
1420 		upper = (1 << SZSHORT) - 1;
1421 		break;
1422 	default:
1423 		cerror("unsupported OPLOG in optim2");
1424 		}
1425 	i = r->tn.lval;
1426 	switch( o = p->in.op ) {
1427 	case DIV:
1428 	case ASG DIV:
1429 	case MOD:
1430 	case ASG MOD:
1431 		/* DIV and MOD work like EQ */
1432 	case EQ:
1433 	case NE:
1434 		if( lower == 0 && (unsigned) i > upper )
1435 			result = o == NE;
1436 		else if( i < lower || i > upper )
1437 			result = o == NE;
1438 		else
1439 			return (0);
1440 		break;
1441 	case LT:
1442 	case GE:
1443 		if( lower == 0 && (unsigned) i > upper )
1444 			result = o == LT;
1445 		else if( i <= lower )
1446 			result = o != LT;
1447 		else if( i > upper )
1448 			result = o == LT;
1449 		else
1450 			return (0);
1451 		break;
1452 	case LE:
1453 	case GT:
1454 		if( lower == 0 && (unsigned) i >= upper )
1455 			result = o == LE;
1456 		else if( i < lower )
1457 			result = o != LE;
1458 		else if( i >= upper )
1459 			result = o == LE;
1460 		else
1461 			return (0);
1462 		break;
1463 	default:
1464 		cerror("unknown op in degenerate()");
1465 		}
1466 
1467 	if( o == MOD || o == ASG MOD ) {
1468 		r->in.op = FREE;
1469 		ncopy(p, l);
1470 		l->in.op = FREE;
1471 		}
1472 	else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1473 		/* no side effects */
1474 		l->in.op = FREE;
1475 		ncopy(p, r);
1476 		r->in.op = FREE;
1477 		p->tn.lval = result;
1478 		}
1479 	else {
1480 		if( o == ASG DIV )
1481 			p->in.op = ASSIGN;
1482 		else {
1483 			p->in.op = COMOP;
1484 			r->tn.type = INT;
1485 			}
1486 		r->tn.lval = result;
1487 		}
1488 	if( logop(o) )
1489 		p->in.type = INT;
1490 
1491 	return (1);
1492 	}
1493 
1494 /*ARGSUSED*/
1495 NODE * addroreg(l) NODE *l;
1496 				/* OREG was built in clocal()
1497 				 * for an auto or formal parameter
1498 				 * now its address is being taken
1499 				 * local code must unwind it
1500 				 * back to PLUS/MINUS REG ICON
1501 				 * according to local conventions
1502 				 */
1503 {
1504 	cerror("address of OREG taken");
1505 	/*NOTREACHED*/
1506 }
1507 
1508 
1509 
1510 # ifndef ONEPASS
1511 main( argc, argv ) char *argv[]; {
1512 	return( mainp2( argc, argv ) );
1513 	}
1514 # endif
1515 
1516 
1517 /* added by jwf */
1518 struct functbl {
1519 	int fop;
1520 	TWORD ftype;
1521 	char *func;
1522 	} opfunc[] = {
1523 	DIV,		TANY,	"udiv",
1524 	MOD,		TANY,	"urem",
1525 	ASG DIV,	TANY,	"audiv",
1526 	ASG MOD,	TANY,	"aurem",
1527 	0,	0,	0 };
1528 
1529 hardops(p)  register NODE *p; {
1530 	/* change hard to do operators into function calls.  */
1531 	register NODE *q;
1532 	register struct functbl *f;
1533 	register o;
1534 	NODE *old,*temp;
1535 
1536 	o = p->in.op;
1537 	if( ! (optype(o)==BITYPE &&
1538 	       (ISUNSIGNED(p->in.left->in.type) ||
1539 		ISUNSIGNED(p->in.right->in.type))) )
1540 		return;
1541 
1542 	for( f=opfunc; f->fop; f++ ) {
1543 		if( o==f->fop ) goto convert;
1544 		}
1545 	return;
1546 
1547 	convert:
1548 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1549 		/* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */
1550 		/* save a subroutine call -- use at most 5 instructions */
1551 		return;
1552 	if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1553 		/* optim2() will modify the op into an ordinary int op */
1554 		return;
1555 	if( asgop( o ) ) {
1556 		old = NIL;
1557 		switch( p->in.left->in.op ){
1558 		case FLD:
1559 			q = p->in.left->in.left;
1560 			/*
1561 			 * rewrite (lval.fld /= rval); as
1562 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1563 			 * else the compiler will evaluate lval twice.
1564 			 */
1565 			if( q->in.op == UNARY MUL ){
1566 				/* first allocate a temp storage */
1567 				temp = talloc();
1568 				temp->in.op = OREG;
1569 				temp->tn.rval = TMPREG;
1570 				temp->tn.lval = BITOOR(freetemp(1));
1571 				temp->in.type = INCREF(p->in.type);
1572 #ifdef FLEXNAMES
1573 				temp->in.name = "";
1574 #else
1575 				temp->in.name[0] = '\0';
1576 #endif
1577 				old = q->in.left;
1578 				q->in.left = temp;
1579 			}
1580 			/* fall thru ... */
1581 
1582 		case REG:
1583 		case NAME:
1584 		case OREG:
1585 			/* change ASG OP to a simple OP */
1586 			q = talloc();
1587 			q->in.op = NOASG p->in.op;
1588 			q->in.rall = NOPREF;
1589 			q->in.type = p->in.type;
1590 			q->in.left = tcopy(p->in.left);
1591 			q->in.right = p->in.right;
1592 			p->in.op = ASSIGN;
1593 			p->in.right = q;
1594 			p = q;
1595 			f -= 2; /* Note: this depends on the table order */
1596 			/* on the right side only - replace *temp with
1597 			 *(temp = &lval), build the assignment node */
1598 			if( old ){
1599 				temp = q->in.left->in.left; /* the "*" node */
1600 				q = talloc();
1601 				q->in.op = ASSIGN;
1602 				q->in.left = temp->in.left;
1603 				q->in.right = old;
1604 				q->in.type = old->in.type;
1605 #ifdef FLEXNAMES
1606 				q->in.name = "";
1607 #else
1608 				q->in.name[0] = '\0';
1609 #endif
1610 				temp->in.left = q;
1611 			}
1612 			break;
1613 
1614 		case UNARY MUL:
1615 			/* avoid doing side effects twice */
1616 			q = p->in.left;
1617 			p->in.left = q->in.left;
1618 			q->in.op = FREE;
1619 			break;
1620 
1621 		default:
1622 			cerror( "hardops: can't compute & LHS" );
1623 			}
1624 		}
1625 
1626 	/* build comma op for args to function */
1627 	q = talloc();
1628 	q->in.op = CM;
1629 	q->in.rall = NOPREF;
1630 	q->in.type = INT;
1631 	q->in.left = p->in.left;
1632 	q->in.right = p->in.right;
1633 	p->in.op = CALL;
1634 	p->in.right = q;
1635 
1636 	/* put function name in left node of call */
1637 	p->in.left = q = talloc();
1638 	q->in.op = ICON;
1639 	q->in.rall = NOPREF;
1640 	q->in.type = INCREF( FTN + p->in.type );
1641 #ifndef FLEXNAMES
1642 	strcpy( q->in.name, f->func );
1643 #else
1644 	q->in.name = f->func;
1645 #endif
1646 	q->tn.lval = 0;
1647 	q->tn.rval = 0;
1648 
1649 	}
1650 
1651 zappost(p) NODE *p; {
1652 	/* look for ++ and -- operators and remove them */
1653 
1654 	register o, ty;
1655 	register NODE *q;
1656 	o = p->in.op;
1657 	ty = optype( o );
1658 
1659 	switch( o ){
1660 
1661 	case INCR:
1662 	case DECR:
1663 			q = p->in.left;
1664 			p->in.right->in.op = FREE;  /* zap constant */
1665 			ncopy( p, q );
1666 			q->in.op = FREE;
1667 			return;
1668 
1669 		}
1670 
1671 	if( ty == BITYPE ) zappost( p->in.right );
1672 	if( ty != LTYPE ) zappost( p->in.left );
1673 }
1674 
1675 fixpre(p) NODE *p; {
1676 
1677 	register o, ty;
1678 	o = p->in.op;
1679 	ty = optype( o );
1680 
1681 	switch( o ){
1682 
1683 	case ASG PLUS:
1684 			p->in.op = PLUS;
1685 			break;
1686 	case ASG MINUS:
1687 			p->in.op = MINUS;
1688 			break;
1689 		}
1690 
1691 	if( ty == BITYPE ) fixpre( p->in.right );
1692 	if( ty != LTYPE ) fixpre( p->in.left );
1693 }
1694 
1695 strip(p) register NODE *p; {
1696 	NODE *q;
1697 
1698 	/* strip nodes off the top when no side effects occur */
1699 	for( ; ; ) {
1700 		switch( p->in.op ) {
1701 		case SCONV:			/* remove lint tidbits */
1702 			q = p->in.left;
1703 			ncopy( p, q );
1704 			q->in.op = FREE;
1705 			break;
1706 		/* could probably add a few more here */
1707 		default:
1708 			return;
1709 			}
1710 		}
1711 	}
1712 
1713 myreader(p) register NODE *p; {
1714 	strip( p );		/* strip off operations with no side effects */
1715 	canon( p );		/* expands r-vals for fields */
1716 	walkf( p, hardops );	/* convert ops to function calls */
1717 	walkf( p, optim2 );
1718 	/* jwf toff = 0;  /* stack offset swindle */
1719 	}
1720