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