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