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