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