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
p2init(argc,argv)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;
mainp2(argc,argv)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
p2compile(p)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
p2bbeg(aoff,myreg)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
p2bend()264 p2bend(){
265 SETOFF( maxoff, ALSTACK );
266 eobl2();
267 }
268
269 # endif
270
271 NODE *deltrees[DELAYS];
272 int deli;
273
delay(p)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
delay1(p)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
delay2(p)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
codgen(p,cookie)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
prcook(cookie)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
order(p,cook)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
store(p)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
constore(p)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
markcall(p)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
stoarg(p,calltype)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
rcount()1048 rcount(){ /* count recursions */
1049 if( ++nrecur > NRECUR ){
1050 cerror( "expression causes compiler loop: try simplifying" );
1051 }
1052
1053 }
1054
1055 # ifndef BUG4
eprint(p,down,a,b)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 *
eread()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
rdin(base)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
ffld(p,down,down1,down2)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
oreg2(p)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
canon(p)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