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