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