xref: /csrg-svn/old/pcc/ccom.tahoe/local2.c (revision 26076)
1 #ifndef lint
2 static char sccsid[] = "@(#)local2.c	1.4 (Berkeley) 02/04/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 BITMASK(n) ((1L<<n)-1)
13 
14 # ifndef ONEPASS
15 where(c){
16 	fprintf( stderr, "%s, line %d: ", filename, lineno );
17 	}
18 # endif
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 int ent_mask;
26 
27 eobl2(){
28 	register OFFSZ spoff;	/* offset from stack pointer */
29 #ifndef FORT
30 	extern int ftlab1, ftlab2;
31 #endif
32 
33 	spoff = maxoff;
34 	spoff /= SZCHAR;
35 	SETOFF(spoff,4);
36 #ifdef FORT
37 #ifndef FLEXNAMES
38 	printf( "	.set	.F%d,%d\n", ftnno, spoff );
39 #else
40 	/* SHOULD BE L%d ... ftnno but must change pc/f77 */
41 	printf( "	.set	LF%d,%d\n", ftnno, spoff );
42 #endif
43 	printf( "	.set	LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
44 #else
45 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
46 	printf( "L%d:\n", ftlab1);
47 	if( maxoff > AUTOINIT )
48 		printf( "	subl3	$%d,fp,sp\n", spoff);
49 	printf( "	jbr 	L%d\n", ftlab2);
50 #endif
51 	ent_mask = 0;
52 	maxargs = -1;
53 	}
54 
55 struct hoptab { int opmask; char * opstring; } ioptab[] = {
56 
57 	PLUS,	"add",
58 	MINUS,	"sub",
59 	MUL,	"mul",
60 	DIV,	"div",
61 	MOD,	"div",
62 	OR,	"or",
63 	ER,	"xor",
64 	AND,	"and",
65 	-1,	""    };
66 
67 hopcode( f, o ){
68 	/* output the appropriate string from the above table */
69 
70 	register struct hoptab *q;
71 
72 	if(asgop(o))
73 		o = NOASG o;
74 	for( q = ioptab;  q->opmask>=0; ++q ){
75 		if( q->opmask == o ){
76 			if(f == 'E')
77 				printf( "e%s", q->opstring);
78 			else
79 				printf( "%s%c", q->opstring, tolower(f));
80 			return;
81 			}
82 		}
83 	cerror( "no hoptab for %s", opst[o] );
84 	}
85 
86 char *
87 rnames[] = {  /* keyed to register number tokens */
88 
89 	"r0", "r1",
90 	"r2", "r3", "r4", "r5",
91 	"r6", "r7", "r8", "r9", "r10", "r11",
92 	"r12", "fp", "sp", "pc",
93 	};
94 
95 /* output register name and update entry mask */
96 char *
97 rname(r)
98 	register int r;
99 {
100 
101 	ent_mask |= 1<<r;
102 	return(rnames[r]);
103 }
104 
105 int rstatus[] = {
106 	SAREG|STAREG, SAREG|STAREG,
107 	SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
108 	SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
109 	SAREG, SAREG, SAREG, SAREG,
110 	};
111 
112 tlen(p) NODE *p;
113 {
114 	switch(p->in.type) {
115 		case CHAR:
116 		case UCHAR:
117 			return(1);
118 
119 		case SHORT:
120 		case USHORT:
121 			return(2);
122 
123 		case DOUBLE:
124 			return(8);
125 
126 		default:
127 			return(4);
128 		}
129 }
130 
131 prtype(n) NODE *n;
132 {
133 	switch (n->in.type)
134 		{
135 
136 		case DOUBLE:
137 			printf("d");
138 			return;
139 
140 		case FLOAT:
141 			printf("f");
142 			return;
143 
144 		case INT:
145 		case UNSIGNED:
146 			printf("l");
147 			return;
148 
149 		case SHORT:
150 		case USHORT:
151 			printf("w");
152 			return;
153 
154 		case CHAR:
155 		case UCHAR:
156 			printf("b");
157 			return;
158 
159 		default:
160 			if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
161 			else {
162 				printf("l");
163 				return;
164 				}
165 		}
166 }
167 
168 zzzcode( p, c ) register NODE *p; {
169 	register int m;
170 	int val;
171 	switch( c ){
172 
173 	case 'N':  /* logical ops, turned into 0-1 */
174 		/* use register given by register 1 */
175 		cbgen( 0, m=getlab(), 'I' );
176 		deflab( p->bn.label );
177 		printf( "	clrl	%s\n", rname(getlr( p, '1' )->tn.rval) );
178 		deflab( m );
179 		return;
180 
181 	case 'P':
182 		cbgen( p->in.op, p->bn.label, c );
183 		return;
184 
185 	case 'A':	/* assignment and load (integer only) */
186 		{
187 		register NODE *l, *r;
188 
189 		if (xdebug) eprint(p, 0, &val, &val);
190 		r = getlr(p, 'R');
191 		if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) {
192 			l = resc;
193 			l->in.type = INT;
194 		} else
195 			l = getlr(p, 'L');
196 		if(r->in.type==FLOAT || r->in.type==DOUBLE
197 		 || l->in.type==FLOAT || l->in.type==DOUBLE)
198 			cerror("float in ZA");
199 		if (r->in.op == ICON)
200 			if(r->in.name[0] == '\0') {
201 				if (r->tn.lval == 0) {
202 					printf("clr");
203 					prtype(l);
204 					printf("	");
205 					adrput(l);
206 					return;
207 				}
208 				if (r->tn.lval < 0 && r->tn.lval >= -63) {
209 					printf("mneg");
210 					prtype(l);
211 					r->tn.lval = -r->tn.lval;
212 					goto ops;
213 				}
214 #ifdef MOVAFASTER
215 			} else {
216 				printf("movab");
217 				printf("	");
218 				acon(r);
219 				printf(",");
220 				adrput(l);
221 				return;
222 #endif MOVAFASTER
223 			}
224 
225 		if (l->in.op == REG) {
226 			if( tlen(l) < tlen(r) ) {
227 				!ISUNSIGNED(l->in.type)?
228 					printf("cvt"):
229 					printf("movz");
230 				prtype(l);
231 				printf("l");
232 				goto ops;
233 			} else
234 				l->in.type = INT;
235 		}
236 		if (tlen(l) == tlen(r)) {
237 			printf("mov");
238 			prtype(l);
239 			goto ops;
240 		} else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
241 			printf("movz");
242 		else
243 			printf("cvt");
244 		prtype(r);
245 		prtype(l);
246 	ops:
247 		printf("	");
248 		adrput(r);
249 		printf(",");
250 		adrput(l);
251 		return;
252 		}
253 
254 	case 'B':	/* get oreg value in temp register for shift */
255 		{
256 		register NODE *r;
257 		if (xdebug) eprint(p, 0, &val, &val);
258 		r = p->in.right;
259 		if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
260 			printf("movl");
261 		else {
262 			printf(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
263 			prtype(r);
264 			printf("l");
265 			}
266 		return;
267 		}
268 
269 	case 'C':	/* num bytes pushed on arg stack */
270 		{
271 		extern int gc_numbytes;
272 		extern int xdebug;
273 
274 		if (xdebug) printf("->%d<-",gc_numbytes);
275 
276 		printf("call%c	$%d",
277 		 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
278 		 gc_numbytes+4);
279 		/* dont change to double (here's the only place to catch it) */
280 		if(p->in.type == FLOAT)
281 			rtyflg = 1;
282 		return;
283 		}
284 
285 	case 'D':	/* INCR and DECR */
286 		zzzcode(p->in.left, 'A');
287 		printf("\n	");
288 
289 	case 'E':	/* INCR and DECR, FOREFF */
290  		if (p->in.right->tn.lval == 1)
291 			{
292 			printf("%s", (p->in.op == INCR ? "inc" : "dec") );
293 			prtype(p->in.left);
294 			printf("	");
295 			adrput(p->in.left);
296 			return;
297 			}
298 		printf("%s", (p->in.op == INCR ? "add" : "sub") );
299 		prtype(p->in.left);
300 		printf("2	");
301 		adrput(p->in.right);
302 		printf(",");
303 		adrput(p->in.left);
304 		return;
305 
306 	case 'F':	/* masked constant for fields */
307 		printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
308 		return;
309 
310 	case 'H':	/* opcode for shift */
311 		if(p->in.op == LS || p->in.op == ASG LS)
312 			printf("shll");
313 		else if(ISUNSIGNED(p->in.left->in.type))
314 			printf("shrl");
315 		else
316 			printf("shar");
317 		return;
318 
319 	case 'L':	/* type of left operand */
320 	case 'R':	/* type of right operand */
321 		{
322 		register NODE *n;
323 		extern int xdebug;
324 
325 		n = getlr ( p, c);
326 		if (xdebug) printf("->%d<-", n->in.type);
327 
328 		prtype(n);
329 		return;
330 		}
331 
332 	case 'M':  /* initiate ediv for mod and unsigned div */
333 		{
334 		register char *r;
335 		m = getlr(p, '1')->tn.rval;
336 		r = rname(m);
337 		printf("\tclrl\t%s\n\tmovl\t", r);
338 		adrput(p->in.left);
339 		printf(",%s\n", rname(m+1));
340 		if(!ISUNSIGNED(p->in.type)) { 	/* should be MOD */
341 			m = getlab();
342 			printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
343 			deflab(m);
344 		}
345 		}
346 		return;
347 
348 	case 'U':
349 		/* Truncate int for type conversions:
350 		    LONG|ULONG -> CHAR|UCHAR|SHORT|USHORT
351 		    SHORT|USHORT -> CHAR|UCHAR
352 		   increment offset to correct byte */
353 		{
354 		register NODE *p1;
355 		int dif;
356 
357 		p1 = p->in.left;
358 		switch( p1->in.op ){
359 		case NAME:
360 		case OREG:
361 			dif = tlen(p1)-tlen(p);
362 			p1->tn.lval += dif;
363 			adrput(p1);
364 			p1->tn.lval -= dif;
365 			return;
366 		default:
367 			cerror( "Illegal ZU type conversion" );
368 			return;
369 			}
370 		}
371 
372 	case 'T':	/* rounded structure length for arguments */
373 		{
374 		int size;
375 
376 		size = p->stn.stsize;
377 		SETOFF( size, 4);
378 		printf("movab	-%d(sp),sp", size);
379 		return;
380 		}
381 
382 	case 'S':  /* structure assignment */
383 		stasg(p);
384 		break;
385 
386 	default:
387 		cerror( "illegal zzzcode" );
388 		}
389 	}
390 
391 #define	MOVB(dst, src, off) { \
392 	printf("\tmovb\t"); upput(src, off); putchar(','); \
393 	upput(dst, off); putchar('\n'); \
394 }
395 #define	MOVW(dst, src, off) { \
396 	printf("\tmovw\t"); upput(src, off); putchar(','); \
397 	upput(dst, off); putchar('\n'); \
398 }
399 #define	MOVL(dst, src, off) { \
400 	printf("\tmovl\t"); upput(src, off); putchar(','); \
401 	upput(dst, off); putchar('\n'); \
402 }
403 /*
404  * Generate code for a structure assignment.
405  */
406 stasg(p)
407 	register NODE *p;
408 {
409 	register NODE *l, *r;
410 	register int size;
411 
412 	switch (p->in.op) {
413 	case STASG:			/* regular assignment */
414 		l = p->in.left;
415 		r = p->in.right;
416 		break;
417 	case STARG:			/* place arg on the stack */
418 		l = getlr(p, '3');
419 		r = p->in.left;
420 		break;
421 	default:
422 		cerror("STASG bad");
423 		/*NOTREACHED*/
424 	}
425 	/*
426 	 * Pun source for use in code generation.
427 	 */
428 	switch (r->in.op) {
429 	case ICON:
430 		r->in.op = NAME;
431 		break;
432 	case REG:
433 		r->in.op = OREG;
434 		break;
435 	default:
436 		cerror( "STASG-r" );
437 		/*NOTREACHED*/
438 	}
439 	size = p->stn.stsize;
440 	if (size <= 0 || size > 65535)
441 		cerror("structure size out of range");
442 	/*
443 	 * Generate optimized code based on structure size
444 	 * and alignment properties....
445 	 */
446 	switch (size) {
447 
448 	case 1:
449 		printf("\tmovb\t");
450 	optimized:
451 		adrput(r);
452 		printf(",");
453 		adrput(l);
454 		printf("\n");
455 werror("optimized structure assignment (size %d alignment %d)", size, p->stn.stalign);
456 		break;
457 
458 	case 2:
459 		if (p->stn.stalign != 2) {
460 			MOVB(l, r, SZCHAR);
461 			printf("\tmovb\t");
462 		} else
463 			printf("\tmovw\t");
464 		goto optimized;
465 
466 	case 4:
467 		if (p->stn.stalign != 4) {
468 			if (p->stn.stalign != 2) {
469 				MOVB(l, r, 3*SZCHAR);
470 				MOVB(l, r, 2*SZCHAR);
471 				MOVB(l, r, 1*SZCHAR);
472 				printf("\tmovb\t");
473 			} else {
474 				MOVW(l, r, SZSHORT);
475 				printf("\tmovw\t");
476 			}
477 		} else
478 			printf("\tmovl\t");
479 		goto optimized;
480 
481 	case 6:
482 		if (p->stn.stalign != 2)
483 			goto movblk;
484 		MOVW(l, r, 2*SZSHORT);
485 		MOVW(l, r, 1*SZSHORT);
486 		printf("\tmovw\t");
487 		goto optimized;
488 
489 	case 8:
490 		if (p->stn.stalign == 4) {
491 			MOVL(l, r, SZLONG);
492 			printf("\tmovl\t");
493 			goto optimized;
494 		}
495 		/* fall thru...*/
496 
497 	default:
498 	movblk:
499 		/*
500 		 * Can we ever get a register conflict with R1 here?
501 		 */
502 		printf("\tmovab\t");
503 		adrput(l);
504 		printf(",r1\n\tmovab\t");
505 		adrput(r);
506 		printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
507 		rname(R2);
508 		break;
509 	}
510 	/*
511 	 * Reverse above pun for reclaim.
512 	 */
513 	if (r->in.op == NAME)
514 		r->in.op = ICON;
515 	else if (r->in.op == OREG)
516 		r->in.op = REG;
517 }
518 
519 /*
520  * Output the address of the second item in the
521  * pair pointed to by p.
522  */
523 upput(p, size)
524 	register NODE *p;
525 {
526 	CONSZ save;
527 
528 	if (p->in.op == FLD)
529 		p = p->in.left;
530 	switch (p->in.op) {
531 
532 	case NAME:
533 	case OREG:
534 		save = p->tn.lval;
535 		p->tn.lval += size/SZCHAR;
536 		adrput(p);
537 		p->tn.lval = save;
538 		break;
539 
540 	case REG:
541 		if (size == SZLONG) {
542 			printf("%s", rname(p->tn.rval+1));
543 			break;
544 		}
545 		/* fall thru... */
546 
547 	default:
548 		cerror("illegal upper address op %s size %d",
549 		    opst[p->tn.op], size);
550 		/*NOTREACHED*/
551 	}
552 }
553 
554 rmove( rt, rs, t ) TWORD t;{
555 	printf( "	movl	%s,%s\n", rname(rs), rname(rt) );
556 	if(t==DOUBLE)
557 		printf( "	movl	%s,%s\n", rname(rs+1), rname(rt+1) );
558 	}
559 
560 struct respref
561 respref[] = {
562 	INTAREG|INTBREG,	INTAREG|INTBREG,
563 	INAREG|INBREG,	INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
564 	INTEMP,	INTEMP,
565 	FORARG,	FORARG,
566 	INTEMP,	INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
567 	0,	0 };
568 
569 setregs(){ /* set up temporary registers */
570 	fregs = 6;	/* tbl- 6 free regs on Tahoe (0-5) */
571 	}
572 
573 #ifndef szty
574 szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
575 	return(t==DOUBLE ? 2 : 1 );
576 	}
577 #endif
578 
579 rewfld( p ) NODE *p; {
580 	return(1);
581 	}
582 
583 callreg(p) NODE *p; {
584 	return( R0 );
585 	}
586 
587 base( p ) register NODE *p; {
588 	register int o = p->in.op;
589 
590 	if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
591 	if( o==REG ) return( p->tn.rval );
592     if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
593 		return( p->in.left->tn.rval );
594     if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
595 		return( p->tn.rval + 0200*1 );
596 	return( -1 );
597 	}
598 
599 offset( p, tyl ) register NODE *p; int tyl; {
600 
601 	if(tyl > 8) return( -1 );
602 	if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
603 	if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
604 	      (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
605 	      && (1<<p->in.right->tn.lval)==tyl))
606 		return( p->in.left->tn.rval );
607 	return( -1 );
608 	}
609 
610 makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
611 	register NODE *t;
612 	register int i;
613 	NODE *f;
614 
615 	p->in.op = OREG;
616 	f = p->in.left; 	/* have to free this subtree later */
617 
618 	/* init base */
619 	switch (q->in.op) {
620 		case ICON:
621 		case REG:
622 		case OREG:
623 			t = q;
624 			break;
625 
626 		case MINUS:
627 			q->in.right->tn.lval = -q->in.right->tn.lval;
628 		case PLUS:
629 			t = q->in.right;
630 			break;
631 
632 		case UNARY MUL:
633 			t = q->in.left->in.left;
634 			break;
635 
636 		default:
637 			cerror("illegal makeor2");
638 	}
639 
640 	p->tn.lval = t->tn.lval;
641 #ifndef FLEXNAMES
642 	for(i=0; i<NCHNAM; ++i)
643 		p->in.name[i] = t->in.name[i];
644 #else
645 	p->in.name = t->in.name;
646 #endif
647 
648 	/* init offset */
649 	p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
650 
651 	tfree(f);
652 	return;
653 	}
654 
655 canaddr( p ) NODE *p; {
656 	register int o = p->in.op;
657 
658 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
659 	return(0);
660 	}
661 
662 #ifndef shltype
663 shltype( o, p ) register NODE *p; {
664 	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
665 	}
666 #endif
667 
668 flshape( p ) NODE *p; {
669 	register int o = p->in.op;
670 
671 	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
672 	return(0);
673 	}
674 
675 shtemp( p ) register NODE *p; {
676 	if( p->in.op == STARG ) p = p->in.left;
677 	return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
678 	}
679 
680 shumul( p ) register NODE *p; {
681 	register int o;
682 	extern int xdebug;
683 
684 	if (xdebug) {
685 		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
686 		printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
687 		}
688 
689 	o = p->in.op;
690 	if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
691 	 && p->in.type != PTR+DOUBLE)
692 		return( STARNM );
693 
694 	return( 0 );
695 	}
696 
697 special( p, shape ) register NODE *p; {
698 	if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
699 	else return(0);
700 }
701 
702 adrcon( val ) CONSZ val; {
703 	printf(ACONFMT, val);
704 	}
705 
706 conput( p ) register NODE *p; {
707 	switch( p->in.op ){
708 
709 	case ICON:
710 		acon( p );
711 		return;
712 
713 	case REG:
714 		printf( "%s", rname(p->tn.rval) );
715 		return;
716 
717 	default:
718 		cerror( "illegal conput" );
719 		}
720 	}
721 
722 insput( p ) NODE *p; {
723 	cerror( "insput" );
724 	}
725 
726 adrput( p ) register NODE *p; {
727 	register int r;
728 	/* output an address, with offsets, from p */
729 
730 	if( p->in.op == FLD ){
731 		p = p->in.left;
732 		}
733 	switch( p->in.op ){
734 
735 	case NAME:
736 		acon( p );
737 		return;
738 
739 	case ICON:
740 		/* addressable value of the constant */
741 		printf( "$" );
742 		acon( p );
743 		return;
744 
745 	case REG:
746 		printf( "%s", rname(p->tn.rval) );
747 		if(p->in.type == DOUBLE)	/* for entry mask */
748 			(void) rname(p->tn.rval+1);
749 		return;
750 
751 	case OREG:
752 		r = p->tn.rval;
753 		if( R2TEST(r) ){ /* double indexing */
754 			register int flags;
755 
756 			flags = R2UPK3(r);
757 			if( flags & 1 ) printf("*");
758 			if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
759 			if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
760 			printf( "[%s]", rname(R2UPK2(r)) );
761 			return;
762 			}
763 		if( r == FP && p->tn.lval > 0 ){  /* in the argument region */
764 			if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
765 			printf( CONFMT, p->tn.lval );
766 			printf( "(fp)" );
767 			return;
768 			}
769 		if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
770 		printf( "(%s)", rname(p->tn.rval) );
771 		return;
772 
773 	case UNARY MUL:
774 		/* STARNM or STARREG found */
775 		if( tshape(p, STARNM) ) {
776 			printf( "*" );
777 			adrput( p->in.left);
778 			}
779 		return;
780 
781 	default:
782 		cerror( "illegal address" );
783 		return;
784 
785 		}
786 
787 	}
788 
789 acon( p ) register NODE *p; { /* print out a constant */
790 
791 	if( p->in.name[0] == '\0' ){
792 		printf( CONFMT, p->tn.lval);
793 		}
794 	else if( p->tn.lval == 0 ) {
795 #ifndef FLEXNAMES
796 		printf( "%.8s", p->in.name );
797 #else
798 		printf( "%s", p->in.name );
799 #endif
800 		}
801 	else {
802 #ifndef FLEXNAMES
803 		printf( "%.8s+", p->in.name );
804 #else
805 		printf( "%s+", p->in.name );
806 #endif
807 		printf( CONFMT, p->tn.lval );
808 		}
809 	}
810 
811 genscall( p, cookie ) register NODE *p; {
812 	/* structure valued call */
813 	return( gencall( p, cookie ) );
814 	}
815 
816 genfcall( p, cookie ) register NODE *p; {
817 	register NODE *p1;
818 	register int m;
819 	static char *funcops[6] = {
820 		"sin", "cos", "sqrt", "exp", "log", "atan"
821 	};
822 
823 	/* generate function opcodes */
824 	if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
825 	 (p1 = p->in.left)->in.op==ICON &&
826 	 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
827 #ifdef FLEXNAMES
828 		p1->in.name++;
829 #else
830 		strcpy(p1->in.name, p1->in.name[1]);
831 #endif
832 		for(m=0; m<6; m++)
833 			if(!strcmp(p1->in.name, funcops[m]))
834 				break;
835 		if(m >= 6)
836 			uerror("no opcode for fortarn function %s", p1->in.name);
837 	} else
838 		uerror("illegal type of fortarn function");
839 	p1 = p->in.right;
840 	p->in.op = FORTCALL;
841 	if(!canaddr(p1))
842 		order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
843 	m = match( p, INTAREG|INTBREG );
844 	return(m != MDONE);
845 }
846 
847 /* tbl */
848 int gc_numbytes;
849 /* tbl */
850 
851 gencall( p, cookie ) register NODE *p; {
852 	/* generate the call given by p */
853 	register NODE *p1, *ptemp;
854 	register int temp, temp1;
855 	register int m;
856 
857 	if( p->in.right ) temp = argsize( p->in.right );
858 	else temp = 0;
859 
860 	if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
861 		/* set aside room for structure return */
862 
863 		if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
864 		else temp1 = temp;
865 		}
866 
867 	if( temp > maxargs ) maxargs = temp;
868 	SETOFF(temp1,4);
869 
870 	if( p->in.right ){ /* make temp node, put offset in, and generate args */
871 		ptemp = talloc();
872 		ptemp->in.op = OREG;
873 		ptemp->tn.lval = -1;
874 		ptemp->tn.rval = SP;
875 #ifndef FLEXNAMES
876 		ptemp->in.name[0] = '\0';
877 #else
878 		ptemp->in.name = "";
879 #endif
880 		ptemp->in.rall = NOPREF;
881 		ptemp->in.su = 0;
882 		genargs( p->in.right, ptemp );
883 		ptemp->in.op = FREE;
884 		}
885 
886 	p1 = p->in.left;
887 	if( p1->in.op != ICON ){
888 		if( p1->in.op != REG ){
889 			if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
890 				if( p1->in.op != NAME ){
891 					order( p1, INAREG );
892 					}
893 				}
894 			}
895 		}
896 
897 /* tbl
898 	setup gc_numbytes so reference to ZC works */
899 
900 	gc_numbytes = temp&(0x3ff);
901 
902 	p->in.op = UNARY CALL;
903 	m = match( p, INTAREG|INTBREG );
904 
905 	return(m != MDONE);
906 	}
907 
908 /* tbl */
909 char *
910 ccbranches[] = {
911 	"eql",
912 	"neq",
913 	"leq",
914 	"lss",
915 	"geq",
916 	"gtr",
917 	"lequ",
918 	"lssu",
919 	"gequ",
920 	"gtru",
921 	};
922 /* tbl */
923 
924 cbgen( o, lab, mode ) { /*   printf conditional and unconditional branches */
925 
926 		if(o != 0 && (o < EQ || o > UGT ))
927 			cerror( "bad conditional branch: %s", opst[o] );
928 		printf( "	j%s	L%d\n",
929 		 o == 0 ? "br" : ccbranches[o-EQ], lab );
930 	}
931 
932 nextcook( p, cookie ) NODE *p; {
933 	/* we have failed to match p with cookie; try another */
934 	if( cookie == FORREW ) return( 0 );  /* hopeless! */
935 	if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
936 	if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
937 	return( FORREW );
938 	}
939 
940 lastchance( p, cook ) NODE *p; {
941 	/* forget it! */
942 	return(0);
943 	}
944 
945 optim2( p ) register NODE *p; {
946 # ifdef ONEPASS
947 	/* do local tree transformations and optimizations */
948 # define RV(p) p->in.right->tn.lval
949 # define nncon(p)	((p)->in.op == ICON && (p)->in.name[0] == 0)
950 	register int o = p->in.op;
951 	register int i;
952 
953 	/* change unsigned mods and divs to logicals (mul is done in mip & c2) */
954 	if(optype(o) == BITYPE && ISUNSIGNED(p->in.left->in.type)
955 	 && nncon(p->in.right) && (i=ispow2(RV(p)))>=0){
956 		switch(o) {
957 		case DIV:
958 		case ASG DIV:
959 			p->in.op = RS;
960 			RV(p) = i;
961 			break;
962 		case MOD:
963 		case ASG MOD:
964 			p->in.op = AND;
965 			RV(p)--;
966 			break;
967 		default:
968 			return;
969 		}
970 		if(asgop(o))
971 			p->in.op = ASG p->in.op;
972 	}
973 # endif
974 }
975 
976 struct functbl {
977 	int fop;
978 	char *func;
979 } opfunc[] = {
980 	DIV,		"udiv",
981 	ASG DIV,	"udiv",
982 	0
983 };
984 
985 hardops(p)  register NODE *p; {
986 	/* change hard to do operators into function calls.  */
987 	register NODE *q;
988 	register struct functbl *f;
989 	register int o;
990 	register TWORD t, t1, t2;
991 
992 	o = p->in.op;
993 
994 	for( f=opfunc; f->fop; f++ ) {
995 		if( o==f->fop ) goto convert;
996 	}
997 	return;
998 
999 	convert:
1000 	t = p->in.type;
1001 	t1 = p->in.left->in.type;
1002 	t2 = p->in.right->in.type;
1003 	if ( t1 != UNSIGNED && (t2 != UNSIGNED)) return;
1004 
1005 	/* need to rewrite tree for ASG OP */
1006 	/* must change ASG OP to a simple OP */
1007 	if( asgop( o ) ) {
1008 		q = talloc();
1009 		q->in.op = NOASG ( o );
1010 		q->in.rall = NOPREF;
1011 		q->in.type = p->in.type;
1012 		q->in.left = tcopy(p->in.left);
1013 		q->in.right = p->in.right;
1014 		p->in.op = ASSIGN;
1015 		p->in.right = q;
1016 		zappost(q->in.left); /* remove post-INCR(DECR) from new node */
1017 		fixpre(q->in.left);	/* change pre-INCR(DECR) to +/-	*/
1018 		p = q;
1019 
1020 	}
1021 	/* turn logicals to compare 0 */
1022 	else if( logop( o ) ) {
1023 		ncopy(q = talloc(), p);
1024 		p->in.left = q;
1025 		p->in.right = q = talloc();
1026 		q->in.op = ICON;
1027 		q->in.type = INT;
1028 #ifndef FLEXNAMES
1029 		q->in.name[0] = '\0';
1030 #else
1031 		q->in.name = "";
1032 #endif
1033 		q->tn.lval = 0;
1034 		q->tn.rval = 0;
1035 		p = p->in.left;
1036 	}
1037 
1038 	/* build comma op for args to function */
1039 	t1 = p->in.left->in.type;
1040 	t2 = 0;
1041 	if ( optype(p->in.op) == BITYPE) {
1042 		q = talloc();
1043 		q->in.op = CM;
1044 		q->in.rall = NOPREF;
1045 		q->in.type = INT;
1046 		q->in.left = p->in.left;
1047 		q->in.right = p->in.right;
1048 		t2 = p->in.right->in.type;
1049 	} else
1050 		q = p->in.left;
1051 
1052 	p->in.op = CALL;
1053 	p->in.right = q;
1054 
1055 	/* put function name in left node of call */
1056 	p->in.left = q = talloc();
1057 	q->in.op = ICON;
1058 	q->in.rall = NOPREF;
1059 	q->in.type = INCREF( FTN + p->in.type );
1060 #ifndef FLEXNAMES
1061 		strcpy( q->in.name, f->func );
1062 #else
1063 		q->in.name = f->func;
1064 #endif
1065 	q->tn.lval = 0;
1066 	q->tn.rval = 0;
1067 
1068 	}
1069 
1070 zappost(p) NODE *p; {
1071 	/* look for ++ and -- operators and remove them */
1072 
1073 	register int o, ty;
1074 	register NODE *q;
1075 	o = p->in.op;
1076 	ty = optype( o );
1077 
1078 	switch( o ){
1079 
1080 	case INCR:
1081 	case DECR:
1082 			q = p->in.left;
1083 			p->in.right->in.op = FREE;  /* zap constant */
1084 			ncopy( p, q );
1085 			q->in.op = FREE;
1086 			return;
1087 
1088 		}
1089 
1090 	if( ty == BITYPE ) zappost( p->in.right );
1091 	if( ty != LTYPE ) zappost( p->in.left );
1092 }
1093 
1094 fixpre(p) NODE *p; {
1095 
1096 	register int o, ty;
1097 	o = p->in.op;
1098 	ty = optype( o );
1099 
1100 	switch( o ){
1101 
1102 	case ASG PLUS:
1103 			p->in.op = PLUS;
1104 			break;
1105 	case ASG MINUS:
1106 			p->in.op = MINUS;
1107 			break;
1108 		}
1109 
1110 	if( ty == BITYPE ) fixpre( p->in.right );
1111 	if( ty != LTYPE ) fixpre( p->in.left );
1112 }
1113 
1114 NODE * addroreg(l) NODE *l;
1115 				/* OREG was built in clocal()
1116 				 * for an auto or formal parameter
1117 				 * now its address is being taken
1118 				 * local code must unwind it
1119 				 * back to PLUS/MINUS REG ICON
1120 				 * according to local conventions
1121 				 */
1122 {
1123 	cerror("address of OREG taken");
1124 }
1125 
1126 # ifndef ONEPASS
1127 main( argc, argv ) char *argv[]; {
1128 	return( mainp2( argc, argv ) );
1129 	}
1130 # endif
1131 
1132 myreader(p) register NODE *p; {
1133 	walkf( p, hardops );	/* convert ops to function calls */
1134 	canon( p );		/* expands r-vals for fileds */
1135 	walkf( p, optim2 );
1136 	}
1137