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