xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32927)
1 # ifndef lint
2 static char *sccsid ="@(#)local2.c	1.21 (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 	case UNARY MUL:
774 		p = p->in.left;
775 		return( p->in.op != UNARY MUL && shtemp(p) );
776 		}
777 
778 	if( optype( p->in.op ) != LTYPE ) return(0);
779 	return(1);
780 	}
781 
782 shumul( p ) register NODE *p; {
783 	register o;
784 	extern int xdebug;
785 
786 	if (xdebug) {
787 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
788 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
789 		}
790 
791 
792 	o = p->in.op;
793 	if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM );
794 
795 	if( ( o == INCR || o == ASG MINUS ) &&
796 	    ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) &&
797 	    p->in.right->in.name[0] == '\0' )
798 		{
799 		switch (p->in.type)
800 			{
801 			case CHAR|PTR:
802 			case UCHAR|PTR:
803 				o = 1;
804 				break;
805 
806 			case SHORT|PTR:
807 			case USHORT|PTR:
808 				o = 2;
809 				break;
810 
811 			case INT|PTR:
812 			case UNSIGNED|PTR:
813 			case LONG|PTR:
814 			case ULONG|PTR:
815 			case FLOAT|PTR:
816 				o = 4;
817 				break;
818 
819 			case DOUBLE|PTR:
820 				o = 8;
821 				break;
822 
823 			default:
824 				if ( ISPTR(p->in.type) &&
825 				     ISPTR(DECREF(p->in.type)) ) {
826 					o = 4;
827 					break;
828 					}
829 				else return(0);
830 			}
831 		return( p->in.right->tn.lval == o ? STARREG : 0);
832 		}
833 
834 	return( 0 );
835 	}
836 
837 adrcon( val ) CONSZ val; {
838 	putchar( '$' );
839 	printf( CONFMT, val );
840 	}
841 
842 conput( p ) register NODE *p; {
843 	switch( p->in.op ){
844 
845 	case ICON:
846 		acon( p );
847 		return;
848 
849 	case REG:
850 		putstr( rnames[p->tn.rval] );
851 		return;
852 
853 	default:
854 		cerror( "illegal conput" );
855 		}
856 	}
857 
858 /*ARGSUSED*/
859 insput( p ) NODE *p; {
860 	cerror( "insput" );
861 	}
862 
863 /*ARGSUSED*/
864 upput( p, off ) NODE *p; int off; {
865 	cerror( "upput" );
866 	}
867 
868 adrput( p ) register NODE *p; {
869 	register int r;
870 	/* output an address, with offsets, from p */
871 
872 	if( p->in.op == FLD ){
873 		p = p->in.left;
874 		}
875 	switch( p->in.op ){
876 
877 	case NAME:
878 		acon( p );
879 		return;
880 
881 	case ICON:
882 		/* addressable value of the constant */
883 		putchar( '$' );
884 		acon( p );
885 		return;
886 
887 	case REG:
888 		putstr( rnames[p->tn.rval] );
889 		return;
890 
891 	case OREG:
892 		r = p->tn.rval;
893 		if( R2TEST(r) ){ /* double indexing */
894 			register int flags;
895 
896 			flags = R2UPK3(r);
897 			if( flags & 1 ) putchar('*');
898 			if( flags & 4 ) putchar('-');
899 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
900 			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
901 			if( flags & 2 ) putchar('+');
902 			printf( "[%s]", rnames[R2UPK2(r)] );
903 			return;
904 			}
905 		if( r == AP ){  /* in the argument region */
906 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
907 			printf( CONFMT, p->tn.lval );
908 			putstr( "(ap)" );
909 			return;
910 			}
911 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
912 		printf( "(%s)", rnames[p->tn.rval] );
913 		return;
914 
915 	case UNARY MUL:
916 		/* STARNM or STARREG found */
917 		if( tshape(p, STARNM) ) {
918 			putchar( '*' );
919 			adrput( p->in.left);
920 			}
921 		else {	/* STARREG - really auto inc or dec */
922 			register NODE *q;
923 
924 /* tbl
925 			p = p->in.left;
926 			p->in.left->in.op = OREG;
927 			if( p->in.op == INCR ) {
928 				adrput( p->in.left );
929 				putchar( '+' );
930 				}
931 			else {
932 				putchar( '-' );
933 				adrput( p->in.left );
934 				}
935    tbl */
936 			q = p->in.left;
937 			if( q->in.right->tn.lval != tlen(p) )
938 				cerror("adrput: bad auto-increment/decrement");
939 			printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"),
940 				rnames[q->in.left->tn.rval],
941 				(q->in.op==INCR ? "+" : "") );
942 			p->in.op = OREG;
943 			p->tn.rval = q->in.left->tn.rval;
944 			p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0);
945 #ifndef FLEXNAMES
946 			p->in.name[0] = '\0';
947 #else
948 			p->in.name = "";
949 #endif
950 			tfree(q);
951 		}
952 		return;
953 
954 	default:
955 		cerror( "illegal address" );
956 		return;
957 
958 		}
959 
960 	}
961 
962 acon( p ) register NODE *p; { /* print out a constant */
963 
964 	if( p->in.name[0] == '\0' ){
965 		printf( CONFMT, p->tn.lval);
966 		}
967 	else if( p->tn.lval == 0 ) {
968 #ifndef FLEXNAMES
969 		printf( "%.8s", p->in.name );
970 #else
971 		putstr( p->in.name );
972 #endif
973 		}
974 	else {
975 #ifndef FLEXNAMES
976 		printf( "%.8s+", p->in.name );
977 #else
978 		printf( "%s+", p->in.name );
979 #endif
980 		printf( CONFMT, p->tn.lval );
981 		}
982 	}
983 
984 /*
985 aacon( p ) register NODE *p; { /* print out a constant */
986 /*
987 
988 	if( p->in.name[0] == '\0' ){
989 		printf( CONFMT, p->tn.lval);
990 		return( 0 );
991 		}
992 	else if( p->tn.lval == 0 ) {
993 #ifndef FLEXNAMES
994 		printf( "$%.8s", p->in.name );
995 #else
996 		printf( "$%s", p->in.name );
997 #endif
998 		return( 1 );
999 		}
1000 	else {
1001 		printf( "$(" );
1002 		printf( CONFMT, p->tn.lval );
1003 		printf( "+" );
1004 #ifndef FLEXNAMES
1005 		printf( "%.8s)", p->in.name );
1006 #else
1007 		printf( "%s)", p->in.name );
1008 #endif
1009 		return(1);
1010 		}
1011 	}
1012  */
1013 
1014 genscall( p, cookie ) register NODE *p; {
1015 	/* structure valued call */
1016 	return( gencall( p, cookie ) );
1017 	}
1018 
1019 /* tbl */
1020 int gc_numbytes;
1021 /* tbl */
1022 
1023 /*ARGSUSED*/
1024 gencall( p, cookie ) register NODE *p; {
1025 	/* generate the call given by p */
1026 	register NODE *p1;
1027 	register temp, temp1;
1028 	register m;
1029 
1030 	if( p->in.right ) temp = argsize( p->in.right );
1031 	else temp = 0;
1032 
1033 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1034 		/* set aside room for structure return */
1035 
1036 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1037 		else temp1 = temp;
1038 		}
1039 
1040 	if( temp > maxargs ) maxargs = temp;
1041 	SETOFF(temp1,4);
1042 
1043 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
1044 		genargs( p->in.right );
1045 		}
1046 
1047 	p1 = p->in.left;
1048 	if( p1->in.op != ICON ){
1049 		if( p1->in.op != REG ){
1050 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1051 				if( p1->in.op != NAME ){
1052 					order( p1, INAREG );
1053 					}
1054 				}
1055 			}
1056 		}
1057 
1058 /*
1059 	if( p1->in.op == REG && p->tn.rval == R5 ){
1060 		cerror( "call register overwrite" );
1061 		}
1062  */
1063 /* tbl
1064 	setup gc_numbytes so reference to ZC works */
1065 
1066 	gc_numbytes = temp&(0x3ff);
1067 /* tbl */
1068 
1069 	p->in.op = UNARY CALL;
1070 	m = match( p, INTAREG|INTBREG );
1071 
1072 	/* compensate for deficiency in 'ret' instruction ... wah,kre */
1073 	/* (plus in assignment to gc_numbytes above, for neatness only) */
1074 	if (temp >= 1024)
1075 		printf("	addl2	$%d,sp\n", (temp&(~0x3ff)));
1076 
1077 /* tbl
1078 	switch( temp ) {
1079 	case 0:
1080 		break;
1081 	case 2:
1082 		printf( "	tst	(sp)+\n" );
1083 		break;
1084 	case 4:
1085 		printf( "	cmp	(sp)+,(sp)+\n" );
1086 		break;
1087 	default:
1088 		printf( "	add	$%d,sp\n", temp);
1089 		}
1090    tbl */
1091 	return(m != MDONE);
1092 	}
1093 
1094 /* tbl */
1095 char *
1096 ccbranches[] = {
1097 	"	jeql	L%d\n",
1098 	"	jneq	L%d\n",
1099 	"	jleq	L%d\n",
1100 	"	jlss	L%d\n",
1101 	"	jgeq	L%d\n",
1102 	"	jgtr	L%d\n",
1103 	"	jlequ	L%d\n",
1104 	"	jlssu	L%d\n",
1105 	"	jgequ	L%d\n",
1106 	"	jgtru	L%d\n",
1107 	};
1108 /* tbl */
1109 
1110 /*ARGSUSED*/
1111 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
1112 
1113 /* tbl */
1114 	if( o == 0 ) printf( "	jbr	L%d\n", lab );
1115 /* tbl */
1116 	else {
1117 		if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
1118 		printf( ccbranches[o-EQ], lab );
1119 		}
1120 	}
1121 
1122 nextcook( p, cookie ) NODE *p; {
1123 	/* we have failed to match p with cookie; try another */
1124 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
1125 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1126 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1127 	return( FORREW );
1128 	}
1129 
1130 /*ARGSUSED*/
1131 lastchance( p, cook ) NODE *p; {
1132 	/* forget it! */
1133 	return(0);
1134 	}
1135 
1136 optim2( p ) register NODE *p; {
1137 	/* do local tree transformations and optimizations */
1138 
1139 	register NODE *l, *r;
1140 
1141 	switch( p->in.op ) {
1142 
1143 	case AND:
1144 		/* commute L and R to eliminate complements and constants */
1145 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
1146 		    l->in.op == COMPL ) {
1147 			p->in.left = p->in.right;
1148 			p->in.right = l;
1149 			}
1150 	case ASG AND:
1151 		/* change meaning of AND to ~R&L - bic on pdp11 */
1152 		r = p->in.right;
1153 		if( r->in.op==ICON && r->in.name[0]==0 ) { /* complement constant */
1154 			r->tn.lval = ~r->tn.lval;
1155 			}
1156 		else if( r->in.op==COMPL ) { /* ~~A => A */
1157 			r->in.op = FREE;
1158 			p->in.right = r->in.left;
1159 			}
1160 		else { /* insert complement node */
1161 			p->in.right = l = talloc();
1162 			l->in.op = COMPL;
1163 			l->in.rall = NOPREF;
1164 			l->in.type = r->in.type;
1165 			l->in.left = r;
1166 			l->in.right = NULL;
1167 			}
1168 		break;
1169 
1170 	case SCONV:
1171 		l = p->in.left;
1172 #if defined(FORT) || defined(SPRECC)
1173 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1174 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1175 			return;
1176 #else
1177 		if( mixtypes(p, l) ) return;
1178 #endif
1179 		if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
1180 			return;
1181 
1182 		/* Only trust it to get it right if the size is the same */
1183 		if( tlen(p) != tlen(l) )
1184 			return;
1185 
1186 		/* clobber conversion */
1187 		if( l->in.op != FLD )
1188 			l->in.type = p->in.type;
1189 		ncopy( p, l );
1190 		l->in.op = FREE;
1191 
1192 		break;
1193 
1194 	case ASSIGN:
1195 		/*
1196 		 * Conversions are equivalent to assignments;
1197 		 * when the two operations are combined,
1198 		 * we can sometimes zap the conversion.
1199 		 */
1200 		r = p->in.right;
1201 		l = p->in.left;
1202 		if ( r->in.op == SCONV &&
1203 		     !mixtypes(l, r) &&
1204 		     l->in.op != FLD &&
1205 		     tlen(l) == tlen(r) ) {
1206 				p->in.right = r->in.left;
1207 				r->in.op = FREE;
1208 			}
1209 		break;
1210 
1211 		}
1212 	}
1213 
1214 /*ARGSUSED*/
1215 NODE * addroreg(l) NODE *l;
1216 				/* OREG was built in clocal()
1217 				 * for an auto or formal parameter
1218 				 * now its address is being taken
1219 				 * local code must unwind it
1220 				 * back to PLUS/MINUS REG ICON
1221 				 * according to local conventions
1222 				 */
1223 {
1224 	cerror("address of OREG taken");
1225 	/*NOTREACHED*/
1226 }
1227 
1228 
1229 
1230 # ifndef ONEPASS
1231 main( argc, argv ) char *argv[]; {
1232 	return( mainp2( argc, argv ) );
1233 	}
1234 # endif
1235 
1236 
1237 /* added by jwf */
1238 struct functbl {
1239 	int fop;
1240 	TWORD ftype;
1241 	char *func;
1242 	} opfunc[] = {
1243 	DIV,		TANY,	"udiv",
1244 	MOD,		TANY,	"urem",
1245 	ASG DIV,	TANY,	"audiv",
1246 	ASG MOD,	TANY,	"aurem",
1247 	0,	0,	0 };
1248 
1249 hardops(p)  register NODE *p; {
1250 	/* change hard to do operators into function calls.  */
1251 	register NODE *q;
1252 	register struct functbl *f;
1253 	register o;
1254 	NODE *old,*temp;
1255 
1256 	o = p->in.op;
1257 	if( ! (optype(o)==BITYPE &&
1258 	       (ISUNSIGNED(p->in.left->in.type) ||
1259 		ISUNSIGNED(p->in.right->in.type))) )
1260 		return;
1261 
1262 	for( f=opfunc; f->fop; f++ ) {
1263 		if( o==f->fop ) goto convert;
1264 		}
1265 	return;
1266 
1267 	convert:
1268 	if( asgop( o ) ) {
1269 		old = NIL;
1270 		switch( p->in.left->in.op ){
1271 		case FLD:
1272 			q = p->in.left->in.left;
1273 			/*
1274 			 * rewrite (lval.fld /= rval); as
1275 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1276 			 * else the compiler will evaluate lval twice.
1277 			 */
1278 			if( q->in.op == UNARY MUL ){
1279 				/* first allocate a temp storage */
1280 				temp = talloc();
1281 				temp->in.op = OREG;
1282 				temp->tn.rval = TMPREG;
1283 				temp->tn.lval = BITOOR(freetemp(1));
1284 				temp->in.type = INCREF(p->in.type);
1285 #ifdef FLEXNAMES
1286 				temp->in.name = "";
1287 #else
1288 				temp->in.name[0] = '\0';
1289 #endif
1290 				old = q->in.left;
1291 				q->in.left = temp;
1292 			}
1293 			/* fall thru ... */
1294 
1295 		case REG:
1296 		case NAME:
1297 		case OREG:
1298 			/* change ASG OP to a simple OP */
1299 			q = talloc();
1300 			q->in.op = NOASG p->in.op;
1301 			q->in.rall = NOPREF;
1302 			q->in.type = p->in.type;
1303 			q->in.left = tcopy(p->in.left);
1304 			q->in.right = p->in.right;
1305 			p->in.op = ASSIGN;
1306 			p->in.right = q;
1307 			p = q;
1308 			f -= 2; /* Note: this depends on the table order */
1309 			/* on the right side only - replace *temp with
1310 			 *(temp = &lval), build the assignment node */
1311 			if( old ){
1312 				temp = q->in.left->in.left; /* the "*" node */
1313 				q = talloc();
1314 				q->in.op = ASSIGN;
1315 				q->in.left = temp->in.left;
1316 				q->in.right = old;
1317 				q->in.type = old->in.type;
1318 #ifdef FLEXNAMES
1319 				q->in.name = "";
1320 #else
1321 				q->in.name[0] = '\0';
1322 #endif
1323 				temp->in.left = q;
1324 			}
1325 			break;
1326 
1327 		case UNARY MUL:
1328 			/* avoid doing side effects twice */
1329 			q = p->in.left;
1330 			p->in.left = q->in.left;
1331 			q->in.op = FREE;
1332 			break;
1333 
1334 		default:
1335 			cerror( "hardops: can't compute & LHS" );
1336 			}
1337 		}
1338 
1339 	/* build comma op for args to function */
1340 	q = talloc();
1341 	q->in.op = CM;
1342 	q->in.rall = NOPREF;
1343 	q->in.type = INT;
1344 	q->in.left = p->in.left;
1345 	q->in.right = p->in.right;
1346 	p->in.op = CALL;
1347 	p->in.right = q;
1348 
1349 	/* put function name in left node of call */
1350 	p->in.left = q = talloc();
1351 	q->in.op = ICON;
1352 	q->in.rall = NOPREF;
1353 	q->in.type = INCREF( FTN + p->in.type );
1354 #ifndef FLEXNAMES
1355 	strcpy( q->in.name, f->func );
1356 #else
1357 	q->in.name = f->func;
1358 #endif
1359 	q->tn.lval = 0;
1360 	q->tn.rval = 0;
1361 
1362 	}
1363 
1364 zappost(p) NODE *p; {
1365 	/* look for ++ and -- operators and remove them */
1366 
1367 	register o, ty;
1368 	register NODE *q;
1369 	o = p->in.op;
1370 	ty = optype( o );
1371 
1372 	switch( o ){
1373 
1374 	case INCR:
1375 	case DECR:
1376 			q = p->in.left;
1377 			p->in.right->in.op = FREE;  /* zap constant */
1378 			ncopy( p, q );
1379 			q->in.op = FREE;
1380 			return;
1381 
1382 		}
1383 
1384 	if( ty == BITYPE ) zappost( p->in.right );
1385 	if( ty != LTYPE ) zappost( p->in.left );
1386 }
1387 
1388 fixpre(p) NODE *p; {
1389 
1390 	register o, ty;
1391 	o = p->in.op;
1392 	ty = optype( o );
1393 
1394 	switch( o ){
1395 
1396 	case ASG PLUS:
1397 			p->in.op = PLUS;
1398 			break;
1399 	case ASG MINUS:
1400 			p->in.op = MINUS;
1401 			break;
1402 		}
1403 
1404 	if( ty == BITYPE ) fixpre( p->in.right );
1405 	if( ty != LTYPE ) fixpre( p->in.left );
1406 }
1407 
1408 strip(p) register NODE *p; {
1409 	NODE *q;
1410 
1411 	/* strip nodes off the top when no side effects occur */
1412 	for( ; ; ) {
1413 		switch( p->in.op ) {
1414 		case SCONV:			/* remove lint tidbits */
1415 			q = p->in.left;
1416 			ncopy( p, q );
1417 			q->in.op = FREE;
1418 			break;
1419 		/* could probably add a few more here */
1420 		default:
1421 			return;
1422 			}
1423 		}
1424 	}
1425 
1426 myreader(p) register NODE *p; {
1427 	strip( p );		/* strip off operations with no side effects */
1428 	canon( p );		/* expands r-vals for fields */
1429 	walkf( p, hardops );	/* convert ops to function calls */
1430 	walkf( p, optim2 );
1431 	/* jwf toff = 0;  /* stack offset swindle */
1432 	}
1433