Commit | Line | Data |
---|---|---|
3c5d933b SJ |
1 | # include "mfile2" |
2 | ||
3 | /* some storage declarations */ | |
4 | ||
5 | # ifndef ONEPASS | |
6 | NODE node[TREESZ]; | |
7 | char filename[100] = ""; /* the name of the file */ | |
8 | int ftnno; /* number of current function */ | |
9 | int lineno; | |
10 | # else | |
11 | # define NOMAIN | |
12 | #endif | |
13 | ||
14 | int nrecur; | |
15 | int lflag; | |
16 | int edebug = 0; | |
17 | int xdebug = 0; | |
18 | int udebug = 0; | |
19 | ||
20 | OFFSZ tmpoff; /* offset for first temporary, in bits for current block */ | |
21 | OFFSZ maxoff; /* maximum temporary offset over all blocks in current ftn, in bits */ | |
22 | int maxtreg; | |
23 | ||
24 | NODE *stotree; | |
25 | int stocook; | |
26 | ||
27 | OFFSZ baseoff = 0; | |
28 | OFFSZ maxtemp = 0; | |
29 | ||
30 | p2init( 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 | ||
102 | mainp2( 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 | ||
197 | p2compile( 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 | ||
215 | p2bbeg( 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 | ||
231 | p2bend(){ | |
232 | SETOFF( maxoff, ALSTACK ); | |
233 | eobl2(); | |
234 | } | |
235 | ||
236 | # endif | |
237 | ||
238 | NODE *deltrees[DELAYS]; | |
239 | int deli; | |
240 | ||
241 | delay( 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 | ||
259 | delay1( 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 | ||
289 | delay2( 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 | ||
335 | codgen( 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 | ||
360 | char *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 | ||
379 | prcook( 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 | ||
404 | int odebug = 0; | |
405 | ||
406 | order(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 | ||
679 | int callflag; | |
680 | int fregs; | |
681 | ||
682 | store( 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 | ||
747 | constore( 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 | ||
768 | markcall( 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 | ||
798 | stoarg( 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 | ||
824 | int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */ | |
825 | ||
826 | cbranch( 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 | ||
955 | rcount(){ /* count recursions */ | |
956 | if( ++nrecur > NRECUR ){ | |
957 | cerror( "expression causes compiler loop: try simplifying" ); | |
958 | } | |
959 | ||
960 | } | |
961 | ||
962 | eprint( 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 | |
1009 | NODE * | |
1010 | eread(){ | |
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 | ||
1055 | CONSZ | |
1056 | rdin( 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 | ||
1092 | ffld( 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 | ||
1150 | oreg2( 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 | ||
1238 | canon(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 |