xref: /csrg-svn/old/pcc/ccom.vax/local2.c (revision 32928)
1 # ifndef lint
2 static char *sccsid ="@(#)local2.c	1.22 (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 	register NODE *l, *r;
1184 
1185 	switch( p->in.op ) {
1186 
1187 	case AND:
1188 		/* commute L and R to eliminate complements and constants */
1189 		if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 ||
1190 		    l->in.op == COMPL ) {
1191 			p->in.left = p->in.right;
1192 			p->in.right = l;
1193 			}
1194 	case ASG AND:
1195 		/* change meaning of AND to ~R&L - bic on pdp11 */
1196 		r = p->in.right;
1197 		if( r->in.op==ICON && r->in.name[0]==0 ) { /* complement constant */
1198 			r->tn.lval = ~r->tn.lval;
1199 			}
1200 		else if( r->in.op==COMPL ) { /* ~~A => A */
1201 			r->in.op = FREE;
1202 			p->in.right = r->in.left;
1203 			}
1204 		else { /* insert complement node */
1205 			p->in.right = l = talloc();
1206 			l->in.op = COMPL;
1207 			l->in.rall = NOPREF;
1208 			l->in.type = r->in.type;
1209 			l->in.left = r;
1210 			l->in.right = NULL;
1211 			}
1212 		break;
1213 
1214 	case SCONV:
1215 		l = p->in.left;
1216 #if defined(FORT) || defined(SPRECC)
1217 		if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1218 		    l->in.type == FLOAT || l->in.type == DOUBLE )
1219 			return;
1220 #else
1221 		if( mixtypes(p, l) ) return;
1222 #endif
1223 		if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
1224 			return;
1225 
1226 		/* Only trust it to get it right if the size is the same */
1227 		if( tlen(p) != tlen(l) )
1228 			return;
1229 
1230 		/* clobber conversion */
1231 		if( l->in.op != FLD )
1232 			l->in.type = p->in.type;
1233 		ncopy( p, l );
1234 		l->in.op = FREE;
1235 
1236 		break;
1237 
1238 	case ASSIGN:
1239 		/*
1240 		 * Conversions are equivalent to assignments;
1241 		 * when the two operations are combined,
1242 		 * we can sometimes zap the conversion.
1243 		 */
1244 		r = p->in.right;
1245 		l = p->in.left;
1246 		if ( r->in.op == SCONV &&
1247 		     !mixtypes(l, r) &&
1248 		     l->in.op != FLD &&
1249 		     tlen(l) == tlen(r) ) {
1250 				p->in.right = r->in.left;
1251 				r->in.op = FREE;
1252 			}
1253 		break;
1254 
1255 		}
1256 	}
1257 
1258 /*ARGSUSED*/
1259 NODE * addroreg(l) NODE *l;
1260 				/* OREG was built in clocal()
1261 				 * for an auto or formal parameter
1262 				 * now its address is being taken
1263 				 * local code must unwind it
1264 				 * back to PLUS/MINUS REG ICON
1265 				 * according to local conventions
1266 				 */
1267 {
1268 	cerror("address of OREG taken");
1269 	/*NOTREACHED*/
1270 }
1271 
1272 
1273 
1274 # ifndef ONEPASS
1275 main( argc, argv ) char *argv[]; {
1276 	return( mainp2( argc, argv ) );
1277 	}
1278 # endif
1279 
1280 
1281 /* added by jwf */
1282 struct functbl {
1283 	int fop;
1284 	TWORD ftype;
1285 	char *func;
1286 	} opfunc[] = {
1287 	DIV,		TANY,	"udiv",
1288 	MOD,		TANY,	"urem",
1289 	ASG DIV,	TANY,	"audiv",
1290 	ASG MOD,	TANY,	"aurem",
1291 	0,	0,	0 };
1292 
1293 hardops(p)  register NODE *p; {
1294 	/* change hard to do operators into function calls.  */
1295 	register NODE *q;
1296 	register struct functbl *f;
1297 	register o;
1298 	NODE *old,*temp;
1299 
1300 	o = p->in.op;
1301 	if( ! (optype(o)==BITYPE &&
1302 	       (ISUNSIGNED(p->in.left->in.type) ||
1303 		ISUNSIGNED(p->in.right->in.type))) )
1304 		return;
1305 
1306 	for( f=opfunc; f->fop; f++ ) {
1307 		if( o==f->fop ) goto convert;
1308 		}
1309 	return;
1310 
1311 	convert:
1312 	if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) {
1313 		/* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */
1314 		/* save a subroutine call -- use at most 5 instructions */
1315 		if( p->in.op == DIV &&
1316 		     (unsigned) p->in.right->tn.lval >= 0x80000000 )
1317 			/* easy to do here, harder to do in zzzcode() */
1318 			p->in.op = UGE;
1319 		return;
1320 		}
1321 	if( asgop( o ) ) {
1322 		old = NIL;
1323 		switch( p->in.left->in.op ){
1324 		case FLD:
1325 			q = p->in.left->in.left;
1326 			/*
1327 			 * rewrite (lval.fld /= rval); as
1328 			 *  ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1329 			 * else the compiler will evaluate lval twice.
1330 			 */
1331 			if( q->in.op == UNARY MUL ){
1332 				/* first allocate a temp storage */
1333 				temp = talloc();
1334 				temp->in.op = OREG;
1335 				temp->tn.rval = TMPREG;
1336 				temp->tn.lval = BITOOR(freetemp(1));
1337 				temp->in.type = INCREF(p->in.type);
1338 #ifdef FLEXNAMES
1339 				temp->in.name = "";
1340 #else
1341 				temp->in.name[0] = '\0';
1342 #endif
1343 				old = q->in.left;
1344 				q->in.left = temp;
1345 			}
1346 			/* fall thru ... */
1347 
1348 		case REG:
1349 		case NAME:
1350 		case OREG:
1351 			/* change ASG OP to a simple OP */
1352 			q = talloc();
1353 			q->in.op = NOASG p->in.op;
1354 			q->in.rall = NOPREF;
1355 			q->in.type = p->in.type;
1356 			q->in.left = tcopy(p->in.left);
1357 			q->in.right = p->in.right;
1358 			p->in.op = ASSIGN;
1359 			p->in.right = q;
1360 			p = q;
1361 			f -= 2; /* Note: this depends on the table order */
1362 			/* on the right side only - replace *temp with
1363 			 *(temp = &lval), build the assignment node */
1364 			if( old ){
1365 				temp = q->in.left->in.left; /* the "*" node */
1366 				q = talloc();
1367 				q->in.op = ASSIGN;
1368 				q->in.left = temp->in.left;
1369 				q->in.right = old;
1370 				q->in.type = old->in.type;
1371 #ifdef FLEXNAMES
1372 				q->in.name = "";
1373 #else
1374 				q->in.name[0] = '\0';
1375 #endif
1376 				temp->in.left = q;
1377 			}
1378 			break;
1379 
1380 		case UNARY MUL:
1381 			/* avoid doing side effects twice */
1382 			q = p->in.left;
1383 			p->in.left = q->in.left;
1384 			q->in.op = FREE;
1385 			break;
1386 
1387 		default:
1388 			cerror( "hardops: can't compute & LHS" );
1389 			}
1390 		}
1391 
1392 	/* build comma op for args to function */
1393 	q = talloc();
1394 	q->in.op = CM;
1395 	q->in.rall = NOPREF;
1396 	q->in.type = INT;
1397 	q->in.left = p->in.left;
1398 	q->in.right = p->in.right;
1399 	p->in.op = CALL;
1400 	p->in.right = q;
1401 
1402 	/* put function name in left node of call */
1403 	p->in.left = q = talloc();
1404 	q->in.op = ICON;
1405 	q->in.rall = NOPREF;
1406 	q->in.type = INCREF( FTN + p->in.type );
1407 #ifndef FLEXNAMES
1408 	strcpy( q->in.name, f->func );
1409 #else
1410 	q->in.name = f->func;
1411 #endif
1412 	q->tn.lval = 0;
1413 	q->tn.rval = 0;
1414 
1415 	}
1416 
1417 zappost(p) NODE *p; {
1418 	/* look for ++ and -- operators and remove them */
1419 
1420 	register o, ty;
1421 	register NODE *q;
1422 	o = p->in.op;
1423 	ty = optype( o );
1424 
1425 	switch( o ){
1426 
1427 	case INCR:
1428 	case DECR:
1429 			q = p->in.left;
1430 			p->in.right->in.op = FREE;  /* zap constant */
1431 			ncopy( p, q );
1432 			q->in.op = FREE;
1433 			return;
1434 
1435 		}
1436 
1437 	if( ty == BITYPE ) zappost( p->in.right );
1438 	if( ty != LTYPE ) zappost( p->in.left );
1439 }
1440 
1441 fixpre(p) NODE *p; {
1442 
1443 	register o, ty;
1444 	o = p->in.op;
1445 	ty = optype( o );
1446 
1447 	switch( o ){
1448 
1449 	case ASG PLUS:
1450 			p->in.op = PLUS;
1451 			break;
1452 	case ASG MINUS:
1453 			p->in.op = MINUS;
1454 			break;
1455 		}
1456 
1457 	if( ty == BITYPE ) fixpre( p->in.right );
1458 	if( ty != LTYPE ) fixpre( p->in.left );
1459 }
1460 
1461 strip(p) register NODE *p; {
1462 	NODE *q;
1463 
1464 	/* strip nodes off the top when no side effects occur */
1465 	for( ; ; ) {
1466 		switch( p->in.op ) {
1467 		case SCONV:			/* remove lint tidbits */
1468 			q = p->in.left;
1469 			ncopy( p, q );
1470 			q->in.op = FREE;
1471 			break;
1472 		/* could probably add a few more here */
1473 		default:
1474 			return;
1475 			}
1476 		}
1477 	}
1478 
1479 myreader(p) register NODE *p; {
1480 	strip( p );		/* strip off operations with no side effects */
1481 	canon( p );		/* expands r-vals for fields */
1482 	walkf( p, hardops );	/* convert ops to function calls */
1483 	walkf( p, optim2 );
1484 	/* jwf toff = 0;  /* stack offset swindle */
1485 	}
1486