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