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