xref: /original-bsd/old/pcc/mip/reader.c (revision 542201aa)
1 #ifndef lint
2 static char *sccsid ="@(#)reader.c	4.8 (Berkeley) 12/10/87";
3 #endif lint
4 
5 # include "pass2.h"
6 
7 /*	some storage declarations */
8 
9 # ifndef ONEPASS
10 NODE node[TREESZ];
11 char filename[100] = "";  /* the name of the file */
12 int ftnno;  /* number of current function */
13 int lineno;
14 # else
15 # define NOMAIN
16 #endif
17 
18 int nrecur;
19 int lflag;
20 #ifdef FORT
21 int Oflag = 0;
22 #endif
23 extern int Wflag;
24 int edebug = 0;
25 int xdebug = 0;
26 int udebug = 0;
27 int vdebug = 0;
28 
29 OFFSZ tmpoff;  /* offset for first temporary, in bits for current block */
30 OFFSZ maxoff;  /* maximum temporary offset over all blocks in current ftn, in bits */
31 int maxtreg;
32 
33 NODE *stotree;
34 int stocook;
35 
36 OFFSZ baseoff = 0;
37 OFFSZ maxtemp = 0;
38 
39 p2init( argc, argv ) char *argv[];{
40 	/* set the values of the pass 2 arguments */
41 
42 	register int c;
43 	register char *cp;
44 	register files;
45 
46 	allo0();  /* free all regs */
47 	files = 0;
48 
49 	for( c=1; c<argc; ++c ){
50 		if( *(cp=argv[c]) == '-' ){
51 			while( *++cp ){
52 				switch( *cp ){
53 
54 				case 'X':  /* pass1 flags */
55 					while( *++cp ) { /* VOID */ }
56 					--cp;
57 					break;
58 
59 				case 'l':  /* linenos */
60 					++lflag;
61 					break;
62 
63 				case 'e':  /* expressions */
64 					++edebug;
65 					break;
66 
67 				case 'o':  /* orders */
68 					++odebug;
69 					break;
70 
71 				case 'r':  /* register allocation */
72 					++rdebug;
73 					break;
74 
75 				case 'a':  /* rallo */
76 					++radebug;
77 					break;
78 
79 				case 'v':
80 					++vdebug;
81 					break;
82 
83 				case 't':  /* ttype calls */
84 					++tdebug;
85 					break;
86 
87 				case 's':  /* shapes */
88 					++sdebug;
89 					break;
90 
91 				case 'u':  /* Sethi-Ullman testing (machine dependent) */
92 					++udebug;
93 					break;
94 
95 				case 'x':  /* general machine-dependent debugging flag */
96 					++xdebug;
97 					break;
98 
99 				case 'w':
100 				case 'W':  /* shut up warnings */
101 
102 					++Wflag;
103 					break;
104 
105 #ifdef FORT
106 				case 'O':  /* optimizing */
107 					++Oflag;
108 					break;
109 #endif
110 
111 				default:
112 					cerror( "bad option: %c", *cp );
113 					}
114 				}
115 			}
116 		else files = 1;  /* assumed to be a filename */
117 		}
118 
119 	mkdope();
120 	setrew();
121 	return( files );
122 
123 	}
124 
125 # ifndef NOMAIN
126 
127 unsigned int caloff();
128 unsigned int offsz;
129 mainp2( argc, argv ) char *argv[]; {
130 	register files;
131 	register temp;
132 	register c;
133 	register char *cp;
134 	register NODE *p;
135 
136 	offsz = caloff();
137 	files = p2init( argc, argv );
138 	tinit();
139 
140 	reread:
141 
142 	if( files ){
143 		while( files < argc && argv[files][0] == '-' ) {
144 			++files;
145 			}
146 		if( files > argc ) return( nerrors );
147 		freopen( argv[files], "r", stdin );
148 		}
149 	while( (c=getchar()) > 0 ) switch( c ){
150 	case ')':
151 	default:
152 		/* copy line unchanged */
153 		if ( c != ')' )
154 			PUTCHAR( c );  /*  initial tab  */
155 		while( (c=getchar()) > 0 ){
156 			PUTCHAR(c);
157 			if( c == '\n' ) break;
158 			}
159 		continue;
160 
161 	case BBEG:
162 		/* beginning of a block */
163 		temp = rdin(10);  /* ftnno */
164 		tmpoff = baseoff = (unsigned int) rdin(10); /* autooff for block gives max offset of autos in block */
165 		maxtreg = rdin(10);
166 		if( getchar() != '\n' ) cerror( "intermediate file format error");
167 
168 		if( temp != ftnno ){ /* beginning of function */
169 			maxoff = baseoff;
170 			ftnno = temp;
171 			maxtemp = 0;
172 			}
173 		else {
174 			if( baseoff > maxoff ) maxoff = baseoff;
175 			/* maxoff at end of ftn is max of autos and temps
176 			   over all blocks in the function */
177 			}
178 		setregs();
179 		continue;
180 
181 	case BEND:  /* end of block */
182 		SETOFF( maxoff, ALSTACK );
183 		eobl2();
184 		while( (c=getchar()) != '\n' ){
185 			if( c <= 0 ) cerror( "intermediate file format eof" );
186 			}
187 		continue;
188 
189 	case EXPR:
190 		/* compile code for an expression */
191 		lineno = rdin( 10 );
192 		for( cp=filename; (*cp=getchar()) != '\n'; ++cp ) ; /* VOID, reads filename */
193 		*cp = '\0';
194 		if( lflag ) lineid( lineno, filename );
195 
196 		tmpoff = baseoff;  /* expression at top level reuses temps */
197 		p = eread();
198 
199 # ifndef BUG4
200 		if( edebug ) fwalk( p, eprint, 0 );
201 # endif
202 
203 # ifdef MYREADER
204 		MYREADER(p);  /* do your own laundering of the input */
205 # endif
206 
207 		nrecur = 0;
208 		delay( p );  /* expression statement  throws out results */
209 		reclaim( p, RNULL, 0 );
210 
211 		allchk();
212 		tcheck();
213 		continue;
214 
215 		}
216 
217 	/* EOF */
218 	if( files ) goto reread;
219 	return(nerrors);
220 
221 	}
222 
223 # endif
224 
225 # ifdef ONEPASS
226 
227 p2compile( p ) NODE *p; {
228 
229 	if( lflag ) lineid( lineno, filename );
230 	tmpoff = baseoff;  /* expression at top level reuses temps */
231 	/* generate code for the tree p */
232 # ifndef BUG4
233 	if( edebug ) fwalk( p, eprint, 0 );
234 # endif
235 
236 # ifdef MYREADER
237 	MYREADER(p);  /* do your own laundering of the input */
238 # endif
239 	nrecur = 0;
240 	delay( p );  /* do the code generation */
241 	reclaim( p, RNULL, 0 );
242 	allchk();
243 	/* can't do tcheck here; some stuff (e.g., attributes) may be around from first pass */
244 	/* first pass will do it... */
245 	}
246 
247 p2bbeg( aoff, myreg ) {
248 	static int myftn = -1;
249 
250 	tmpoff = baseoff = (unsigned int) aoff;
251 	maxtreg = myreg;
252 	if( myftn != ftnno ){ /* beginning of function */
253 		maxoff = baseoff;
254 		myftn = ftnno;
255 		maxtemp = 0;
256 		}
257 	else {
258 		if( baseoff > maxoff ) maxoff = baseoff;
259 		/* maxoff at end of ftn is max of autos and temps over all blocks */
260 		}
261 	setregs();
262 	}
263 
264 p2bend(){
265 	SETOFF( maxoff, ALSTACK );
266 	eobl2();
267 	}
268 
269 # endif
270 
271 NODE *deltrees[DELAYS];
272 int deli;
273 
274 delay( p ) register NODE *p; {
275 	/* look in all legal places for COMOP's and ++ and -- ops to delay */
276 	/* note; don't delay ++ and -- within calls or things like
277 	/* getchar (in their macro forms) will start behaving strangely */
278 	register i;
279 
280 	/* look for visible COMOPS, and rewrite repeatedly */
281 
282 	while( delay1( p ) ) { /* VOID */ }
283 
284 	/* look for visible, delayable ++ and -- */
285 
286 	deli = 0;
287 	delay2( p );
288 	codgen( p, FOREFF );  /* do what is left */
289 	for( i = 0; i<deli; ++i ) codgen( deltrees[i], FOREFF );  /* do the rest */
290 	}
291 
292 delay1( p ) register NODE *p; {  /* look for COMOPS */
293 	register o, ty;
294 
295 	o = p->in.op;
296 	ty = optype( o );
297 	if( ty == LTYPE ) return( 0 );
298 	else if( ty == UTYPE ) return( delay1( p->in.left ) );
299 
300 	switch( o ){
301 
302 	case QUEST:
303 	case ANDAND:
304 	case OROR:
305 		/* don't look on RHS */
306 		return( delay1(p->in.left ) );
307 
308 	case COMOP:  /* the meat of the routine */
309 		delay( p->in.left );  /* completely evaluate the LHS */
310 		/* rewrite the COMOP */
311 		{ register NODE *q;
312 			q = p->in.right;
313 			ncopy( p, p->in.right );
314 			q->in.op = FREE;
315 			}
316 		return( 1 );
317 		}
318 
319 	return( delay1(p->in.left) || delay1(p->in.right ) );
320 	}
321 
322 delay2( p ) register NODE *p; {
323 
324 	/* look for delayable ++ and -- operators */
325 
326 	register o, ty;
327 	o = p->in.op;
328 	ty = optype( o );
329 
330 	switch( o ){
331 
332 	case NOT:
333 	case QUEST:
334 	case ANDAND:
335 	case OROR:
336 	case CALL:
337 	case UNARY CALL:
338 	case STCALL:
339 	case UNARY STCALL:
340 	case FORTCALL:
341 	case UNARY FORTCALL:
342 	case COMOP:
343 	case CBRANCH:
344 		/* for the moment, don't delay past a conditional context, or
345 		/* inside of a call */
346 		return;
347 
348 	case UNARY MUL:
349 		/* if *p++, do not rewrite */
350 		if( autoincr( p ) ) return;
351 		break;
352 
353 	case INCR:
354 	case DECR:
355 		if( deltest( p ) ){
356 			if( deli < DELAYS ){
357 				register NODE *q;
358 				deltrees[deli++] = tcopy(p);
359 				q = p->in.left;
360 				p->in.right->in.op = FREE;  /* zap constant */
361 				ncopy( p, q );
362 				q->in.op = FREE;
363 				return;
364 				}
365 			}
366 
367 		}
368 
369 	if( ty == BITYPE ) delay2( p->in.right );
370 	if( ty != LTYPE ) delay2( p->in.left );
371 	}
372 
373 codgen( p, cookie ) NODE *p; {
374 
375 	/* generate the code for p;
376 	   order may call codgen recursively */
377 	/* cookie is used to describe the context */
378 
379 	for(;;){
380 		canon(p);  /* creats OREG from * if possible and does sucomp */
381 		stotree = NIL;
382 # ifndef BUG4
383 		if( edebug ){
384 			printf( "store called on:\n" );
385 			fwalk( p, eprint, 0 );
386 			}
387 # endif
388 		store(p);
389 		if( stotree==NIL ) break;
390 
391 		/* because it's minimal, can do w.o. stores */
392 
393 		order( stotree, stocook );
394 		}
395 
396 	order( p, cookie );
397 
398 	}
399 
400 # ifndef BUG4
401 char *cnames[] = {
402 	"SANY",
403 	"SAREG",
404 	"STAREG",
405 	"SBREG",
406 	"STBREG",
407 	"SCC",
408 	"SNAME",
409 	"SCON",
410 	"SFLD",
411 	"SOREG",
412 # ifdef WCARD1
413 	"WCARD1",
414 # else
415 	"STARNM",
416 # endif
417 # ifdef WCARD2
418 	"WCARD2",
419 # else
420 	"STARREG",
421 # endif
422 	"INTEMP",
423 	"FORARG",
424 	"SWADD",
425 	0,
426 	};
427 
428 prcook( cookie ){
429 
430 	/* print a nice-looking description of cookie */
431 
432 	int i, flag;
433 
434 	if( cookie & SPECIAL ){
435 		if( cookie == SZERO ) printf( "SZERO" );
436 		else if( cookie == SONE ) printf( "SONE" );
437 		else if( cookie == SMONE ) printf( "SMONE" );
438 		else if( cookie == SCCON ) printf( "SCCON" );
439 		else if( cookie == SSCON ) printf( "SSCON" );
440 		else if( cookie == SSOREG ) printf( "SSOREG" );
441 		else printf( "SPECIAL+%d", cookie & ~SPECIAL );
442 		return;
443 		}
444 
445 	flag = 0;
446 	for( i=0; cnames[i]; ++i ){
447 		if( cookie & (1<<i) ){
448 			if( flag ) printf( "|" );
449 			++flag;
450 			printf( cnames[i] );
451 			}
452 		}
453 
454 	}
455 # endif
456 
457 int odebug = 0;
458 
459 order(p,cook) register NODE *p; {
460 
461 	register o, ty, m;
462 	int m1;
463 	int cookie;
464 	register NODE *p1, *p2;
465 
466 	cookie = cook;
467 	rcount();
468 	canon(p);
469 	rallo( p, p->in.rall );
470 	goto first;
471 	/* by this time, p should be able to be generated without stores;
472 	   the only question is how */
473 
474 	again:
475 
476 	if ( p->in.op == FREE )
477 		return;		/* whole tree was done */
478 	cookie = cook;
479 	rcount();
480 	canon(p);
481 	rallo( p, p->in.rall );
482 	/* if any rewriting and canonicalization has put
483 	 * the tree (p) into a shape that cook is happy
484 	 * with (exclusive of FOREFF, FORREW, and INTEMP)
485 	 * then we are done.
486 	 * this allows us to call order with shapes in
487 	 * addition to cookies and stop short if possible.
488 	 */
489 	if( tshape(p, cook &(~(FOREFF|FORREW|INTEMP))) )return;
490 
491 	first:
492 # ifndef BUG4
493 	if( odebug ){
494 		printf( "order( %o, ", p );
495 		prcook( cookie );
496 		printf( " )\n" );
497 		fwalk( p, eprint, 0 );
498 		}
499 # endif
500 
501 	o = p->in.op;
502 	ty = optype(o);
503 
504 	/* first of all, for most ops, see if it is in the table */
505 
506 	/* look for ops */
507 
508 	switch( m = p->in.op ){
509 
510 	default:
511 		/* look for op in table */
512 		for(;;){
513 			if( (m = match( p, cookie ) ) == MDONE ) goto cleanup;
514 			else if( m == MNOPE ){
515 				if( !(cookie = nextcook( p, cookie ) ) ) goto nomat;
516 				continue;
517 				}
518 			else break;
519 			}
520 		break;
521 
522 	case COMOP:
523 	case FORCE:
524 	case CBRANCH:
525 	case QUEST:
526 	case ANDAND:
527 	case OROR:
528 	case NOT:
529 	case UNARY CALL:
530 	case CALL:
531 	case UNARY STCALL:
532 	case STCALL:
533 	case UNARY FORTCALL:
534 	case FORTCALL:
535 		/* don't even go near the table... */
536 		;
537 
538 		}
539 	/* get here to do rewriting if no match or
540 	   fall through from above for hard ops */
541 
542 	p1 = p->in.left;
543 	if( ty == BITYPE ) p2 = p->in.right;
544 	else p2 = NIL;
545 
546 # ifndef BUG4
547 	if( odebug ){
548 		printf( "order( %o, ", p );
549 		prcook( cook );
550 		printf( " ), cookie " );
551 		prcook( cookie );
552 		printf( ", rewrite %s\n", opst[m] );
553 		}
554 # endif
555 	switch( m ){
556 	default:
557 		nomat:
558 		cerror( "no table entry for op %s", opst[p->in.op] );
559 
560 	case COMOP:
561 		codgen( p1, FOREFF );
562 		p2->in.rall = p->in.rall;
563 		codgen( p2, cookie );
564 		ncopy( p, p2 );
565 		p2->in.op = FREE;
566 		goto cleanup;
567 
568 	case FORCE:
569 		/* recurse, letting the work be done by rallo */
570 		p = p->in.left;
571 		cook = INTAREG|INTBREG;
572 		goto again;
573 
574 	case CBRANCH:
575 		o = p2->tn.lval;
576 		cbranch( p1, -1, o );
577 		p2->in.op = FREE;
578 		p->in.op = FREE;
579 		return;
580 
581 	case QUEST:
582 		cbranch( p1, -1, m=getlab() );
583 		p2->in.left->in.rall = p->in.rall;
584 		codgen( p2->in.left, INTAREG|INTBREG );
585 		/* force right to compute result into same reg used by left */
586 		p2->in.right->in.rall = p2->in.left->tn.rval|MUSTDO;
587 		reclaim( p2->in.left, RNULL, 0 );
588 		cbgen( 0, m1 = getlab(), 'I' );
589 		deflab( m );
590 		codgen( p2->in.right, INTAREG|INTBREG );
591 		deflab( m1 );
592 		p->in.op = REG;  /* set up node describing result */
593 		p->tn.lval = 0;
594 		p->tn.rval = p2->in.right->tn.rval;
595 		p->in.type = p2->in.right->in.type;
596 		tfree( p2->in.right );
597 		p2->in.op = FREE;
598 		goto cleanup;
599 
600 	case ANDAND:
601 	case OROR:
602 	case NOT:  /* logical operators */
603 		/* if here, must be a logical operator for 0-1 value */
604 		cbranch( p, -1, m=getlab() );
605 		p->in.op = CCODES;
606 		p->bn.label = m;
607 		order( p, INTAREG );
608 		goto cleanup;
609 
610 	case FLD:	/* fields of funny type */
611 		if ( p1->in.op == UNARY MUL ){
612 			offstar( p1->in.left );
613 			goto again;
614 			}
615 
616 	case UNARY MINUS:
617 		order( p1, INBREG|INAREG|SOREG );
618 		goto again;
619 
620 	case NAME:
621 		/* all leaves end up here ... */
622 		if( o == REG ) goto nomat;
623 		order( p, INTAREG|INTBREG );
624 		goto again;
625 
626 	case INIT:
627 		uerror( "illegal initialization" );
628 		return;
629 
630 	case UNARY FORTCALL:
631 		p->in.right = NIL;
632 	case FORTCALL:
633 		o = p->in.op = UNARY FORTCALL;
634 		if( genfcall( p, cookie ) ) goto nomat;
635 		goto cleanup;
636 
637 	case UNARY CALL:
638 		p->in.right = NIL;
639 	case CALL:
640 		o = p->in.op = UNARY CALL;
641 		if( gencall( p, cookie ) ) goto nomat;
642 		goto cleanup;
643 
644 	case UNARY STCALL:
645 		p->in.right = NIL;
646 	case STCALL:
647 		o = p->in.op = UNARY STCALL;
648 		if( genscall( p, cookie ) ) goto nomat;
649 		goto cleanup;
650 
651 		/* if arguments are passed in register, care must be taken that reclaim
652 		/* not throw away the register which now has the result... */
653 
654 	case UNARY MUL:
655 		if( cook == FOREFF ){
656 			/* do nothing */
657 			order( p->in.left, FOREFF );
658 			p->in.op = FREE;
659 			return;
660 			}
661 #ifdef R2REGS
662 		/* try to coax a tree into a doubly indexed OREG */
663 		p1 = p->in.left;
664 		if( p1->in.op == PLUS ) {
665 			if( ISPTR(p1->in.left->in.type) &&
666 			    offset(p1->in.right, tlen(p)) >= 0 ) {
667 				order( p1->in.left, INAREG|INTAREG );
668 				goto again;
669 				}
670 			if( ISPTR(p1->in.right->in.type) &&
671 			    offset(p1->in.left, tlen(p)) >= 0 ) {
672 				order( p1->in.right, INAREG|INTAREG );
673 				goto again;
674 				}
675 			}
676 #endif
677 		offstar( p->in.left );
678 		goto again;
679 
680 	case INCR:  /* INCR and DECR */
681 		if( setincr(p) ) goto again;
682 
683 		/* x++ becomes (x += 1) -1; */
684 
685 		if( cook & FOREFF ){  /* result not needed so inc or dec and be done with it */
686 			/* x++ => x += 1 */
687 			p->in.op = (p->in.op==INCR)?ASG PLUS:ASG MINUS;
688 			goto again;
689 			}
690 
691 		p1 = tcopy(p);
692 		reclaim( p->in.left, RNULL, 0 );
693 		p->in.left = p1;
694 		p1->in.op = (p->in.op==INCR)?ASG PLUS:ASG MINUS;
695 		p->in.op = (p->in.op==INCR)?MINUS:PLUS;
696 		goto again;
697 
698 	case STASG:
699 		if( setstr( p ) ) goto again;
700 		goto nomat;
701 
702 	case ASG PLUS:  /* and other assignment ops */
703 		if( setasop(p) ) goto again;
704 
705 		/* there are assumed to be no side effects in LHS */
706 
707 		p2 = tcopy(p);
708 		p->in.op = ASSIGN;
709 		reclaim( p->in.right, RNULL, 0 );
710 		p->in.right = p2;
711 		canon(p);
712 		rallo( p, p->in.rall );
713 
714 # ifndef BUG4
715 		if( odebug ) fwalk( p, eprint, 0 );
716 # endif
717 
718 		order( p2->in.left, INTBREG|INTAREG );
719 		order( p2, INTBREG|INTAREG );
720 		goto again;
721 
722 	case ASSIGN:
723 		if( setasg( p ) ) goto again;
724 		goto nomat;
725 
726 
727 	case BITYPE:
728 		if( setbin( p ) ) goto again;
729 		/* try to replace binary ops by =ops */
730 		switch(o){
731 
732 		case PLUS:
733 		case MINUS:
734 		case MUL:
735 		case DIV:
736 		case MOD:
737 		case AND:
738 		case OR:
739 		case ER:
740 		case LS:
741 		case RS:
742 			p->in.op = ASG o;
743 			goto again;
744 			}
745 		goto nomat;
746 
747 		}
748 
749 	cleanup:
750 
751 	/* if it is not yet in the right state, put it there */
752 
753 	if( cook & FOREFF ){
754 		reclaim( p, RNULL, 0 );
755 		return;
756 		}
757 
758 	if( p->in.op==FREE ) return;
759 
760 	if( tshape( p, cook ) ) return;
761 
762 	if( (m=match(p,cook) ) == MDONE ) return;
763 
764 	/* we are in bad shape, try one last chance */
765 	if( lastchance( p, cook ) ) goto again;
766 
767 	goto nomat;
768 	}
769 
770 int callflag;
771 int fregs;
772 
773 store( p ) register NODE *p; {
774 
775 	/* find a subtree of p which should be stored */
776 
777 	register o, ty;
778 
779 	o = p->in.op;
780 	ty = optype(o);
781 
782 	if( ty == LTYPE ) return;
783 
784 	switch( o ){
785 
786 	case UNARY CALL:
787 	case UNARY FORTCALL:
788 	case UNARY STCALL:
789 		++callflag;
790 		break;
791 
792 	case UNARY MUL:
793 		if( asgop(p->in.left->in.op) ) stoasg( p->in.left, UNARY MUL );
794 		break;
795 
796 	case CALL:
797 	case FORTCALL:
798 	case STCALL:
799 		store( p->in.left );
800 		stoarg( p->in.right, o );
801 		++callflag;
802 		return;
803 
804 	case COMOP:
805 		markcall( p->in.right );
806 		if( p->in.right->in.su > fregs ) SETSTO( p, INTEMP );
807 		store( p->in.left );
808 		return;
809 
810 	case ANDAND:
811 	case OROR:
812 	case QUEST:
813 		markcall( p->in.right );
814 		if( p->in.right->in.su > fregs ) SETSTO( p, INTEMP );
815 	case CBRANCH:   /* to prevent complicated expressions on the LHS from being stored */
816 	case NOT:
817 		constore( p->in.left );
818 		return;
819 
820 		}
821 
822 	if( ty == UTYPE ){
823 		store( p->in.left );
824 		return;
825 		}
826 
827 	if( asgop( p->in.right->in.op ) ) stoasg( p->in.right, o );
828 
829 	if( p->in.su>fregs ){ /* must store */
830 		mkadrs( p );  /* set up stotree and stocook to subtree
831 				 that must be stored */
832 		}
833 
834 	store( p->in.right );
835 	store( p->in.left );
836 	}
837 
838 constore( p ) register NODE *p; {
839 
840 	/* store conditional expressions */
841 	/* the point is, avoid storing expressions in conditional
842 	   conditional context, since the evaluation order is predetermined */
843 
844 	switch( p->in.op ) {
845 
846 	case ANDAND:
847 	case OROR:
848 	case QUEST:
849 		markcall( p->in.right );
850 	case NOT:
851 		constore( p->in.left );
852 		return;
853 
854 		}
855 
856 	store( p );
857 	}
858 
859 markcall( p ) register NODE *p; {  /* mark off calls below the current node */
860 
861 	again:
862 	switch( p->in.op ){
863 
864 	case UNARY CALL:
865 	case UNARY STCALL:
866 	case UNARY FORTCALL:
867 	case CALL:
868 	case STCALL:
869 	case FORTCALL:
870 		++callflag;
871 		return;
872 
873 		}
874 
875 	switch( optype( p->in.op ) ){
876 
877 	case BITYPE:
878 		markcall( p->in.right );
879 	case UTYPE:
880 		p = p->in.left;
881 		/* eliminate recursion (aren't I clever...) */
882 		goto again;
883 	case LTYPE:
884 		return;
885 		}
886 
887 	}
888 
889 stoarg( p, calltype ) register NODE *p; {
890 	/* arrange to store the args */
891 
892 	if( p->in.op == CM ){
893 		stoarg( p->in.left, calltype );
894 		p = p->in.right ;
895 		}
896 	if( calltype == CALL ){
897 		STOARG(p);
898 		}
899 	else if( calltype == STCALL ){
900 		STOSTARG(p);
901 		}
902 	else {
903 		STOFARG(p);
904 		}
905 	callflag = 0;
906 	store(p);
907 # ifndef NESTCALLS
908 	if( callflag ){ /* prevent two calls from being active at once  */
909 		SETSTO(p,INTEMP);
910 		store(p); /* do again to preserve bottom up nature....  */
911 		}
912 #endif
913 	}
914 
915 int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;  /* negatives of relationals */
916 
917 cbranch( p, true, false ) NODE *p; {
918 	/* evaluate p for truth value, and branch to true or false
919 	/* accordingly: label <0 means fall through */
920 
921 	register o, lab, flab, tlab;
922 
923 	lab = -1;
924 
925 	switch( o=p->in.op ){
926 
927 	case ULE:
928 	case ULT:
929 	case UGE:
930 	case UGT:
931 	case EQ:
932 	case NE:
933 	case LE:
934 	case LT:
935 	case GE:
936 	case GT:
937 		if( true < 0 ){
938 			o = p->in.op = negrel[ o-EQ ];
939 			true = false;
940 			false = -1;
941 			}
942 #ifndef NOOPT
943 		if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->in.name[0] == '\0' ){
944 			switch( o ){
945 
946 			case UGT:
947 			case ULE:
948 				o = p->in.op = (o==UGT)?NE:EQ;
949 			case EQ:
950 			case NE:
951 			case LE:
952 			case LT:
953 			case GE:
954 			case GT:
955 				if( logop(p->in.left->in.op) ){
956 					/* strange situation: e.g., (a!=0) == 0 */
957 					/* must prevent reference to p->in.left->lable, so get 0/1 */
958 					/* we could optimize, but why bother */
959 					codgen( p->in.left, INAREG|INBREG );
960 					}
961 				codgen( p->in.left, FORCC );
962 				cbgen( o, true, 'I' );
963 				break;
964 
965 			case UGE:
966 				codgen(p->in.left, FORCC);
967 				cbgen( 0, true, 'I' );  /* unconditional branch */
968 				break;
969 			case ULT:
970 				codgen(p->in.left, FORCC);
971 				}
972 			}
973 		else
974 #endif
975 			{
976 			p->bn.label = true;
977 			codgen( p, FORCC );
978 			}
979 		if( false>=0 ) cbgen( 0, false, 'I' );
980 		reclaim( p, RNULL, 0 );
981 		return;
982 
983 	case ANDAND:
984 		lab = false<0 ? getlab() : false ;
985 		cbranch( p->in.left, -1, lab );
986 		cbranch( p->in.right, true, false );
987 		if( false < 0 ) deflab( lab );
988 		p->in.op = FREE;
989 		return;
990 
991 	case OROR:
992 		lab = true<0 ? getlab() : true;
993 		cbranch( p->in.left, lab, -1 );
994 		cbranch( p->in.right, true, false );
995 		if( true < 0 ) deflab( lab );
996 		p->in.op = FREE;
997 		return;
998 
999 	case NOT:
1000 		cbranch( p->in.left, false, true );
1001 		p->in.op = FREE;
1002 		break;
1003 
1004 	case COMOP:
1005 		codgen( p->in.left, FOREFF );
1006 		p->in.op = FREE;
1007 		cbranch( p->in.right, true, false );
1008 		return;
1009 
1010 	case QUEST:
1011 		flab = false<0 ? getlab() : false;
1012 		tlab = true<0 ? getlab() : true;
1013 		cbranch( p->in.left, -1, lab = getlab() );
1014 		cbranch( p->in.right->in.left, tlab, flab );
1015 		deflab( lab );
1016 		cbranch( p->in.right->in.right, true, false );
1017 		if( true < 0 ) deflab( tlab);
1018 		if( false < 0 ) deflab( flab );
1019 		p->in.right->in.op = FREE;
1020 		p->in.op = FREE;
1021 		return;
1022 
1023 	case ICON:
1024 		if( p->in.type != FLOAT && p->in.type != DOUBLE ){
1025 
1026 			if( p->tn.lval || p->in.name[0] ){
1027 				/* addresses of C objects are never 0 */
1028 				if( true>=0 ) cbgen( 0, true, 'I' );
1029 				}
1030 			else if( false>=0 ) cbgen( 0, false, 'I' );
1031 			p->in.op = FREE;
1032 			return;
1033 			}
1034 		/* fall through to default with other strange constants */
1035 
1036 	default:
1037 		/* get condition codes */
1038 		codgen( p, FORCC );
1039 		if( true >= 0 ) cbgen( NE, true, 'I' );
1040 		if( false >= 0 ) cbgen( true >= 0 ? 0 : EQ, false, 'I' );
1041 		reclaim( p, RNULL, 0 );
1042 		return;
1043 
1044 		}
1045 
1046 	}
1047 
1048 rcount(){ /* count recursions */
1049 	if( ++nrecur > NRECUR ){
1050 		cerror( "expression causes compiler loop: try simplifying" );
1051 		}
1052 
1053 	}
1054 
1055 # ifndef BUG4
1056 eprint( p, down, a, b ) NODE *p; int *a, *b; {
1057 
1058 	*a = *b = down+1;
1059 	while( down >= 2 ){
1060 		printf( "\t" );
1061 		down -= 2;
1062 		}
1063 	if( down-- ) printf( "    " );
1064 
1065 
1066 	printf( "%o) %s", p, opst[p->in.op] );
1067 	switch( p->in.op ) { /* special cases */
1068 
1069 	case REG:
1070 		printf( " %s", rnames[p->tn.rval] );
1071 		break;
1072 
1073 	case ICON:
1074 	case NAME:
1075 	case OREG:
1076 		printf( " " );
1077 		adrput( p );
1078 		break;
1079 
1080 	case STCALL:
1081 	case UNARY STCALL:
1082 	case STARG:
1083 	case STASG:
1084 		printf( " size=%d", p->stn.stsize );
1085 		printf( " align=%d", p->stn.stalign );
1086 		break;
1087 		}
1088 
1089 	printf( ", " );
1090 	tprint( p->in.type );
1091 	printf( ", " );
1092 	if( p->in.rall == NOPREF ) printf( "NOPREF" );
1093 	else {
1094 		if( p->in.rall & MUSTDO ) printf( "MUSTDO " );
1095 		else printf( "PREF " );
1096 		printf( "%s", rnames[p->in.rall&~MUSTDO]);
1097 		}
1098 	printf( ", SU= %d\n", p->in.su );
1099 
1100 	}
1101 # endif
1102 
1103 # ifndef NOMAIN
1104 NODE *
1105 eread(){
1106 
1107 	/* call eread recursively to get subtrees, if any */
1108 
1109 	register NODE *p;
1110 	register i, c;
1111 	register char *pc;
1112 	register j;
1113 
1114 	i = rdin( 10 );
1115 
1116 	p = talloc();
1117 
1118 	p->in.op = i;
1119 
1120 	i = optype(i);
1121 
1122 	if( i == LTYPE ) p->tn.lval = rdin( 10 );
1123 	if( i != BITYPE ) p->tn.rval = rdin( 10 );
1124 
1125 	p->in.type = rdin(8 );
1126 	p->in.rall = NOPREF;  /* register allocation information */
1127 
1128 	if( p->in.op == STASG || p->in.op == STARG || p->in.op == STCALL || p->in.op == UNARY STCALL ){
1129 		p->stn.stsize = (rdin( 10 ) + (SZCHAR-1) )/SZCHAR;
1130 		p->stn.stalign = rdin(10) / SZCHAR;
1131 		if( getchar() != '\n' ) cerror( "illegal \n" );
1132 		}
1133 	else {   /* usual case */
1134 		if( p->in.op == REG ) rbusy( p->tn.rval, p->in.type );  /* non usually, but sometimes justified */
1135 #ifndef FLEXNAMES
1136 		for( pc=p->in.name,j=0; ( c = getchar() ) != '\n'; ++j ){
1137 			if( j < NCHNAM ) *pc++ = c;
1138 			}
1139 		if( j < NCHNAM ) *pc = '\0';
1140 #else
1141 		{ char buf[BUFSIZ];
1142 		for( pc=buf,j=0; ( c = getchar() ) != '\n'; ++j ){
1143 			if( j < BUFSIZ ) *pc++ = c;
1144 			}
1145 		if( j < BUFSIZ ) *pc = '\0';
1146 		p->in.name = tstr(buf);
1147 		}
1148 #endif
1149 		}
1150 
1151 	/* now, recursively read descendents, if any */
1152 
1153 	if( i != LTYPE ) p->in.left = eread();
1154 	if( i == BITYPE ) p->in.right = eread();
1155 
1156 	return( p );
1157 
1158 	}
1159 
1160 CONSZ
1161 rdin( base ){
1162 	register sign, c;
1163 	CONSZ val;
1164 
1165 	sign = 1;
1166 	val = 0;
1167 
1168 	while( (c=getchar()) > 0 ) {
1169 		if( c == '-' ){
1170 			if( val != 0 ) cerror( "illegal -");
1171 			sign = -sign;
1172 			continue;
1173 			}
1174 		if( c == '\t' ) break;
1175 		if( c>='0' && c<='9' ) {
1176 			val *= base;
1177 			if( sign > 0 )
1178 				val += c-'0';
1179 			else
1180 				val -= c-'0';
1181 			continue;
1182 			}
1183 		cerror( "illegal character `%c' on intermediate file", c );
1184 		break;
1185 		}
1186 
1187 	if( c <= 0 ) {
1188 		cerror( "unexpected EOF");
1189 		}
1190 	return( val );
1191 	}
1192 # endif
1193 
1194 #ifndef FIELDOPS
1195 	/* do this if there is no special hardware support for fields */
1196 
1197 ffld( p, down, down1, down2 ) NODE *p; int *down1, *down2; {
1198 	 /* look for fields that are not in an lvalue context, and rewrite them... */
1199 	register NODE *shp;
1200 	register s, o, v, ty;
1201 
1202 	*down1 =  asgop( p->in.op );
1203 	*down2 = 0;
1204 
1205 	if( !down && p->in.op == FLD ){ /* rewrite the node */
1206 
1207 		if( !rewfld(p) ) return;
1208 
1209 		ty = (szty(p->in.type) == 2)? LONG: INT;
1210 		v = p->tn.rval;
1211 		s = UPKFSZ(v);
1212 # ifdef RTOLBYTES
1213 		o = UPKFOFF(v);  /* amount to shift */
1214 # else
1215 		o = szty(p->in.type)*SZINT - s - UPKFOFF(v);  /* amount to shift */
1216 #endif
1217 
1218 		/* make & mask part */
1219 
1220 		p->in.left->in.type = ty;
1221 
1222 		p->in.op = AND;
1223 		p->in.right = talloc();
1224 		p->in.right->in.op = ICON;
1225 		p->in.right->in.rall = NOPREF;
1226 		p->in.right->in.type = ty;
1227 		p->in.right->tn.lval = 1;
1228 		p->in.right->tn.rval = 0;
1229 #ifndef FLEXNAMES
1230 		p->in.right->in.name[0] = '\0';
1231 #else
1232 		p->in.right->in.name = "";
1233 #endif
1234 		p->in.right->tn.lval <<= s;
1235 		p->in.right->tn.lval--;
1236 
1237 		/* now, if a shift is needed, do it */
1238 
1239 		if( o != 0 ){
1240 			shp = talloc();
1241 			shp->in.op = RS;
1242 			shp->in.rall = NOPREF;
1243 			shp->in.type = ty;
1244 			shp->in.left = p->in.left;
1245 			shp->in.right = talloc();
1246 			shp->in.right->in.op = ICON;
1247 			shp->in.right->in.rall = NOPREF;
1248 			shp->in.right->in.type = ty;
1249 			shp->in.right->tn.rval = 0;
1250 			shp->in.right->tn.lval = o;  /* amount to shift */
1251 #ifndef FLEXNAMES
1252 			shp->in.right->in.name[0] = '\0';
1253 #else
1254 			shp->in.right->in.name = "";
1255 #endif
1256 			p->in.left = shp;
1257 			/* whew! */
1258 			}
1259 		}
1260 	}
1261 #endif
1262 
1263 oreg2( p ) register NODE *p; {
1264 
1265 	/* look for situations where we can turn * into OREG */
1266 
1267 	NODE *q;
1268 	register i;
1269 	register r;
1270 	register char *cp;
1271 	register NODE *ql, *qr;
1272 	CONSZ temp;
1273 
1274 	if( p->in.op == UNARY MUL ){
1275 		q = p->in.left;
1276 		if( q->in.op == REG ){
1277 			temp = q->tn.lval;
1278 			r = q->tn.rval;
1279 			cp = q->in.name;
1280 			goto ormake;
1281 			}
1282 
1283 		if( q->in.op != PLUS && q->in.op != MINUS ) return;
1284 		ql = q->in.left;
1285 		qr = q->in.right;
1286 
1287 #ifdef R2REGS
1288 
1289 		/* look for doubly indexed expressions */
1290 
1291 		if( q->in.op == PLUS) {
1292 			if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
1293 				makeor2(p, ql, r, i);
1294 				return;
1295 			} else if( (r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
1296 				makeor2(p, qr, r, i);
1297 				return;
1298 				}
1299 			}
1300 
1301 
1302 #endif
1303 
1304 		if( (q->in.op==PLUS || q->in.op==MINUS) && qr->in.op == ICON &&
1305 				ql->in.op==REG && szty(qr->in.type)==1) {
1306 			temp = qr->tn.lval;
1307 			if( q->in.op == MINUS ) temp = -temp;
1308 			r = ql->tn.rval;
1309 			temp += ql->tn.lval;
1310 			cp = qr->in.name;
1311 			if( *cp && ( q->in.op == MINUS || *ql->in.name ) ) return;
1312 			if( !*cp ) cp = ql->in.name;
1313 
1314 			ormake:
1315 			if( notoff( p->in.type, r, temp, cp ) ) return;
1316 			p->in.op = OREG;
1317 			p->tn.rval = r;
1318 			p->tn.lval = temp;
1319 #ifndef FLEXNAMES
1320 			for( i=0; i<NCHNAM; ++i )
1321 				p->in.name[i] = *cp++;
1322 #else
1323 			p->in.name = cp;
1324 #endif
1325 			tfree(q);
1326 			return;
1327 			}
1328 		}
1329 
1330 	}
1331 
1332 canon(p) NODE *p; {
1333 	/* put p in canonical form */
1334 	int oreg2(), sucomp();
1335 
1336 #ifndef FIELDOPS
1337 	int ffld();
1338 	fwalk( p, ffld, 0 ); /* look for field operators */
1339 # endif
1340 	walkf( p, oreg2 );  /* look for and create OREG nodes */
1341 #ifdef MYCANON
1342 	MYCANON(p);  /* your own canonicalization routine(s) */
1343 #endif
1344 	walkf( p, sucomp );  /* do the Sethi-Ullman computation */
1345 
1346 	}
1347 
1348