Commit | Line | Data |
---|---|---|
512c3113 TL |
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 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 | ||
340 | codgen( 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 | ||
365 | char *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 | ||
384 | prcook( 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 | ||
409 | int odebug = 0; | |
410 | ||
411 | order(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 | ||
686 | int callflag; | |
687 | int fregs; | |
688 | ||
689 | store( 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 | ||
754 | constore( 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 | ||
775 | markcall( 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 | ||
805 | stoarg( 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 | ||
831 | int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */ | |
832 | ||
833 | cbranch( 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 | ||
962 | rcount(){ /* count recursions */ | |
963 | if( ++nrecur > NRECUR ){ | |
964 | cerror( "expression causes compiler loop: try simplifying" ); | |
965 | } | |
966 | ||
967 | } | |
968 | ||
969 | eprint( 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 | |
1016 | NODE * | |
1017 | eread(){ | |
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 | ||
1062 | CONSZ | |
1063 | rdin( 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 | ||
1099 | ffld( 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 | ||
1157 | oreg2( 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 | ||
1222 | canon(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 |