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