xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32926)
1 # ifndef lint
2 static char *sccsid ="@(#)local2.c	1.20 (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 'B':	/* get oreg value in temp register for left shift */
418 		{
419 		register NODE *r;
420 		if (xdebug) eprint(p, 0, &val, &val);
421 		r = p->in.right;
422 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
423 			putstr("movl");
424 		else {
425 			putstr("cvt");
426 			prtype(r);
427 			putchar('l');
428 			}
429 		return;
430 		}
431 
432 	case 'C':	/* num words pushed on arg stack */
433 		{
434 		extern int gc_numbytes;
435 		extern int xdebug;
436 
437 		if (xdebug) printf("->%d<-",gc_numbytes);
438 
439 		printf("$%d", gc_numbytes/(SZLONG/SZCHAR) );
440 		return;
441 		}
442 
443 	case 'D':	/* INCR and DECR */
444 		zzzcode(p->in.left, 'A');
445 		putchar('\n');
446 		putchar('\t');
447 
448 	case 'E':	/* INCR and DECR, FOREFF */
449 		if (p->in.right->tn.lval == 1)
450 			{
451 			putstr( p->in.op == INCR ? "inc" : "dec" );
452 			prtype(p->in.left);
453 			putchar('\t');
454 			adrput(p->in.left);
455 			return;
456 			}
457 		putstr( p->in.op == INCR ? "add" : "sub" );
458 		prtype(p->in.left);
459 		putchar('2');
460 		putchar('\t');
461 		adrput(p->in.right);
462 		putchar(',');
463 		adrput(p->in.left);
464 		return;
465 
466 	case 'F':	/* register type of right operand */
467 		{
468 		register NODE *n;
469 		extern int xdebug;
470 		register int ty;
471 
472 		n = getlr( p, 'R' );
473 		ty = n->in.type;
474 
475 		if (xdebug) printf("->%d<-", ty);
476 
477 		if ( ty==DOUBLE) putchar('d');
478 		else if ( ty==FLOAT ) putchar('f');
479 		else putchar('l');
480 		return;
481 		}
482 
483 	case 'L':	/* type of left operand */
484 	case 'R':	/* type of right operand */
485 		{
486 		register NODE *n;
487 		extern int xdebug;
488 
489 		n = getlr( p, c );
490 		if (xdebug) printf("->%d<-", n->in.type);
491 
492 		prtype(n);
493 		return;
494 		}
495 
496 	case 'Z':	/* complement mask for bit instr */
497 		printf("$%ld", ~p->in.right->tn.lval);
498 		return;
499 
500 	case 'U':	/* 32 - n, for unsigned right shifts */
501 		printf("$%d", 32 - p->in.right->tn.lval );
502 		return;
503 
504 	case 'T':	/* rounded structure length for arguments */
505 		{
506 		int size;
507 
508 		size = p->stn.stsize;
509 		SETOFF( size, 4);
510 		printf("$%d", size);
511 		return;
512 		}
513 
514 	case 'S':  /* structure assignment */
515 		{
516 			register NODE *l, *r;
517 			register size;
518 
519 			if( p->in.op == STASG ){
520 				l = p->in.left;
521 				r = p->in.right;
522 
523 				}
524 			else if( p->in.op == STARG ){  /* store an arg into a temporary */
525 				r = p->in.left;
526 				}
527 			else cerror( "STASG bad" );
528 
529 			if( r->in.op == ICON ) r->in.op = NAME;
530 			else if( r->in.op == REG ) r->in.op = OREG;
531 			else if( r->in.op != OREG ) cerror( "STASG-r" );
532 
533 			size = p->stn.stsize;
534 
535 			if( size <= 0 || size > 65535 )
536 				cerror("structure size <0=0 or >65535");
537 
538 			switch(size) {
539 				case 1:
540 					putstr("	movb	");
541 					break;
542 				case 2:
543 					putstr("	movw	");
544 					break;
545 				case 4:
546 					putstr("	movl	");
547 					break;
548 				case 8:
549 					putstr("	movq	");
550 					break;
551 				default:
552 					printf("	movc3	$%d,", size);
553 					break;
554 			}
555 			adrput(r);
556 			if( p->in.op == STASG ){
557 				putchar(',');
558 				adrput(l);
559 				putchar('\n');
560 				}
561 			else
562 				putstr(",(sp)\n");
563 
564 			if( r->in.op == NAME ) r->in.op = ICON;
565 			else if( r->in.op == OREG ) r->in.op = REG;
566 
567 			}
568 		break;
569 
570 	default:
571 		cerror( "illegal zzzcode" );
572 		}
573 	}
574 
575 /*
576  * collapsible(dest, src) -- if a conversion with a register destination
577  *	can be accomplished in one instruction, return the type of src
578  *	that will do the job correctly; otherwise return 0.  Note that
579  *	a register must always end up having type INT or UNSIGNED.
580  */
581 int
582 collapsible(dest, src)
583 NODE *dest, *src;
584 {
585 	int st = src->in.type;
586 	int dt = dest->in.type;
587 	int newt = 0;
588 
589 	/*
590 	 * Are there side effects of evaluating src?
591 	 * If the derived type will not be the same size as src,
592 	 * we may have to use two steps.
593 	 */
594 	if (tlen(src) > tlen(dest)) {
595 		if (tshape(src, STARREG))
596 			return (0);
597 		if (src->in.op == OREG && R2TEST(src->tn.rval))
598 			return (0);
599 		}
600 
601 	/*
602 	 * Can we get an object of dest's type by punning src?
603 	 * Praises be to great Cthulhu for little-endian machines...
604 	 */
605 	if (st == CHAR && dt == USHORT)
606 		/*
607 		 * Special case -- we must sign-extend to 16 bits.
608 		 */
609 		return (0);
610 
611 	if (tlen(src) < tlen(dest))
612 		newt = st;
613 	else
614 		newt = dt;
615 
616 	return (newt);
617 	}
618 
619 rmove( rt, rs, t ) TWORD t; {
620 	printf( "	%s	%s,%s\n",
621 #ifdef FORT
622 		!Oflag ? (t==DOUBLE ? "movq" : "movl") :
623 #endif
624 		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
625 		rnames[rs], rnames[rt] );
626 	}
627 
628 struct respref
629 respref[] = {
630 	INTAREG|INTBREG,	INTAREG|INTBREG,
631 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
632 	INTEMP,	INTEMP,
633 	FORARG,	FORARG,
634 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
635 	0,	0 };
636 
637 setregs(){ /* set up temporary registers */
638 	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
639 	;
640 	}
641 
642 /*ARGSUSED*/
643 rewfld( p ) NODE *p; {
644 	return(1);
645 	}
646 
647 /*ARGSUSED*/
648 callreg(p) NODE *p; {
649 	return( R0 );
650 	}
651 
652 base( p ) register NODE *p; {
653 	register int o = p->in.op;
654 
655 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
656 	if( o==REG ) return( p->tn.rval );
657     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
658 		return( p->in.left->tn.rval );
659     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
660 		return( p->tn.rval + 0200*1 );
661 	if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 );
662 	if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 );
663 	if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG
664 	  && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
665 		return( p->in.left->in.left->tn.rval + 0200*(1+2) );
666 	return( -1 );
667 	}
668 
669 offset( p, tyl ) register NODE *p; int tyl; {
670 
671 	if( tyl==1 &&
672 	    p->in.op==REG &&
673 	    (p->in.type==INT || p->in.type==UNSIGNED) )
674 		return( p->tn.rval );
675 	if( p->in.op==LS &&
676 	    p->in.left->in.op==REG &&
677 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
678 	    p->in.right->in.op==ICON &&
679 	    p->in.right->in.name[0]=='\0' &&
680 	    (1<<p->in.right->tn.lval)==tyl)
681 		return( p->in.left->tn.rval );
682 	if( tyl==2 &&
683 	    p->in.op==PLUS &&
684 	    (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
685 	    p->in.left->in.op==REG &&
686 	    p->in.right->in.op==REG &&
687 	    p->in.left->tn.rval==p->in.right->tn.rval )
688 		return( p->in.left->tn.rval );
689 	return( -1 );
690 	}
691 
692 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
693 	register NODE *t;
694 	NODE *f;
695 
696 	p->in.op = OREG;
697 	f = p->in.left; 	/* have to free this subtree later */
698 
699 	/* init base */
700 	switch (q->in.op) {
701 		case ICON:
702 		case REG:
703 		case OREG:
704 			t = q;
705 			break;
706 
707 		case MINUS:
708 			q->in.right->tn.lval = -q->in.right->tn.lval;
709 		case PLUS:
710 			t = q->in.right;
711 			break;
712 
713 		case INCR:
714 		case ASG MINUS:
715 			t = q->in.left;
716 			break;
717 
718 		case UNARY MUL:
719 			t = q->in.left->in.left;
720 			break;
721 
722 		default:
723 			cerror("illegal makeor2");
724 	}
725 
726 	p->tn.lval = t->tn.lval;
727 #ifndef FLEXNAMES
728 	{
729 		register int i;
730 		for(i=0; i<NCHNAM; ++i)
731 			p->in.name[i] = t->in.name[i];
732 	}
733 #else
734 	p->in.name = t->in.name;
735 #endif
736 
737 	/* init offset */
738 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
739 
740 	tfree(f);
741 	return;
742 	}
743 
744 canaddr( p ) NODE *p; {
745 	register int o = p->in.op;
746 
747 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
748 	return(0);
749 	}
750 
751 flshape( p ) register NODE *p; {
752 	return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON ||
753 		(p->in.op == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) );
754 	}
755 
756 /* INTEMP shapes must not contain any temporary registers */
757 shtemp( p ) register NODE *p; {
758 	int r;
759 
760 	if( p->in.op == STARG ) p = p->in.left;
761 
762 	switch (p->in.op) {
763 	case REG:
764 		return( !istreg(p->tn.rval) );
765 	case OREG:
766 		r = p->tn.rval;
767 		if( R2TEST(r) ) {
768 			if( istreg(R2UPK1(r)) )
769 				return(0);
770 			r = R2UPK2(r);
771 			}
772 		return( !istreg(r) );
773 /*
774 	case UNARY MUL:
775 		p = p->in.left;
776 		return( p->in.op != UNARY MUL && shtemp(p) );
777 */
778 		}
779 
780 	if( optype( p->in.op ) != LTYPE ) return(0);
781 	return(1);
782 	}
783 
784 shumul( p ) register NODE *p; {
785 	register o;
786 	extern int xdebug;
787 
788 	if (xdebug) {
789 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
790 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
791 		}
792 
793 
794 	o = p->in.op;
795 	if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
796 
797 	if( ( o == INCR || o == ASG MINUS ) &&
798 	    ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) &&
799 	    p->in.right->in.name[0] == '\0' )
800 		{
801 		switch (p->in.type)
802 			{
803 			case CHAR|PTR:
804 			case UCHAR|PTR:
805 				o = 1;
806 				break;
807 
808 			case SHORT|PTR:
809 			case USHORT|PTR:
810 				o = 2;
811 				break;
812 
813 			case INT|PTR:
814 			case UNSIGNED|PTR:
815 			case LONG|PTR:
816 			case ULONG|PTR:
817 			case FLOAT|PTR:
818 				o = 4;
819 				break;
820 
821 			case DOUBLE|PTR:
822 				o = 8;
823 				break;
824 
825 			default:
826 				if ( ISPTR(p->in.type) &&
827 				     ISPTR(DECREF(p->in.type)) ) {
828 					o = 4;
829 					break;
830 					}
831 				else return(0);
832 			}
833 		return( p->in.right->tn.lval == o ? STARREG : 0);
834 		}
835 
836 	return( 0 );
837 	}
838 
839 adrcon( val ) CONSZ val; {
840 	putchar( '$' );
841 	printf( CONFMT, val );
842 	}
843 
844 conput( p ) register NODE *p; {
845 	switch( p->in.op ){
846 
847 	case ICON:
848 		acon( p );
849 		return;
850 
851 	case REG:
852 		putstr( rnames[p->tn.rval] );
853 		return;
854 
855 	default:
856 		cerror( "illegal conput" );
857 		}
858 	}
859 
860 /*ARGSUSED*/
861 insput( p ) NODE *p; {
862 	cerror( "insput" );
863 	}
864 
865 /*ARGSUSED*/
866 upput( p, off ) NODE *p; int off; {
867 	cerror( "upput" );
868 	}
869 
870 adrput( p ) register NODE *p; {
871 	register int r;
872 	/* output an address, with offsets, from p */
873 
874 	if( p->in.op == FLD ){
875 		p = p->in.left;
876 		}
877 	switch( p->in.op ){
878 
879 	case NAME:
880 		acon( p );
881 		return;
882 
883 	case ICON:
884 		/* addressable value of the constant */
885 		putchar( '$' );
886 		acon( p );
887 		return;
888 
889 	case REG:
890 		putstr( rnames[p->tn.rval] );
891 		return;
892 
893 	case OREG:
894 		r = p->tn.rval;
895 		if( R2TEST(r) ){ /* double indexing */
896 			register int flags;
897 
898 			flags = R2UPK3(r);
899 			if( flags & 1 ) putchar('*');
900 			if( flags & 4 ) putchar('-');
901 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
902 			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
903 			if( flags & 2 ) putchar('+');
904 			printf( "[%s]", rnames[R2UPK2(r)] );
905 			return;
906 			}
907 		if( r == AP ){  /* in the argument region */
908 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
909 			printf( CONFMT, p->tn.lval );
910 			putstr( "(ap)" );
911 			return;
912 			}
913 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
914 		printf( "(%s)", rnames[p->tn.rval] );
915 		return;
916 
917 	case UNARY MUL:
918 		/* STARNM or STARREG found */
919 		if( tshape(p, STARNM) ) {
920 			putchar( '*' );
921 			adrput( p->in.left);
922 			}
923 		else {	/* STARREG - really auto inc or dec */
924 			register NODE *q;
925 
926 /* tbl
927 			p = p->in.left;
928 			p->in.left->in.op = OREG;
929 			if( p->in.op == INCR ) {
930 				adrput( p->in.left );
931 				putchar( '+' );
932 				}
933 			else {
934 				putchar( '-' );
935 				adrput( p->in.left );
936 				}
937    tbl */
938 			q = p->in.left;
939 			if( q->in.right->tn.lval != tlen(p) )
940 				cerror("adrput: bad auto-increment/decrement");
941 			printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
942 				rnames[q->in.left->tn.rval],
943 				(q->in.op==INCR ? "+" : "") );
944 			p->in.op = OREG;
945 			p->tn.rval = q->in.left->tn.rval;
946 			p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0);
947 #ifndef FLEXNAMES
948 			p->in.name[0] = '\0';
949 #else
950 			p->in.name = "";
951 #endif
952 			tfree(q);
953 		}
954 		return;
955 
956 	default:
957 		cerror( "illegal address" );
958 		return;
959 
960 		}
961 
962 	}
963 
964 acon( p ) register NODE *p; { /* print out a constant */
965 
966 	if( p->in.name[0] == '\0' ){
967 		printf( CONFMT, p->tn.lval);
968 		}
969 	else if( p->tn.lval == 0 ) {
970 #ifndef FLEXNAMES
971 		printf( "%.8s", p->in.name );
972 #else
973 		putstr( p->in.name );
974 #endif
975 		}
976 	else {
977 #ifndef FLEXNAMES
978 		printf( "%.8s+", p->in.name );
979 #else
980 		printf( "%s+", p->in.name );
981 #endif
982 		printf( CONFMT, p->tn.lval );
983 		}
984 	}
985 
986 /*
987 aacon( p ) register NODE *p; { /* print out a constant */
988 /*
989 
990 	if( p->in.name[0] == '\0' ){
991 		printf( CONFMT, p->tn.lval);
992 		return( 0 );
993 		}
994 	else if( p->tn.lval == 0 ) {
995 #ifndef FLEXNAMES
996 		printf( "$%.8s", p->in.name );
997 #else
998 		printf( "$%s", p->in.name );
999 #endif
1000 		return( 1 );
1001 		}
1002 	else {
1003 		printf( "$(" );
1004 		printf( CONFMT, p->tn.lval );
1005 		printf( "+" );
1006 #ifndef FLEXNAMES
1007 		printf( "%.8s)", p->in.name );
1008 #else
1009 		printf( "%s)", p->in.name );
1010 #endif
1011 		return(1);
1012 		}
1013 	}
1014  */
1015 
1016 genscall( p, cookie ) register NODE *p; {
1017 	/* structure valued call */
1018 	return( gencall( p, cookie ) );
1019 	}
1020 
1021 /* tbl */
1022 int gc_numbytes;
1023 /* tbl */
1024 
1025 /*ARGSUSED*/
1026 gencall( p, cookie ) register NODE *p; {
1027 	/* generate the call given by p */
1028 	register NODE *p1;
1029 	register temp, temp1;
1030 	register m;
1031 
1032 	if( p->in.right ) temp = argsize( p->in.right );
1033 	else temp = 0;
1034 
1035 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1036 		/* set aside room for structure return */
1037 
1038 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1039 		else temp1 = temp;
1040 		}
1041 
1042 	if( temp > maxargs ) maxargs = temp;
1043 	SETOFF(temp1,4);
1044 
1045 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1046 		genargs( p->in.right );
1047 		}
1048 
1049 	p1 = p->in.left;
1050 	if( p1->in.op != ICON ){
1051 		if( p1->in.op != REG ){
1052 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1053 				if( p1->in.op != NAME ){
1054 					order( p1, INAREG );
1055 					}
1056 				}
1057 			}
1058 		}
1059 
1060 /*
1061 	if( p1->in.op == REG && p->tn.rval == R5 ){
1062 		cerror( "call register overwrite" );
1063 		}
1064  */
1065 /* tbl
1066 	setup gc_numbytes so reference to ZC works */
1067 
1068 	gc_numbytes = temp&(0x3ff);
1069 /* tbl */
1070 
1071 	p->in.op = UNARY CALL;
1072 	m = match( p, INTAREG|INTBREG );
1073 
1074 	/* compensate for deficiency in 'ret' instruction ... wah,kre */
1075 	/* (plus in assignment to gc_numbytes above, for neatness only) */
1076 	if (temp >= 1024)
1077 		printf("	addl2	$%d,sp\n", (temp&(~0x3ff)));
1078 
1079 /* tbl
1080 	switch( temp ) {
1081 	case 0:
1082 		break;
1083 	case 2:
1084 		printf( "	tst	(sp)+\n" );
1085 		break;
1086 	case 4:
1087 		printf( "	cmp	(sp)+,(sp)+\n" );
1088 		break;
1089 	default:
1090 		printf( "	add	$%d,sp\n", temp);
1091 		}
1092    tbl */
1093 	return(m != MDONE);
1094 	}
1095 
1096 /* tbl */
1097 char *
1098 ccbranches[] = {
1099 	"	jeql	L%d\n",
1100 	"	jneq	L%d\n",
1101 	"	jleq	L%d\n",
1102 	"	jlss	L%d\n",
1103 	"	jgeq	L%d\n",
1104 	"	jgtr	L%d\n",
1105 	"	jlequ	L%d\n",
1106 	"	jlssu	L%d\n",
1107 	"	jgequ	L%d\n",
1108 	"	jgtru	L%d\n",
1109 	};
1110 /* tbl */
1111 
1112 /*ARGSUSED*/
1113 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1114 
1115 /* tbl */
1116 	if( o == 0 ) printf( "	jbr	L%d\n", lab );
1117 /* tbl */
1118 	else {
1119 		if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
1120 		printf( ccbranches[o-EQ], lab );
1121 		}
1122 	}
1123 
1124 nextcook( p, cookie ) NODE *p; {
1125 	/* we have failed to match p with cookie; try another */
1126 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1127 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1128 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1129 	return( FORREW );
1130 	}
1131 
1132 /*ARGSUSED*/
1133 lastchance( p, cook ) NODE *p; {
1134 	/* forget it! */
1135 	return(0);
1136 	}
1137 
1138 optim2( p ) register NODE *p; {
1139 	/* do local tree transformations and optimizations */
1140 
1141 	register NODE *l, *r;
1142 
1143 	switch( p->in.op ) {
1144 
1145 	case AND:
1146 		/* commute L and R to eliminate complements and constants */
1147 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
1148 		    l->in.op == COMPL ) {
1149 			p->in.left = p->in.right;
1150 			p->in.right = l;
1151 			}
1152 	case ASG AND:
1153 		/* change meaning of AND to ~R&L - bic on pdp11 */
1154 		r = p->in.right;
1155 		if( r->in.op==ICON && r->in.name[0]==0 ) { /* complement constant */
1156 			r->tn.lval = ~r->tn.lval;
1157 			}
1158 		else if( r->in.op==COMPL ) { /* ~~A => A */
1159 			r->in.op = FREE;
1160 			p->in.right = r->in.left;
1161 			}
1162 		else { /* insert complement node */
1163 			p->in.right = l = talloc();
1164 			l->in.op = COMPL;
1165 			l->in.rall = NOPREF;
1166 			l->in.type = r->in.type;
1167 			l->in.left = r;
1168 			l->in.right = NULL;
1169 			}
1170 		break;
1171 
1172 	case SCONV:
1173 		l = p->in.left;
1174 #if defined(FORT) || defined(SPRECC)
1175 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1176 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1177 			return;
1178 #else
1179 		if( mixtypes(p, l) ) return;
1180 #endif
1181 		if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
1182 			return;
1183 
1184 		/* Only trust it to get it right if the size is the same */
1185 		if( tlen(p) != tlen(l) )
1186 			return;
1187 
1188 		/* clobber conversion */
1189 		if( l->in.op != FLD )
1190 			l->in.type = p->in.type;
1191 		ncopy( p, l );
1192 		l->in.op = FREE;
1193 
1194 		break;
1195 
1196 	case ASSIGN:
1197 		/*
1198 		 * Conversions are equivalent to assignments;
1199 		 * when the two operations are combined,
1200 		 * we can sometimes zap the conversion.
1201 		 */
1202 		r = p->in.right;
1203 		l = p->in.left;
1204 		if ( r->in.op == SCONV &&
1205 		     !mixtypes(l, r) &&
1206 		     l->in.op != FLD &&
1207 		     tlen(l) == tlen(r) ) {
1208 				p->in.right = r->in.left;
1209 				r->in.op = FREE;
1210 			}
1211 		break;
1212 
1213 		}
1214 	}
1215 
1216 /*ARGSUSED*/
1217 NODE * addroreg(l) NODE *l;
1218 				/* OREG was built in clocal()
1219 				 * for an auto or formal parameter
1220 				 * now its address is being taken
1221 				 * local code must unwind it
1222 				 * back to PLUS/MINUS REG ICON
1223 				 * according to local conventions
1224 				 */
1225 {
1226 	cerror("address of OREG taken");
1227 	/*NOTREACHED*/
1228 }
1229 
1230 
1231 
1232 # ifndef ONEPASS
1233 main( argc, argv ) char *argv[]; {
1234 	return( mainp2( argc, argv ) );
1235 	}
1236 # endif
1237 
1238 
1239 /* added by jwf */
1240 struct functbl {
1241 	int fop;
1242 	TWORD ftype;
1243 	char *func;
1244 	} opfunc[] = {
1245 	DIV,		TANY,	"udiv",
1246 	MOD,		TANY,	"urem",
1247 	ASG DIV,	TANY,	"audiv",
1248 	ASG MOD,	TANY,	"aurem",
1249 	0,	0,	0 };
1250 
1251 hardops(p)  register NODE *p; {
1252 	/* change hard to do operators into function calls.  */
1253 	register NODE *q;
1254 	register struct functbl *f;
1255 	register o;
1256 	NODE *old,*temp;
1257 
1258 	o = p->in.op;
1259 	if( ! (optype(o)==BITYPE &&
1260 	       (ISUNSIGNED(p->in.left->in.type) ||
1261 		ISUNSIGNED(p->in.right->in.type))) )
1262 		return;
1263 
1264 	for( f=opfunc; f->fop; f++ ) {
1265 		if( o==f->fop ) goto convert;
1266 		}
1267 	return;
1268 
1269 	convert:
1270 	if( asgop( o ) ) {
1271 		old = NIL;
1272 		switch( p->in.left->in.op ){
1273 		case FLD:
1274 			q = p->in.left->in.left;
1275 			/*
1276 			 * rewrite (lval.fld /= rval); as
1277 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1278 			 * else the compiler will evaluate lval twice.
1279 			 */
1280 			if( q->in.op == UNARY MUL ){
1281 				/* first allocate a temp storage */
1282 				temp = talloc();
1283 				temp->in.op = OREG;
1284 				temp->tn.rval = TMPREG;
1285 				temp->tn.lval = BITOOR(freetemp(1));
1286 				temp->in.type = INCREF(p->in.type);
1287 #ifdef FLEXNAMES
1288 				temp->in.name = "";
1289 #else
1290 				temp->in.name[0] = '\0';
1291 #endif
1292 				old = q->in.left;
1293 				q->in.left = temp;
1294 			}
1295 			/* fall thru ... */
1296 
1297 		case REG:
1298 		case NAME:
1299 		case OREG:
1300 			/* change ASG OP to a simple OP */
1301 			q = talloc();
1302 			q->in.op = NOASG p->in.op;
1303 			q->in.rall = NOPREF;
1304 			q->in.type = p->in.type;
1305 			q->in.left = tcopy(p->in.left);
1306 			q->in.right = p->in.right;
1307 			p->in.op = ASSIGN;
1308 			p->in.right = q;
1309 			p = q;
1310 			f -= 2; /* Note: this depends on the table order */
1311 			/* on the right side only - replace *temp with
1312 			 *(temp = &lval), build the assignment node */
1313 			if( old ){
1314 				temp = q->in.left->in.left; /* the "*" node */
1315 				q = talloc();
1316 				q->in.op = ASSIGN;
1317 				q->in.left = temp->in.left;
1318 				q->in.right = old;
1319 				q->in.type = old->in.type;
1320 #ifdef FLEXNAMES
1321 				q->in.name = "";
1322 #else
1323 				q->in.name[0] = '\0';
1324 #endif
1325 				temp->in.left = q;
1326 			}
1327 			break;
1328 
1329 		case UNARY MUL:
1330 			/* avoid doing side effects twice */
1331 			q = p->in.left;
1332 			p->in.left = q->in.left;
1333 			q->in.op = FREE;
1334 			break;
1335 
1336 		default:
1337 			cerror( "hardops: can't compute & LHS" );
1338 			}
1339 		}
1340 
1341 	/* build comma op for args to function */
1342 	q = talloc();
1343 	q->in.op = CM;
1344 	q->in.rall = NOPREF;
1345 	q->in.type = INT;
1346 	q->in.left = p->in.left;
1347 	q->in.right = p->in.right;
1348 	p->in.op = CALL;
1349 	p->in.right = q;
1350 
1351 	/* put function name in left node of call */
1352 	p->in.left = q = talloc();
1353 	q->in.op = ICON;
1354 	q->in.rall = NOPREF;
1355 	q->in.type = INCREF( FTN + p->in.type );
1356 #ifndef FLEXNAMES
1357 	strcpy( q->in.name, f->func );
1358 #else
1359 	q->in.name = f->func;
1360 #endif
1361 	q->tn.lval = 0;
1362 	q->tn.rval = 0;
1363 
1364 	}
1365 
1366 zappost(p) NODE *p; {
1367 	/* look for ++ and -- operators and remove them */
1368 
1369 	register o, ty;
1370 	register NODE *q;
1371 	o = p->in.op;
1372 	ty = optype( o );
1373 
1374 	switch( o ){
1375 
1376 	case INCR:
1377 	case DECR:
1378 			q = p->in.left;
1379 			p->in.right->in.op = FREE;  /* zap constant */
1380 			ncopy( p, q );
1381 			q->in.op = FREE;
1382 			return;
1383 
1384 		}
1385 
1386 	if( ty == BITYPE ) zappost( p->in.right );
1387 	if( ty != LTYPE ) zappost( p->in.left );
1388 }
1389 
1390 fixpre(p) NODE *p; {
1391 
1392 	register o, ty;
1393 	o = p->in.op;
1394 	ty = optype( o );
1395 
1396 	switch( o ){
1397 
1398 	case ASG PLUS:
1399 			p->in.op = PLUS;
1400 			break;
1401 	case ASG MINUS:
1402 			p->in.op = MINUS;
1403 			break;
1404 		}
1405 
1406 	if( ty == BITYPE ) fixpre( p->in.right );
1407 	if( ty != LTYPE ) fixpre( p->in.left );
1408 }
1409 
1410 strip(p) register NODE *p; {
1411 	NODE *q;
1412 
1413 	/* strip nodes off the top when no side effects occur */
1414 	for( ; ; ) {
1415 		switch( p->in.op ) {
1416 		case SCONV:			/* remove lint tidbits */
1417 			q = p->in.left;
1418 			ncopy( p, q );
1419 			q->in.op = FREE;
1420 			break;
1421 		/* could probably add a few more here */
1422 		default:
1423 			return;
1424 			}
1425 		}
1426 	}
1427 
1428 myreader(p) register NODE *p; {
1429 	strip( p );		/* strip off operations with no side effects */
1430 	canon( p );		/* expands r-vals for fields */
1431 	walkf( p, hardops );	/* convert ops to function calls */
1432 	walkf( p, optim2 );
1433 	/* jwf toff = 0;  /* stack offset swindle */
1434 	}
1435