Research V7 development
[unix-history] / usr / src / cmd / mip / reader.c
CommitLineData
3c5d933b
SJ
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 INCR:
316 case DECR:
317 if( deltest( p ) ){
318 if( deli < DELAYS ){
319 register NODE *q;
320 deltrees[deli++] = tcopy(p);
321 q = p->left;
322 p->right->op = FREE; /* zap constant */
323 ncopy( p, q );
324 q->op = FREE;
325 return;
326 }
327 }
328
329 }
330
331 if( ty == BITYPE ) delay2( p->right );
332 if( ty != LTYPE ) delay2( p->left );
333 }
334
335codgen( p, cookie ) NODE *p; {
336
337 /* generate the code for p;
338 order may call codgen recursively */
339 /* cookie is used to describe the context */
340
341 for(;;){
342 canon(p); /* creats OREG from * if possible and does sucomp */
343 stotree = NIL;
344 if( edebug ){
345 printf( "store called on:\n" );
346 fwalk( p, eprint, 0 );
347 }
348 store(p);
349 if( stotree==NIL ) break;
350
351 /* because it's minimal, can do w.o. stores */
352
353 order( stotree, stocook );
354 }
355
356 order( p, cookie );
357
358 }
359
360char *cnames[] = {
361 "SANY",
362 "SAREG",
363 "STAREG",
364 "SBREG",
365 "STBREG",
366 "SCC",
367 "SNAME",
368 "SCON",
369 "SFLD",
370 "SOREG",
371 "STARNM",
372 "STARREG",
373 "INTEMP",
374 "FORARG",
375 "SWADD",
376 0,
377 };
378
379prcook( cookie ){
380
381 /* print a nice-looking description of cookie */
382
383 int i, flag;
384
385 if( cookie & SPECIAL ){
386 if( cookie == SZERO ) printf( "SZERO" );
387 else if( cookie == SONE ) printf( "SONE" );
388 else if( cookie == SMONE ) printf( "SMONE" );
389 else printf( "SPECIAL+%d", cookie & ~SPECIAL );
390 return;
391 }
392
393 flag = 0;
394 for( i=0; cnames[i]; ++i ){
395 if( cookie & (1<<i) ){
396 if( flag ) printf( "|" );
397 ++flag;
398 printf( cnames[i] );
399 }
400 }
401
402 }
403
404int odebug = 0;
405
406order(p,cook) NODE *p; {
407
408 register o, ty, m;
409 int m1;
410 int cookie;
411 NODE *p1, *p2;
412
413 /* by this time, p should be able to be generated without stores;
414 the only question is how */
415
416 again:
417
418 cookie = cook;
419 rcount();
420 canon(p);
421 rallo( p, p->rall );
422
423 if( odebug ){
424 printf( "order( %o, ", p );
425 prcook( cookie );
426 printf( " )\n" );
427 fwalk( p, eprint, 0 );
428 }
429
430 o = p->op;
431 ty = optype(o);
432
433 /* first of all, for most ops, see if it is in the table */
434
435 /* look for ops */
436
437 switch( m = p->op ){
438
439 default:
440 /* look for op in table */
441 for(;;){
442 if( (m = match( p, cookie ) ) == MDONE ) goto cleanup;
443 else if( m == MNOPE ){
444 if( !(cookie = nextcook( p, cookie ) ) ) goto nomat;
445 continue;
446 }
447 else break;
448 }
449 break;
450
451 case COMOP:
452 case FORCE:
453 case CBRANCH:
454 case QUEST:
455 case ANDAND:
456 case OROR:
457 case NOT:
458 case UNARY CALL:
459 case CALL:
460 case UNARY STCALL:
461 case STCALL:
462 case UNARY FORTCALL:
463 case FORTCALL:
464 /* don't even go near the table... */
465 ;
466
467 }
468 /* get here to do rewriting if no match or
469 fall through from above for hard ops */
470
471 p1 = p->left;
472 if( ty == BITYPE ) p2 = p->right;
473 else p2 = NIL;
474
475 if( odebug ){
476 printf( "order( %o, ", p );
477 prcook( cook );
478 printf( " ), cookie " );
479 prcook( cookie );
480 printf( ", rewrite %s\n", opst[m] );
481 }
482 switch( m ){
483 default:
484 nomat:
485 cerror( "no table entry for op %s", opst[p->op] );
486
487 case COMOP:
488 codgen( p1, FOREFF );
489 p2->rall = p->rall;
490 codgen( p2, cookie );
491 ncopy( p, p2 );
492 p2->op = FREE;
493 goto cleanup;
494
495 case FORCE:
496 /* recurse, letting the work be done by rallo */
497 p = p->left;
498 cook = INTAREG|INTBREG;
499 goto again;
500
501 case CBRANCH:
502 o = p2->lval;
503 cbranch( p1, -1, o );
504 p2->op = FREE;
505 p->op = FREE;
506 return;
507
508 case QUEST:
509 cbranch( p1, -1, m=getlab() );
510 p2->left->rall = p->rall;
511 codgen( p2->left, INTAREG|INTBREG );
512 /* force right to compute result into same reg used by left */
513 p2->right->rall = p2->left->rval|MUSTDO;
514 reclaim( p2->left, RNULL, 0 );
515 cbgen( 0, m1 = getlab(), 'I' );
516 deflab( m );
517 codgen( p2->right, INTAREG|INTBREG );
518 deflab( m1 );
519 p->op = REG; /* set up node describing result */
520 p->lval = 0;
521 p->rval = p2->right->rval;
522 p->type = p2->right->type;
523 tfree( p2->right );
524 p2->op = FREE;
525 goto cleanup;
526
527 case ANDAND:
528 case OROR:
529 case NOT: /* logical operators */
530 /* if here, must be a logical operator for 0-1 value */
531 cbranch( p, -1, m=getlab() );
532 p->op = CCODES;
533 p->label = m;
534 order( p, INTAREG );
535 goto cleanup;
536
537 case FLD: /* fields of funny type */
538 if ( p1->op == UNARY MUL ){
539 offstar( p1->left );
540 goto again;
541 }
542
543 case UNARY MINUS:
544 order( p1, INBREG|INAREG );
545 goto again;
546
547 case NAME:
548 /* all leaves end up here ... */
549 if( o == REG ) goto nomat;
550 order( p, INTAREG|INTBREG );
551 goto again;
552
553 case INIT:
554 uerror( "illegal initialization" );
555 return;
556
557 case UNARY FORTCALL:
558 p->right = NIL;
559 case FORTCALL:
560 o = p->op = UNARY FORTCALL;
561 if( genfcall( p, cookie ) ) goto nomat;
562 goto cleanup;
563
564 case UNARY CALL:
565 p->right = NIL;
566 case CALL:
567 o = p->op = UNARY CALL;
568 if( gencall( p, cookie ) ) goto nomat;
569 goto cleanup;
570
571 case UNARY STCALL:
572 p->right = NIL;
573 case STCALL:
574 o = p->op = UNARY STCALL;
575 if( genscall( p, cookie ) ) goto nomat;
576 goto cleanup;
577
578 /* if arguments are passed in register, care must be taken that reclaim
579 /* not throw away the register which now has the result... */
580
581 case UNARY MUL:
582 if( cook == FOREFF ){
583 /* do nothing */
584 order( p->left, FOREFF );
585 p->op = FREE;
586 return;
587 }
588 offstar( p->left );
589 goto again;
590
591 case INCR: /* INCR and DECR */
592 if( setincr(p) ) goto again;
593
594 /* x++ becomes (x += 1) -1; */
595
596 if( cook & FOREFF ){ /* result not needed so inc or dec and be done with it */
597 /* x++ => x += 1 */
598 p->op = (p->op==INCR)?ASG PLUS:ASG MINUS;
599 goto again;
600 }
601
602 p1 = tcopy(p);
603 reclaim( p->left, RNULL, 0 );
604 p->left = p1;
605 p1->op = (p->op==INCR)?ASG PLUS:ASG MINUS;
606 p->op = (p->op==INCR)?MINUS:PLUS;
607 goto again;
608
609 case STASG:
610 if( setstr( p ) ) goto again;
611 goto nomat;
612
613 case ASG PLUS: /* and other assignment ops */
614 if( setasop(p) ) goto again;
615
616 /* there are assumed to be no side effects in LHS */
617
618 p2 = tcopy(p);
619 p->op = ASSIGN;
620 reclaim( p->right, RNULL, 0 );
621 p->right = p2;
622 canon(p);
623 rallo( p, p->rall );
624
625 if( odebug ) fwalk( p, eprint, 0 );
626
627 order( p2->left, INTBREG|INTAREG );
628 order( p2, INTBREG|INTAREG );
629 goto again;
630
631 case ASSIGN:
632 if( setasg( p ) ) goto again;
633 goto nomat;
634
635
636 case BITYPE:
637 if( setbin( p ) ) goto again;
638 /* try to replace binary ops by =ops */
639 switch(o){
640
641 case PLUS:
642 case MINUS:
643 case MUL:
644 case DIV:
645 case MOD:
646 case AND:
647 case OR:
648 case ER:
649 case LS:
650 case RS:
651 p->op = ASG o;
652 goto again;
653 }
654 goto nomat;
655
656 }
657
658 cleanup:
659
660 /* if it is not yet in the right state, put it there */
661
662 if( cook & FOREFF ){
663 reclaim( p, RNULL, 0 );
664 return;
665 }
666
667 if( p->op==FREE ) return;
668
669 if( tshape( p, cook ) ) return;
670
671 if( (m=match(p,cook) ) == MDONE ) return;
672
673 /* we are in bad shape, try one last chance */
674 if( lastchance( p, cook ) ) goto again;
675
676 goto nomat;
677 }
678
679int callflag;
680int fregs;
681
682store( p ) register NODE *p; {
683
684 /* find a subtree of p which should be stored */
685
686 register o, ty;
687
688 o = p->op;
689 ty = optype(o);
690
691 if( ty == LTYPE ) return;
692
693 switch( o ){
694
695 case UNARY CALL:
696 case UNARY FORTCALL:
697 case UNARY STCALL:
698 ++callflag;
699 break;
700
701 case UNARY MUL:
702 if( asgop(p->left->op) ) stoasg( p->left, UNARY MUL );
703 break;
704
705 case CALL:
706 case FORTCALL:
707 case STCALL:
708 store( p->left );
709 stoarg( p->right, o );
710 ++callflag;
711 return;
712
713 case COMOP:
714 markcall( p->right );
715 if( p->right->su > fregs ) SETSTO( p, INTEMP );
716 store( p->left );
717 return;
718
719 case ANDAND:
720 case OROR:
721 case QUEST:
722 markcall( p->right );
723 if( p->right->su > fregs ) SETSTO( p, INTEMP );
724 case CBRANCH: /* to prevent complicated expressions on the LHS from being stored */
725 case NOT:
726 constore( p->left );
727 return;
728
729 }
730
731 if( ty == UTYPE ){
732 store( p->left );
733 return;
734 }
735
736 if( asgop( p->right->op ) ) stoasg( p->right, o );
737
738 if( p->su>fregs ){ /* must store */
739 mkadrs( p ); /* set up stotree and stocook to subtree
740 that must be stored */
741 }
742
743 store( p->right );
744 store( p->left );
745 }
746
747constore( p ) register NODE *p; {
748
749 /* store conditional expressions */
750 /* the point is, avoid storing expressions in conditional
751 conditional context, since the evaluation order is predetermined */
752
753 switch( p->op ) {
754
755 case ANDAND:
756 case OROR:
757 case QUEST:
758 markcall( p->right );
759 case NOT:
760 constore( p->left );
761 return;
762
763 }
764
765 store( p );
766 }
767
768markcall( p ) register NODE *p; { /* mark off calls below the current node */
769
770 again:
771 switch( p->op ){
772
773 case UNARY CALL:
774 case UNARY STCALL:
775 case UNARY FORTCALL:
776 case CALL:
777 case STCALL:
778 case FORTCALL:
779 ++callflag;
780 return;
781
782 }
783
784 switch( optype( p->op ) ){
785
786 case BITYPE:
787 markcall( p->right );
788 case UTYPE:
789 p = p->left;
790 /* eliminate recursion (aren't I clever...) */
791 goto again;
792 case LTYPE:
793 return;
794 }
795
796 }
797
798stoarg( p, calltype ) register NODE *p; {
799 /* arrange to store the args */
800
801 if( p->op == CM ){
802 stoarg( p->left, calltype );
803 p = p->right ;
804 }
805 if( calltype == CALL ){
806 STOARG(p);
807 }
808 else if( calltype == STCALL ){
809 STOSTARG(p);
810 }
811 else {
812 STOFARG(p);
813 }
814 callflag = 0;
815 store(p);
816# ifndef NESTCALLS
817 if( callflag ){ /* prevent two calls from being active at once */
818 SETSTO(p,INTEMP);
819 store(p); /* do again to preserve bottom up nature.... */
820 }
821#endif
822 }
823
824int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */
825
826cbranch( p, true, false ) NODE *p; {
827 /* evaluate p for truth value, and branch to true or false
828 /* accordingly: label <0 means fall through */
829
830 register o, lab, flab, tlab;
831
832 lab = -1;
833
834 switch( o=p->op ){
835
836 case ULE:
837 case ULT:
838 case UGE:
839 case UGT:
840 case EQ:
841 case NE:
842 case LE:
843 case LT:
844 case GE:
845 case GT:
846 if( true < 0 ){
847 o = p->op = negrel[ o-EQ ];
848 true = false;
849 false = -1;
850 }
851#ifndef NOOPT
852 if( p->right->op == ICON && p->right->lval == 0 && p->right->name[0] == '\0' ){
853 switch( o ){
854
855 case UGT:
856 case ULE:
857 o = p->op = (o==UGT)?NE:EQ;
858 case EQ:
859 case NE:
860 case LE:
861 case LT:
862 case GE:
863 case GT:
864 if( logop(p->left->op) ){
865 /* strange situation: e.g., (a!=0) == 0 */
866 /* must prevent reference to p->left->lable, so get 0/1 */
867 /* we could optimize, but why bother */
868 codgen( p->left, INAREG|INBREG );
869 }
870 codgen( p->left, FORCC );
871 cbgen( o, true, 'I' );
872 break;
873
874 case UGE:
875 cbgen( 0, true, 'I' ); /* unconditional branch */
876 case ULT:
877 ; /* do nothing for LT */
878 }
879 }
880 else
881#endif
882 {
883 p->label = true;
884 codgen( p, FORCC );
885 }
886 if( false>=0 ) cbgen( 0, false, 'I' );
887 reclaim( p, RNULL, 0 );
888 return;
889
890 case ANDAND:
891 lab = false<0 ? getlab() : false ;
892 cbranch( p->left, -1, lab );
893 cbranch( p->right, true, false );
894 if( false < 0 ) deflab( lab );
895 p->op = FREE;
896 return;
897
898 case OROR:
899 lab = true<0 ? getlab() : true;
900 cbranch( p->left, lab, -1 );
901 cbranch( p->right, true, false );
902 if( true < 0 ) deflab( lab );
903 p->op = FREE;
904 return;
905
906 case NOT:
907 cbranch( p->left, false, true );
908 p->op = FREE;
909 break;
910
911 case COMOP:
912 codgen( p->left, FOREFF );
913 p->op = FREE;
914 cbranch( p->right, true, false );
915 return;
916
917 case QUEST:
918 flab = false<0 ? getlab() : false;
919 tlab = true<0 ? getlab() : true;
920 cbranch( p->left, -1, lab = getlab() );
921 cbranch( p->right->left, tlab, flab );
922 deflab( lab );
923 cbranch( p->right->right, true, false );
924 if( true < 0 ) deflab( tlab);
925 if( false < 0 ) deflab( flab );
926 p->right->op = FREE;
927 p->op = FREE;
928 return;
929
930 case ICON:
931 if( p->type != FLOAT && p->type != DOUBLE ){
932
933 if( p->lval || p->name[0] ){
934 /* addresses of C objects are never 0 */
935 if( true>=0 ) cbgen( 0, true, 'I' );
936 }
937 else if( false>=0 ) cbgen( 0, false, 'I' );
938 p->op = FREE;
939 return;
940 }
941 /* fall through to default with other strange constants */
942
943 default:
944 /* get condition codes */
945 codgen( p, FORCC );
946 if( true >= 0 ) cbgen( NE, true, 'I' );
947 if( false >= 0 ) cbgen( true >= 0 ? 0 : EQ, false, 'I' );
948 reclaim( p, RNULL, 0 );
949 return;
950
951 }
952
953 }
954
955rcount(){ /* count recursions */
956 if( ++nrecur > NRECUR ){
957 cerror( "expression causes compiler loop: try simplifying" );
958 }
959
960 }
961
962eprint( p, down, a, b ) NODE *p; int *a, *b; {
963
964 *a = *b = down+1;
965 while( down >= 2 ){
966 printf( "\t" );
967 down -= 2;
968 }
969 if( down-- ) printf( " " );
970
971
972 printf( "%o) %s", p, opst[p->op] );
973 switch( p->op ) { /* special cases */
974
975 case REG:
976 printf( " %s", rnames[p->rval] );
977 break;
978
979 case ICON:
980 case NAME:
981 case OREG:
982 printf( " " );
983 adrput( p );
984 break;
985
986 case STCALL:
987 case UNARY STCALL:
988 case STARG:
989 case STASG:
990 printf( " size=%d", p->stsize );
991 printf( " align=%d", p->stalign );
992 break;
993 }
994
995 printf( ", " );
996 tprint( p->type );
997 printf( ", " );
998 if( p->rall == NOPREF ) printf( "NOPREF" );
999 else {
1000 if( p->rall & MUSTDO ) printf( "MUSTDO " );
1001 else printf( "PREF " );
1002 printf( "%s", rnames[p->rall&~MUSTDO]);
1003 }
1004 printf( ", SU= %d\n", p->su );
1005
1006 }
1007
1008# ifndef NOMAIN
1009NODE *
1010eread(){
1011
1012 /* call eread recursively to get subtrees, if any */
1013
1014 register NODE *p;
1015 register i, c;
1016 register char *pc;
1017 register j;
1018
1019 i = rdin( 10 );
1020
1021 p = talloc();
1022
1023 p->op = i;
1024
1025 i = optype(i);
1026
1027 if( i == LTYPE ) p->lval = rdin( 10 );
1028 if( i != BITYPE ) p->rval = rdin( 10 );
1029
1030 p->type = rdin(8 );
1031 p->rall = NOPREF; /* register allocation information */
1032
1033 if( p->op == STASG || p->op == STARG || p->op == STCALL || p->op == UNARY STCALL ){
1034 p->stsize = (rdin( 10 ) + (SZCHAR-1) )/SZCHAR;
1035 p->stalign = rdin(10) / SZCHAR;
1036 if( getchar() != '\n' ) cerror( "illegal \n" );
1037 }
1038 else { /* usual case */
1039 if( p->op == REG ) rbusy( p->rval, p->type ); /* non usually, but sometimes justified */
1040 for( pc=p->name,j=0; ( c = getchar() ) != '\n'; ++j ){
1041 if( j < NCHNAM ) *pc++ = c;
1042 }
1043 if( j < NCHNAM ) *pc = '\0';
1044 }
1045
1046 /* now, recursively read descendents, if any */
1047
1048 if( i != LTYPE ) p->left = eread();
1049 if( i == BITYPE ) p->right = eread();
1050
1051 return( p );
1052
1053 }
1054
1055CONSZ
1056rdin( base ){
1057 register sign, c;
1058 CONSZ val;
1059
1060 sign = 1;
1061 val = 0;
1062
1063 while( (c=getchar()) > 0 ) {
1064 if( c == '-' ){
1065 if( val != 0 ) cerror( "illegal -");
1066 sign = -sign;
1067 continue;
1068 }
1069 if( c == '\t' ) break;
1070 if( c>='0' && c<='9' ) {
1071 val *= base;
1072 if( sign > 0 )
1073 val += c-'0';
1074 else
1075 val -= c-'0';
1076 continue;
1077 }
1078 cerror( "illegal character `%c' on intermediate file", c );
1079 break;
1080 }
1081
1082 if( c <= 0 ) {
1083 cerror( "unexpected EOF");
1084 }
1085 return( val );
1086 }
1087# endif
1088
1089#ifndef FIELDOPS
1090 /* do this if there is no special hardware support for fields */
1091
1092ffld( p, down, down1, down2 ) NODE *p; int *down1, *down2; {
1093 /* look for fields that are not in an lvalue context, and rewrite them... */
1094 register NODE *shp;
1095 register s, o, v, ty;
1096
1097 *down1 = asgop( p->op );
1098 *down2 = 0;
1099
1100 if( !down && p->op == FLD ){ /* rewrite the node */
1101
1102 if( !rewfld(p) ) return;
1103
1104 ty = (szty(p->type) == 2)? LONG: INT;
1105 v = p->rval;
1106 s = UPKFSZ(v);
1107# ifdef RTOLBYTES
1108 o = UPKFOFF(v); /* amount to shift */
1109# else
1110 o = szty(p->type)*SZINT - s - UPKFOFF(v); /* amount to shift */
1111#endif
1112
1113 /* make & mask part */
1114
1115 p->left->type = ty;
1116
1117 p->op = AND;
1118 p->right = talloc();
1119 p->right->op = ICON;
1120 p->right->rall = NOPREF;
1121 p->right->type = ty;
1122 p->right->lval = 1;
1123 p->right->rval = 0;
1124 p->right->name[0] = '\0';
1125 p->right->lval <<= s;
1126 p->right->lval--;
1127
1128 /* now, if a shift is needed, do it */
1129
1130 if( o != 0 ){
1131 shp = talloc();
1132 shp->op = RS;
1133 shp->rall = NOPREF;
1134 shp->type = ty;
1135 shp->left = p->left;
1136 shp->right = talloc();
1137 shp->right->op = ICON;
1138 shp->right->rall = NOPREF;
1139 shp->right->type = ty;
1140 shp->right->rval = 0;
1141 shp->right->lval = o; /* amount to shift */
1142 shp->right->name[0] = '\0';
1143 p->left = shp;
1144 /* whew! */
1145 }
1146 }
1147 }
1148#endif
1149
1150oreg2( p ) register NODE *p; {
1151
1152 /* look for situations where we can turn * into OREG */
1153
1154 NODE *q;
1155 register i;
1156 register r;
1157 register char *cp;
1158 register NODE *ql, *qr;
1159 CONSZ temp;
1160
1161 if( p->op == UNARY MUL ){
1162 q = p->left;
1163 if( q->op == REG ){
1164 temp = q->lval;
1165 r = q->rval;
1166 cp = q->name;
1167 goto ormake;
1168 }
1169
1170 if( q->op != PLUS && q->op != MINUS ) return;
1171 ql = q->left;
1172 qr = q->right;
1173
1174#ifdef R2REGS
1175
1176 /* look for doubly indexed expressions */
1177
1178 if( q->op==PLUS && qr->op==REG && ql->op==REG &&
1179 (szty(ql->type)==1||szty(qr->type)==1) ) {
1180 temp = 0;
1181 cp = ql->name;
1182 if( *cp ){
1183 if( *qr->name ) return;
1184 }
1185 else {
1186 cp = qr->name;
1187 }
1188 if( szty(qr->type)>1) r = R2PACK(qr->rval,ql->rval);
1189 else r = R2PACK(ql->rval,qr->rval);
1190 goto ormake;
1191 }
1192
1193 if( (q->op==PLUS||q->op==MINUS) && qr->op==ICON && ql->op==PLUS &&
1194 ql->left->op==REG &&
1195 ql->right->op==REG ){
1196 temp = qr->lval;
1197 cp = qr->name;
1198 if( q->op == MINUS ){
1199 if( *cp ) return;
1200 temp = -temp;
1201 }
1202 if( *cp ){
1203 if( *ql->name ) return;
1204 }
1205 else {
1206 cp = ql->name;
1207 }
1208 r = R2PACK(ql->left->rval,ql->right->rval);
1209 goto ormake;
1210 }
1211
1212#endif
1213
1214 if( (q->op==PLUS || q->op==MINUS) && qr->op == ICON &&
1215 ql->op==REG && szty(qr->type)==1) {
1216 temp = qr->lval;
1217 if( q->op == MINUS ) temp = -temp;
1218 r = ql->rval;
1219 temp += ql->lval;
1220 cp = qr->name;
1221 if( *cp && ( q->op == MINUS || *ql->name ) ) return;
1222 if( !*cp ) cp = ql->name;
1223
1224 ormake:
1225 if( notoff( p->type, r, temp, cp ) ) return;
1226 p->op = OREG;
1227 p->rval = r;
1228 p->lval = temp;
1229 for( i=0; i<NCHNAM; ++i )
1230 p->name[i] = *cp++;
1231 tfree(q);
1232 return;
1233 }
1234 }
1235
1236 }
1237
1238canon(p) NODE *p; {
1239 /* put p in canonical form */
1240 int oreg2(), sucomp();
1241
1242#ifndef FIELDOPS
1243 int ffld();
1244 fwalk( p, ffld, 0 ); /* look for field operators */
1245# endif
1246 walkf( p, oreg2 ); /* look for and create OREG nodes */
1247#ifdef MYCANON
1248 MYCANON(p); /* your own canonicalization routine(s) */
1249#endif
1250 walkf( p, sucomp ); /* do the Sethi-Ullman computation */
1251
1252 }
1253