|
|
1.1 ! root 1: # ifndef lint ! 2: static char *sccsid ="@(#)local2.c 1.39 (Berkeley) 5/11/88"; ! 3: # endif ! 4: ! 5: # include "pass2.h" ! 6: # include <ctype.h> ! 7: ! 8: # define putstr(s) fputs((s), stdout) ! 9: ! 10: # ifdef FORT ! 11: int ftlab1, ftlab2; ! 12: # endif ! 13: /* a lot of the machine dependent parts of the second pass */ ! 14: ! 15: # define BITMASK(n) ((1L<<n)-1) ! 16: ! 17: /*ARGSUSED*/ ! 18: where(c){ ! 19: fprintf( stderr, "%s, line %d: ", filename, lineno ); ! 20: } ! 21: ! 22: lineid( l, fn ) char *fn; { ! 23: /* identify line l and file fn */ ! 24: printf( "# line %d, file %s\n", l, fn ); ! 25: } ! 26: ! 27: ! 28: eobl2(){ ! 29: register OFFSZ spoff; /* offset from stack pointer */ ! 30: #ifndef FORT ! 31: extern int ftlab1, ftlab2; ! 32: #endif ! 33: ! 34: spoff = maxoff; ! 35: if( spoff >= AUTOINIT ) spoff -= AUTOINIT; ! 36: spoff /= SZCHAR; ! 37: SETOFF(spoff,4); ! 38: #ifdef FORT ! 39: #ifndef FLEXNAMES ! 40: printf( " .set .F%d,%ld\n", ftnno, spoff ); ! 41: #else ! 42: /* SHOULD BE L%d ... ftnno but must change pc/f77 */ ! 43: printf( " .set LF%d,%ld\n", ftnno, spoff ); ! 44: #endif ! 45: #else ! 46: printf( "L%d:\n", ftlab1); ! 47: if( spoff!=0 ) ! 48: if( spoff < 64 ) ! 49: printf( " subl2 $%ld,sp\n", spoff); ! 50: else ! 51: printf( " movab -%ld(sp),sp\n", spoff); ! 52: printf( " jbr L%d\n", ftlab2); ! 53: #endif ! 54: maxargs = -1; ! 55: } ! 56: ! 57: struct hoptab { int opmask; char * opstring; } ioptab[] = { ! 58: ! 59: PLUS, "add", ! 60: MINUS, "sub", ! 61: MUL, "mul", ! 62: DIV, "div", ! 63: OR, "bis", ! 64: ER, "xor", ! 65: AND, "bic", ! 66: -1, "" }; ! 67: ! 68: hopcode( f, o ){ ! 69: /* output the appropriate string from the above table */ ! 70: ! 71: register struct hoptab *q; ! 72: ! 73: if(asgop(o)) ! 74: o = NOASG o; ! 75: for( q = ioptab; q->opmask>=0; ++q ){ ! 76: if( q->opmask == o ){ ! 77: printf( "%s%c", q->opstring, tolower(f)); ! 78: return; ! 79: } ! 80: } ! 81: cerror( "no hoptab for %s", opst[o] ); ! 82: } ! 83: ! 84: char * ! 85: rnames[] = { /* keyed to register number tokens */ ! 86: ! 87: "r0", "r1", ! 88: "r2", "r3", "r4", "r5", ! 89: "r6", "r7", "r8", "r9", "r10", "r11", ! 90: "ap", "fp", "sp", "pc", ! 91: }; ! 92: ! 93: int rstatus[] = { ! 94: SAREG|STAREG, SAREG|STAREG, ! 95: SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, ! 96: SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, ! 97: SAREG, SAREG, SAREG, SAREG, ! 98: }; ! 99: ! 100: tlen(p) NODE *p; ! 101: { ! 102: switch(p->in.type) { ! 103: case CHAR: ! 104: case UCHAR: ! 105: return(1); ! 106: ! 107: case SHORT: ! 108: case USHORT: ! 109: return(SZSHORT/SZCHAR); ! 110: ! 111: case DOUBLE: ! 112: return(SZDOUBLE/SZCHAR); ! 113: ! 114: default: ! 115: return(SZINT/SZCHAR); ! 116: } ! 117: } ! 118: ! 119: mixtypes(p, q) NODE *p, *q; ! 120: { ! 121: register TWORD tp, tq; ! 122: ! 123: tp = p->in.type; ! 124: tq = q->in.type; ! 125: ! 126: return( (tp==FLOAT || tp==DOUBLE) != ! 127: (tq==FLOAT || tq==DOUBLE) ); ! 128: } ! 129: ! 130: prtype(n) NODE *n; ! 131: { ! 132: switch (n->in.type) ! 133: { ! 134: ! 135: case DOUBLE: ! 136: putchar('d'); ! 137: return; ! 138: ! 139: case FLOAT: ! 140: putchar('f'); ! 141: return; ! 142: ! 143: case LONG: ! 144: case ULONG: ! 145: case INT: ! 146: case UNSIGNED: ! 147: putchar('l'); ! 148: return; ! 149: ! 150: case SHORT: ! 151: case USHORT: ! 152: putchar('w'); ! 153: return; ! 154: ! 155: case CHAR: ! 156: case UCHAR: ! 157: putchar('b'); ! 158: return; ! 159: ! 160: default: ! 161: if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); ! 162: else { ! 163: putchar('l'); ! 164: return; ! 165: } ! 166: } ! 167: } ! 168: ! 169: zzzcode( p, c ) register NODE *p; { ! 170: register int m; ! 171: int val; ! 172: switch( c ){ ! 173: ! 174: case 'N': /* logical ops, turned into 0-1 */ ! 175: /* use register given by register 1 */ ! 176: cbgen( 0, m=getlab(), 'I' ); ! 177: deflab( p->bn.label ); ! 178: printf( " clrl %s\n", rnames[getlr( p, '1' )->tn.rval] ); ! 179: deflab( m ); ! 180: return; ! 181: ! 182: case 'P': ! 183: cbgen( p->in.op, p->bn.label, c ); ! 184: return; ! 185: ! 186: case 'A': ! 187: case 'V': ! 188: sconv( p, c == 'V' ); ! 189: return; ! 190: ! 191: case 'G': /* i *= f; asgops with int lhs and float rhs */ ! 192: { ! 193: register NODE *l, *r, *s; ! 194: int rt; ! 195: ! 196: l = p->in.left; ! 197: r = p->in.right; ! 198: s = talloc(); ! 199: rt = r->in.type; ! 200: ! 201: s->in.op = SCONV; ! 202: s->in.left = l; ! 203: s->in.type = rt; ! 204: zzzcode(s, 'A'); ! 205: putstr("\n\t"); ! 206: ! 207: hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); ! 208: putstr("2\t"); ! 209: adrput(r); ! 210: putchar(','); ! 211: adrput(resc); ! 212: putstr("\n\t"); ! 213: ! 214: s->in.op = ASSIGN; ! 215: s->in.left = l; ! 216: s->in.right = resc; ! 217: s->in.type = l->in.type; ! 218: zzzcode(s, 'A'); ! 219: ! 220: s->in.op = FREE; ! 221: return; ! 222: } ! 223: ! 224: case 'J': /* unsigned DIV/MOD with constant divisors */ ! 225: { ! 226: register int ck = INAREG; ! 227: int label1, label2; ! 228: ! 229: /* case constant <= 1 is handled by optim() in pass 1 */ ! 230: /* case constant < 0x80000000 is handled in table */ ! 231: switch( p->in.op ) { ! 232: /* case DIV: handled in optim2() */ ! 233: case MOD: ! 234: if( p->in.left->in.op == REG && ! 235: p->in.left->tn.rval == resc->tn.rval ) ! 236: goto asgmod; ! 237: label1 = getlab(); ! 238: expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); ! 239: printf("\tjlssu\tL%d\n", label1); ! 240: expand(p, ck, "\tsubl2\tAR,A1\n"); ! 241: printf("L%d:", label1); ! 242: break; ! 243: case ASG DIV: ! 244: label1 = getlab(); ! 245: label2 = getlab(); ! 246: expand(p, ck, "cmpl\tAL,AR\n"); ! 247: printf("\tjgequ\tL%d\n", label1); ! 248: expand(p, ck, "\tmovl\t$1,AL\n"); ! 249: printf("\tjbr\tL%d\nL%d:\n", label2, label1); ! 250: expand(p, ck, "\tclrl\tAL\n"); ! 251: printf("L%d:", label2); ! 252: break; ! 253: case ASG MOD: ! 254: asgmod: ! 255: label1 = getlab(); ! 256: expand(p, ck, "cmpl\tAL,AR\n"); ! 257: printf("\tjlssu\tL%d\n", label1); ! 258: expand(p, ck, "\tsubl2\tAR,AL\n"); ! 259: printf("L%d:", label1); ! 260: break; ! 261: } ! 262: return; ! 263: } ! 264: ! 265: case 'B': /* get oreg value in temp register for left shift */ ! 266: { ! 267: register NODE *r; ! 268: if (xdebug) eprint(p, 0, &val, &val); ! 269: r = p->in.right; ! 270: if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT ) ! 271: putstr("movl"); ! 272: else { ! 273: putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); ! 274: prtype(r); ! 275: putchar('l'); ! 276: } ! 277: return; ! 278: } ! 279: ! 280: case 'C': /* num words pushed on arg stack */ ! 281: { ! 282: extern int gc_numbytes; ! 283: extern int xdebug; ! 284: ! 285: if (xdebug) printf("->%d<-",gc_numbytes); ! 286: ! 287: printf("$%d", gc_numbytes/(SZLONG/SZCHAR) ); ! 288: return; ! 289: } ! 290: ! 291: case 'D': /* INCR and DECR */ ! 292: zzzcode(p->in.left, 'A'); ! 293: putchar('\n'); ! 294: putchar('\t'); ! 295: ! 296: case 'E': /* INCR and DECR, FOREFF */ ! 297: if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1) ! 298: { ! 299: putstr(p->in.op == INCR ? "inc" : "dec"); ! 300: prtype(p->in.left); ! 301: putchar('\t'); ! 302: adrput(p->in.left); ! 303: return; ! 304: } ! 305: putstr(p->in.op == INCR ? "add" : "sub"); ! 306: prtype(p->in.left); ! 307: putchar('2'); ! 308: putchar('\t'); ! 309: adrput(p->in.right); ! 310: putchar(','); ! 311: adrput(p->in.left); ! 312: return; ! 313: ! 314: case 'F': /* register type of right operand */ ! 315: { ! 316: register NODE *n; ! 317: extern int xdebug; ! 318: register int ty; ! 319: ! 320: n = getlr( p, 'R' ); ! 321: ty = n->in.type; ! 322: ! 323: if (xdebug) printf("->%d<-", ty); ! 324: ! 325: if ( ty==DOUBLE) putchar('d'); ! 326: else if ( ty==FLOAT ) putchar('f'); ! 327: else putchar('l'); ! 328: return; ! 329: } ! 330: ! 331: case 'L': /* type of left operand */ ! 332: case 'R': /* type of right operand */ ! 333: { ! 334: register NODE *n; ! 335: extern int xdebug; ! 336: ! 337: n = getlr( p, c ); ! 338: if (xdebug) printf("->%d<-", n->in.type); ! 339: ! 340: prtype(n); ! 341: return; ! 342: } ! 343: ! 344: case 'Z': /* AND for CC with ICON -- lval is complemented */ ! 345: { ! 346: register NODE *l, *r; ! 347: ! 348: l = getlr( p, 'L' ); ! 349: r = getlr( p, 'R' ); ! 350: m = (1 << tlen(l) * SZCHAR) - 1; ! 351: r->tn.lval = ~r->tn.lval; ! 352: if( (l->in.type == CHAR || l->in.type == SHORT) && ! 353: (r->tn.lval & ~m) ) { ! 354: putstr("cvt"); ! 355: prtype(l); ! 356: putstr("l\t"); ! 357: adrput(l); ! 358: putchar(','); ! 359: adrput(resc); ! 360: putstr("\n\t"); ! 361: resc->tn.type = INT; ! 362: l = resc; ! 363: } ! 364: else if( l->in.type == UCHAR || l->in.type == USHORT ) ! 365: /* remove trash left over from complementing */ ! 366: r->tn.lval &= m; ! 367: putstr("bit"); ! 368: prtype(l); ! 369: printf("\t$%ld", r->tn.lval); ! 370: putchar(','); ! 371: adrput(l); ! 372: return; ! 373: } ! 374: ! 375: case 'U': /* 32 - n, for unsigned right shifts */ ! 376: printf("$%d", 32 - p->in.right->tn.lval ); ! 377: return; ! 378: ! 379: case 'T': /* rounded structure length for arguments */ ! 380: { ! 381: int size; ! 382: ! 383: size = p->stn.stsize; ! 384: SETOFF( size, 4); ! 385: printf("$%d", size); ! 386: return; ! 387: } ! 388: ! 389: case 'S': /* structure assignment */ ! 390: stasg(p); ! 391: break; ! 392: ! 393: default: ! 394: cerror( "illegal zzzcode" ); ! 395: } ! 396: } ! 397: ! 398: stasg(p) ! 399: register NODE *p; ! 400: { ! 401: register NODE *l, *r; ! 402: register size; ! 403: ! 404: if( p->in.op == STASG ){ ! 405: l = p->in.left; ! 406: r = p->in.right; ! 407: ! 408: } ! 409: else if( p->in.op == STARG ){ /* store an arg into a temporary */ ! 410: r = p->in.left; ! 411: } ! 412: else cerror( "STASG bad" ); ! 413: ! 414: if( r->in.op == ICON ) r->in.op = NAME; ! 415: else if( r->in.op == REG ) r->in.op = OREG; ! 416: else if( r->in.op != OREG ) cerror( "STASG-r" ); ! 417: ! 418: size = p->stn.stsize; ! 419: ! 420: if( size <= 0 || size > 65535 ) ! 421: cerror("structure size <0=0 or >65535"); ! 422: ! 423: switch(size) { ! 424: case 1: ! 425: putstr(" movb "); ! 426: break; ! 427: case 2: ! 428: putstr(" movw "); ! 429: break; ! 430: case 4: ! 431: putstr(" movl "); ! 432: break; ! 433: case 8: ! 434: putstr(" movq "); ! 435: break; ! 436: default: ! 437: printf(" movc3 $%d,", size); ! 438: break; ! 439: } ! 440: adrput(r); ! 441: if( p->in.op == STASG ){ ! 442: putchar(','); ! 443: adrput(l); ! 444: putchar('\n'); ! 445: } ! 446: else ! 447: putstr(",(sp)\n"); ! 448: ! 449: if( r->in.op == NAME ) r->in.op = ICON; ! 450: else if( r->in.op == OREG ) r->in.op = REG; ! 451: } ! 452: ! 453: NODE *makearg( ty ) int ty; { ! 454: register NODE *p, *q; ! 455: ! 456: /* build a -(sp) operand */ ! 457: p = talloc(); ! 458: p->in.op = REG; ! 459: /* the type needn't be right, just consistent */ ! 460: p->in.type = INCREF(ty); ! 461: p->tn.rval = SP; ! 462: p->tn.lval = 0; ! 463: q = talloc(); ! 464: q->in.op = ASG MINUS; ! 465: q->in.type = INCREF(ty); ! 466: q->in.left = p; ! 467: p = talloc(); ! 468: p->in.op = ICON; ! 469: p->in.type = INT; ! 470: p->tn.name = ""; ! 471: /* size of floating argument is always 2 */ ! 472: p->tn.lval = (1 + (ty == FLOAT || ty == DOUBLE)) * (SZINT/SZCHAR); ! 473: q->in.right = p; ! 474: p = talloc(); ! 475: p->in.op = UNARY MUL; ! 476: p->in.left = q; ! 477: return( p ); ! 478: } ! 479: ! 480: sconv( p, forarg ) register NODE *p; { ! 481: register NODE *l, *r; ! 482: int m, val; ! 483: ! 484: if (xdebug) eprint(p, 0, &val, &val); ! 485: r = getlr(p, 'R'); ! 486: if (p->in.op == ASSIGN) ! 487: l = getlr(p, 'L'); ! 488: else if (p->in.op == SCONV) { ! 489: m = r->in.type; ! 490: if (forarg) ! 491: l = makearg( m ); ! 492: else ! 493: l = resc; ! 494: l->in.type = m; ! 495: r = getlr(p, 'L'); ! 496: } ! 497: else { /* OPLTYPE */ ! 498: m = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT); ! 499: if (forarg) ! 500: l = makearg( m ); ! 501: else ! 502: l = resc; ! 503: l->in.type = m; ! 504: } ! 505: if (r->in.op == ICON) ! 506: if (r->in.name[0] == '\0') { ! 507: if (r->tn.lval == 0 && ! 508: (r->in.type == DOUBLE || r->in.type == FLOAT || ! 509: !forarg)) { ! 510: if (r->in.type == FLOAT) ! 511: r->in.type = DOUBLE; ! 512: putstr("clr"); ! 513: prtype(l); ! 514: putchar('\t'); ! 515: adrput(l); ! 516: goto cleanup; ! 517: } ! 518: if (r->tn.lval < 0 && r->tn.lval >= -63) { ! 519: putstr("mneg"); ! 520: prtype(l); ! 521: r->tn.lval = -r->tn.lval; ! 522: goto ops; ! 523: } ! 524: if (r->tn.lval < 0) ! 525: r->in.type = r->tn.lval >= -128 ? CHAR ! 526: : (r->tn.lval >= -32768 ? SHORT ! 527: : INT); ! 528: else if (l->in.type == FLOAT || ! 529: l->in.type == DOUBLE) ! 530: r->in.type = r->tn.lval <= 63 ? INT ! 531: : (r->tn.lval <= 127 ? CHAR ! 532: : (r->tn.lval <= 32767 ? SHORT ! 533: : INT)); ! 534: else ! 535: r->in.type = r->tn.lval <= 63 ? INT ! 536: : (r->tn.lval <= 127 ? CHAR ! 537: : (r->tn.lval <= 255 ? UCHAR ! 538: : (r->tn.lval <= 32767 ? SHORT ! 539: : (r->tn.lval <= 65535 ? USHORT ! 540: : INT)))); ! 541: if (forarg && r->in.type == INT) { ! 542: putstr("pushl\t"); ! 543: adrput(r); ! 544: goto cleanup; ! 545: } ! 546: } ! 547: else { ! 548: if (forarg && tlen(r) == SZINT/SZCHAR) { ! 549: putstr("pushl\t"); ! 550: adrput(r); ! 551: goto cleanup; ! 552: } ! 553: putstr("moval\t"); ! 554: acon(r); ! 555: putchar(','); ! 556: adrput(l); ! 557: goto cleanup; ! 558: } ! 559: ! 560: if (p->in.op == SCONV && ! 561: !(l->in.type == FLOAT || l->in.type == DOUBLE) && ! 562: !mixtypes(l, r)) { ! 563: /* ! 564: * Because registers must always contain objects ! 565: * of the same width as INTs, we may have to ! 566: * perform two conversions to get an INT. Can ! 567: * the conversions be collapsed into one? ! 568: */ ! 569: if (m = collapsible(l, r)) ! 570: r->in.type = m; ! 571: else { ! 572: /* two steps are required */ ! 573: NODE *x; ! 574: ! 575: if (forarg) { ! 576: x = resc; ! 577: x->in.type = l->in.type; ! 578: } ! 579: else { ! 580: x = &resc[1]; ! 581: *x = *l; ! 582: } ! 583: ! 584: if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type)) ! 585: putstr("movz"); ! 586: else ! 587: putstr("cvt"); ! 588: prtype(r); ! 589: prtype(x); ! 590: putchar('\t'); ! 591: adrput(r); ! 592: putchar(','); ! 593: adrput(x); ! 594: putchar('\n'); ! 595: putchar('\t'); ! 596: r = x; ! 597: } ! 598: l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT); ! 599: } ! 600: ! 601: else if ((forarg || l == resc) && ! 602: tlen(l) < SZINT/SZCHAR && ! 603: mixtypes(l, r)) { ! 604: /* two steps needed here too */ ! 605: NODE *x; ! 606: ! 607: if (forarg) { ! 608: x = resc; ! 609: x->in.type = l->in.type; ! 610: } ! 611: else { ! 612: x = &resc[1]; ! 613: *x = *l; ! 614: } ! 615: putstr("cvt"); ! 616: prtype(r); ! 617: prtype(x); ! 618: putchar('\t'); ! 619: adrput(r); ! 620: putchar(','); ! 621: adrput(x); ! 622: putstr("\n\t"); ! 623: r = x; ! 624: l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT); ! 625: } ! 626: ! 627: else if ((r->in.type == UNSIGNED || r->in.type == ULONG) && ! 628: mixtypes(l, r)) { ! 629: int label1; ! 630: NODE *x = NULL; ! 631: ! 632: #if defined(FORT) || defined(SPRECC) ! 633: if (forarg) ! 634: #else ! 635: if (forarg || l == resc) ! 636: #endif ! 637: { ! 638: /* compute in register, convert to double when done */ ! 639: x = l; ! 640: l = resc; ! 641: l->in.type = x->in.type; ! 642: } ! 643: ! 644: label1 = getlab(); ! 645: ! 646: putstr("cvtl"); ! 647: prtype(l); ! 648: putchar('\t'); ! 649: adrput(r); ! 650: putchar(','); ! 651: adrput(l); ! 652: printf("\n\tjgeq\tL%d\n\tadd", label1); ! 653: prtype(l); ! 654: putstr("2\t$0"); ! 655: prtype(l); ! 656: putstr("4.294967296e9,"); ! 657: adrput(l); ! 658: printf("\nL%d:", label1); ! 659: ! 660: #if defined(FORT) || defined(SPRECC) ! 661: if (!forarg) ! 662: #else ! 663: if (!forarg && (l->in.type == DOUBLE || l != resc)) ! 664: #endif ! 665: goto cleanup; ! 666: if (x == NULL) ! 667: cerror("sconv botch"); ! 668: if (l == x) { ! 669: r = &resc[1]; ! 670: *r = *l; ! 671: } ! 672: else { ! 673: r = l; ! 674: l = x; ! 675: } ! 676: l->in.type = DOUBLE; ! 677: putstr("\n\t"); ! 678: } ! 679: ! 680: else if( (l->in.type == FLOAT || l->in.type == DOUBLE) && ! 681: (r->in.type == UCHAR || r->in.type == USHORT) ) { ! 682: /* skip unnecessary unsigned to floating conversion */ ! 683: #if defined(FORT) || defined(SPRECC) ! 684: if (forarg) ! 685: #else ! 686: if (forarg || l == resc) ! 687: #endif ! 688: l->in.type = DOUBLE; ! 689: putstr("movz"); ! 690: prtype(r); ! 691: putstr("l\t"); ! 692: adrput(r); ! 693: putchar(','); ! 694: adrput(resc); ! 695: putstr("\n\t"); ! 696: if (l == resc) { ! 697: r = &resc[1]; ! 698: *r = *l; ! 699: } ! 700: else ! 701: r = resc; ! 702: r->in.type = INT; ! 703: } ! 704: ! 705: #if defined(FORT) || defined(SPRECC) ! 706: if (forarg && l->in.type == FLOAT) ! 707: #else ! 708: if ((forarg || l == resc) && l->in.type == FLOAT) ! 709: #endif ! 710: { ! 711: /* perform an implicit conversion to double */ ! 712: l->in.type = DOUBLE; ! 713: if (r->in.type != FLOAT && ! 714: r->in.type != CHAR && ! 715: r->in.type != SHORT) { ! 716: /* trim bits from the mantissa */ ! 717: putstr("cvt"); ! 718: prtype(r); ! 719: putstr("f\t"); ! 720: adrput(r); ! 721: putchar(','); ! 722: adrput(resc); ! 723: putstr("\n\t"); ! 724: if (l == resc) { ! 725: r = &resc[1]; ! 726: *r = *l; ! 727: } ! 728: else ! 729: r = resc; ! 730: r->in.type = FLOAT; ! 731: } ! 732: } ! 733: ! 734: if (!mixtypes(l,r)) { ! 735: if (tlen(l) == tlen(r)) { ! 736: if (forarg && tlen(l) == SZINT/SZCHAR) { ! 737: putstr("pushl\t"); ! 738: adrput(r); ! 739: goto cleanup; ! 740: } ! 741: putstr("mov"); ! 742: #ifdef FORT ! 743: if (Oflag) ! 744: prtype(l); ! 745: else { ! 746: if (l->in.type == DOUBLE) ! 747: putchar('q'); ! 748: else if(l->in.type == FLOAT) ! 749: putchar('l'); ! 750: else ! 751: prtype(l); ! 752: } ! 753: #else ! 754: prtype(l); ! 755: #endif FORT ! 756: goto ops; ! 757: } ! 758: else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type)) ! 759: putstr("movz"); ! 760: else ! 761: putstr("cvt"); ! 762: } ! 763: else ! 764: putstr("cvt"); ! 765: prtype(r); ! 766: prtype(l); ! 767: ops: ! 768: putchar('\t'); ! 769: adrput(r); ! 770: putchar(','); ! 771: adrput(l); ! 772: ! 773: cleanup: ! 774: if (forarg) ! 775: tfree(l); ! 776: } ! 777: ! 778: /* ! 779: * collapsible(dest, src) -- if a conversion with a register destination ! 780: * can be accomplished in one instruction, return the type of src ! 781: * that will do the job correctly; otherwise return 0. Note that ! 782: * a register must always end up having type INT or UNSIGNED. ! 783: */ ! 784: int ! 785: collapsible(dest, src) ! 786: NODE *dest, *src; ! 787: { ! 788: int st = src->in.type; ! 789: int dt = dest->in.type; ! 790: int newt = 0; ! 791: ! 792: /* ! 793: * Are there side effects of evaluating src? ! 794: * If the derived type will not be the same size as src, ! 795: * we may have to use two steps. ! 796: */ ! 797: if (tlen(src) > tlen(dest)) { ! 798: if (tshape(src, STARREG)) ! 799: return (0); ! 800: if (src->in.op == OREG && R2TEST(src->tn.rval)) ! 801: return (0); ! 802: } ! 803: ! 804: /* ! 805: * Can we get an object of dest's type by punning src? ! 806: * Praises be to great Cthulhu for little-endian machines... ! 807: */ ! 808: if (st == CHAR && dt == USHORT) ! 809: /* ! 810: * Special case -- we must sign-extend to 16 bits. ! 811: */ ! 812: return (0); ! 813: ! 814: if (tlen(src) < tlen(dest)) ! 815: newt = st; ! 816: else ! 817: newt = dt; ! 818: ! 819: return (newt); ! 820: } ! 821: ! 822: rmove( rt, rs, t ) TWORD t; { ! 823: printf( " %s %s,%s\n", ! 824: #ifdef FORT ! 825: !Oflag ? (t==DOUBLE ? "movq" : "movl") : ! 826: #endif ! 827: (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")), ! 828: rnames[rs], rnames[rt] ); ! 829: } ! 830: ! 831: struct respref ! 832: respref[] = { ! 833: INTAREG|INTBREG, INTAREG|INTBREG, ! 834: INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, ! 835: INTEMP, INTEMP, ! 836: FORARG, FORARG, ! 837: INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, ! 838: 0, 0 }; ! 839: ! 840: setregs(){ /* set up temporary registers */ ! 841: fregs = 6; /* tbl- 6 free regs on VAX (0-5) */ ! 842: } ! 843: ! 844: /*ARGSUSED*/ ! 845: rewfld( p ) NODE *p; { ! 846: return(1); ! 847: } ! 848: ! 849: /*ARGSUSED*/ ! 850: callreg(p) NODE *p; { ! 851: return( R0 ); ! 852: } ! 853: ! 854: base( p ) register NODE *p; { ! 855: register int o = p->in.op; ! 856: ! 857: if( o==ICON && p->tn.name[0] != '\0' ) return( 100 ); /* ie no base reg */ ! 858: if( o==REG ) return( p->tn.rval ); ! 859: if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) ! 860: return( p->in.left->tn.rval ); ! 861: if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) ! 862: return( p->tn.rval + 0200*1 ); ! 863: if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 ); ! 864: if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 ); ! 865: if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG ! 866: && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) ! 867: return( p->in.left->in.left->tn.rval + 0200*(1+2) ); ! 868: if( o==NAME ) return( 100 + 0200*1 ); ! 869: return( -1 ); ! 870: } ! 871: ! 872: offset( p, tyl ) register NODE *p; int tyl; { ! 873: ! 874: if( tyl==1 && ! 875: p->in.op==REG && ! 876: (p->in.type==INT || p->in.type==UNSIGNED) ) ! 877: return( p->tn.rval ); ! 878: if( p->in.op==LS && ! 879: p->in.left->in.op==REG && ! 880: (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && ! 881: p->in.right->in.op==ICON && ! 882: p->in.right->in.name[0]=='\0' && ! 883: (1<<p->in.right->tn.lval)==tyl) ! 884: return( p->in.left->tn.rval ); ! 885: if( tyl==2 && ! 886: p->in.op==PLUS && ! 887: (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && ! 888: p->in.left->in.op==REG && ! 889: p->in.right->in.op==REG && ! 890: p->in.left->tn.rval==p->in.right->tn.rval ) ! 891: return( p->in.left->tn.rval ); ! 892: return( -1 ); ! 893: } ! 894: ! 895: makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { ! 896: register NODE *t; ! 897: NODE *f; ! 898: ! 899: p->in.op = OREG; ! 900: f = p->in.left; /* have to free this subtree later */ ! 901: ! 902: /* init base */ ! 903: switch (q->in.op) { ! 904: case ICON: ! 905: case REG: ! 906: case OREG: ! 907: case NAME: ! 908: t = q; ! 909: break; ! 910: ! 911: case MINUS: ! 912: q->in.right->tn.lval = -q->in.right->tn.lval; ! 913: case PLUS: ! 914: t = q->in.right; ! 915: break; ! 916: ! 917: case INCR: ! 918: case ASG MINUS: ! 919: t = q->in.left; ! 920: break; ! 921: ! 922: case UNARY MUL: ! 923: t = q->in.left->in.left; ! 924: break; ! 925: ! 926: default: ! 927: cerror("illegal makeor2"); ! 928: } ! 929: ! 930: p->tn.lval = t->tn.lval; ! 931: #ifndef FLEXNAMES ! 932: { ! 933: register int i; ! 934: for(i=0; i<NCHNAM; ++i) ! 935: p->in.name[i] = t->in.name[i]; ! 936: } ! 937: #else ! 938: p->in.name = t->in.name; ! 939: #endif ! 940: ! 941: /* init offset */ ! 942: p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); ! 943: ! 944: tfree(f); ! 945: return; ! 946: } ! 947: ! 948: canaddr( p ) NODE *p; { ! 949: register int o = p->in.op; ! 950: ! 951: if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); ! 952: return(0); ! 953: } ! 954: ! 955: flshape( p ) NODE *p; { ! 956: register int o = p->in.op; ! 957: ! 958: return( o == REG || o == NAME || o == ICON || ! 959: (o == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) ); ! 960: } ! 961: ! 962: /* INTEMP shapes must not contain any temporary registers */ ! 963: shtemp( p ) register NODE *p; { ! 964: int r; ! 965: ! 966: if( p->in.op == STARG ) p = p->in.left; ! 967: ! 968: switch (p->in.op) { ! 969: case REG: ! 970: return( !istreg(p->tn.rval) ); ! 971: case OREG: ! 972: r = p->tn.rval; ! 973: if( R2TEST(r) ) { ! 974: if( istreg(R2UPK1(r)) ) ! 975: return(0); ! 976: r = R2UPK2(r); ! 977: } ! 978: return( !istreg(r) ); ! 979: case UNARY MUL: ! 980: p = p->in.left; ! 981: return( p->in.op != UNARY MUL && shtemp(p) ); ! 982: } ! 983: ! 984: if( optype( p->in.op ) != LTYPE ) return(0); ! 985: return(1); ! 986: } ! 987: ! 988: shumul( p ) register NODE *p; { ! 989: register int o; ! 990: extern int xdebug; ! 991: ! 992: if (xdebug) { ! 993: int val; ! 994: printf("shumul:\n"); ! 995: eprint(p, 0, &val, &val); ! 996: } ! 997: ! 998: o = p->in.op; ! 999: if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM ); ! 1000: ! 1001: if( ( o == INCR || o == ASG MINUS ) && ! 1002: ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) && ! 1003: p->in.right->in.name[0] == '\0' ) ! 1004: { ! 1005: switch (p->in.type) ! 1006: { ! 1007: case CHAR|PTR: ! 1008: case UCHAR|PTR: ! 1009: o = 1; ! 1010: break; ! 1011: ! 1012: case SHORT|PTR: ! 1013: case USHORT|PTR: ! 1014: o = 2; ! 1015: break; ! 1016: ! 1017: case INT|PTR: ! 1018: case UNSIGNED|PTR: ! 1019: case LONG|PTR: ! 1020: case ULONG|PTR: ! 1021: case FLOAT|PTR: ! 1022: o = 4; ! 1023: break; ! 1024: ! 1025: case DOUBLE|PTR: ! 1026: o = 8; ! 1027: break; ! 1028: ! 1029: default: ! 1030: if ( ISPTR(p->in.type) && ! 1031: ISPTR(DECREF(p->in.type)) ) { ! 1032: o = 4; ! 1033: break; ! 1034: } ! 1035: else return(0); ! 1036: } ! 1037: return( p->in.right->tn.lval == o ? STARREG : 0); ! 1038: } ! 1039: ! 1040: return( 0 ); ! 1041: } ! 1042: ! 1043: adrcon( val ) CONSZ val; { ! 1044: putchar( '$' ); ! 1045: printf( CONFMT, val ); ! 1046: } ! 1047: ! 1048: conput( p ) register NODE *p; { ! 1049: switch( p->in.op ){ ! 1050: ! 1051: case ICON: ! 1052: acon( p ); ! 1053: return; ! 1054: ! 1055: case REG: ! 1056: putstr( rnames[p->tn.rval] ); ! 1057: return; ! 1058: ! 1059: default: ! 1060: cerror( "illegal conput" ); ! 1061: } ! 1062: } ! 1063: ! 1064: /*ARGSUSED*/ ! 1065: insput( p ) NODE *p; { ! 1066: cerror( "insput" ); ! 1067: } ! 1068: ! 1069: upput( p, size ) NODE *p; int size; { ! 1070: if( size == SZLONG && p->in.op == REG ) { ! 1071: putstr( rnames[p->tn.rval + 1] ); ! 1072: return; ! 1073: } ! 1074: cerror( "upput" ); ! 1075: } ! 1076: ! 1077: adrput( p ) register NODE *p; { ! 1078: register int r; ! 1079: /* output an address, with offsets, from p */ ! 1080: ! 1081: if( p->in.op == FLD ){ ! 1082: p = p->in.left; ! 1083: } ! 1084: switch( p->in.op ){ ! 1085: ! 1086: case NAME: ! 1087: acon( p ); ! 1088: return; ! 1089: ! 1090: case ICON: ! 1091: /* addressable value of the constant */ ! 1092: putchar( '$' ); ! 1093: acon( p ); ! 1094: return; ! 1095: ! 1096: case REG: ! 1097: putstr( rnames[p->tn.rval] ); ! 1098: return; ! 1099: ! 1100: case OREG: ! 1101: r = p->tn.rval; ! 1102: if( R2TEST(r) ){ /* double indexing */ ! 1103: register int flags; ! 1104: ! 1105: flags = R2UPK3(r); ! 1106: if( flags & 1 ) putchar('*'); ! 1107: if( flags & 4 ) putchar('-'); ! 1108: if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); ! 1109: if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); ! 1110: if( flags & 2 ) putchar('+'); ! 1111: printf( "[%s]", rnames[R2UPK2(r)] ); ! 1112: return; ! 1113: } ! 1114: if( r == AP ){ /* in the argument region */ ! 1115: if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); ! 1116: printf( CONFMT, p->tn.lval ); ! 1117: putstr( "(ap)" ); ! 1118: return; ! 1119: } ! 1120: if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); ! 1121: printf( "(%s)", rnames[p->tn.rval] ); ! 1122: return; ! 1123: ! 1124: case UNARY MUL: ! 1125: /* STARNM or STARREG found */ ! 1126: if( tshape(p, STARNM) ) { ! 1127: putchar( '*' ); ! 1128: adrput( p->in.left); ! 1129: } ! 1130: else { /* STARREG - really auto inc or dec */ ! 1131: register NODE *q; ! 1132: ! 1133: q = p->in.left; ! 1134: if( q->in.right->tn.lval != tlen(p) ) ! 1135: cerror("adrput: bad auto-increment/decrement"); ! 1136: printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"), ! 1137: rnames[q->in.left->tn.rval], ! 1138: (q->in.op==INCR ? "+" : "") ); ! 1139: p->in.op = OREG; ! 1140: p->tn.rval = q->in.left->tn.rval; ! 1141: p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0); ! 1142: #ifndef FLEXNAMES ! 1143: p->in.name[0] = '\0'; ! 1144: #else ! 1145: p->in.name = ""; ! 1146: #endif ! 1147: tfree(q); ! 1148: } ! 1149: return; ! 1150: ! 1151: default: ! 1152: cerror( "illegal address" ); ! 1153: return; ! 1154: ! 1155: } ! 1156: ! 1157: } ! 1158: ! 1159: acon( p ) register NODE *p; { /* print out a constant */ ! 1160: ! 1161: if( p->in.name[0] == '\0' ) ! 1162: printf( CONFMT, p->tn.lval); ! 1163: else { ! 1164: #ifndef FLEXNAMES ! 1165: printf( "%.8s", p->in.name ); ! 1166: #else ! 1167: putstr( p->in.name ); ! 1168: #endif ! 1169: if( p->tn.lval != 0 ) { ! 1170: putchar( '+' ); ! 1171: printf( CONFMT, p->tn.lval ); ! 1172: } ! 1173: } ! 1174: } ! 1175: ! 1176: genscall( p, cookie ) register NODE *p; { ! 1177: /* structure valued call */ ! 1178: return( gencall( p, cookie ) ); ! 1179: } ! 1180: ! 1181: /* tbl */ ! 1182: int gc_numbytes; ! 1183: /* tbl */ ! 1184: ! 1185: /*ARGSUSED*/ ! 1186: gencall( p, cookie ) register NODE *p; { ! 1187: /* generate the call given by p */ ! 1188: register NODE *p1; ! 1189: register int temp, temp1; ! 1190: register int m; ! 1191: ! 1192: if( p->in.right ) temp = argsize( p->in.right ); ! 1193: else temp = 0; ! 1194: ! 1195: if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ ! 1196: /* set aside room for structure return */ ! 1197: ! 1198: if( p->stn.stsize > temp ) temp1 = p->stn.stsize; ! 1199: else temp1 = temp; ! 1200: } ! 1201: ! 1202: if( temp > maxargs ) maxargs = temp; ! 1203: SETOFF(temp1,4); ! 1204: ! 1205: if( p->in.right ){ /* make temp node, put offset in, and generate args */ ! 1206: genargs( p->in.right ); ! 1207: } ! 1208: ! 1209: p1 = p->in.left; ! 1210: if( p1->in.op != ICON ){ ! 1211: if( p1->in.op != REG ){ ! 1212: if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ ! 1213: if( p1->in.op != NAME ){ ! 1214: order( p1, INAREG ); ! 1215: } ! 1216: } ! 1217: } ! 1218: } ! 1219: ! 1220: /* tbl ! 1221: setup gc_numbytes so reference to ZC works */ ! 1222: ! 1223: gc_numbytes = temp&(0x3ff); ! 1224: /* tbl */ ! 1225: ! 1226: p->in.op = UNARY CALL; ! 1227: m = match( p, INTAREG|INTBREG ); ! 1228: ! 1229: /* compensate for deficiency in 'ret' instruction ... wah,kre */ ! 1230: /* (plus in assignment to gc_numbytes above, for neatness only) */ ! 1231: if (temp >= 1024) ! 1232: printf(" addl2 $%d,sp\n", (temp&(~0x3ff))); ! 1233: ! 1234: return(m != MDONE); ! 1235: } ! 1236: ! 1237: /* tbl */ ! 1238: char * ! 1239: ccbranches[] = { ! 1240: "eql", ! 1241: "neq", ! 1242: "leq", ! 1243: "lss", ! 1244: "geq", ! 1245: "gtr", ! 1246: "lequ", ! 1247: "lssu", ! 1248: "gequ", ! 1249: "gtru", ! 1250: }; ! 1251: /* tbl */ ! 1252: ! 1253: /*ARGSUSED*/ ! 1254: cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ ! 1255: ! 1256: if( o != 0 && ( o < EQ || o > UGT ) ) ! 1257: cerror( "bad conditional branch: %s", opst[o] ); ! 1258: printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); ! 1259: } ! 1260: ! 1261: nextcook( p, cookie ) NODE *p; { ! 1262: /* we have failed to match p with cookie; try another */ ! 1263: if( cookie == FORREW ) return( 0 ); /* hopeless! */ ! 1264: if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); ! 1265: if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); ! 1266: return( FORREW ); ! 1267: } ! 1268: ! 1269: /*ARGSUSED*/ ! 1270: lastchance( p, cook ) NODE *p; { ! 1271: /* forget it! */ ! 1272: return(0); ! 1273: } ! 1274: ! 1275: optim2( p ) register NODE *p; { ! 1276: /* do local tree transformations and optimizations */ ! 1277: ! 1278: int o; ! 1279: int i, mask; ! 1280: register NODE *l, *r; ! 1281: ! 1282: switch( o = p->in.op ) { ! 1283: ! 1284: case ASG PLUS: ! 1285: case ASG MINUS: ! 1286: case ASG MUL: ! 1287: case ASG OR: ! 1288: /* simple ASG OPSIMP -- reduce range of constant rhs */ ! 1289: l = p->in.left; ! 1290: r = p->in.right; ! 1291: if( tlen(l) < SZINT/SZCHAR && ! 1292: r->in.op==ICON && r->in.name[0]==0 ){ ! 1293: mask = (1 << tlen(l) * SZCHAR) - 1; ! 1294: if( r->tn.lval & (mask & ~(mask >> 1)) ) ! 1295: r->tn.lval |= ~mask; ! 1296: else ! 1297: r->tn.lval &= mask; ! 1298: } ! 1299: break; ! 1300: ! 1301: case AND: ! 1302: /* commute L and R to eliminate complements and constants */ ! 1303: if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 || ! 1304: l->in.op == COMPL ) { ! 1305: p->in.left = p->in.right; ! 1306: p->in.right = l; ! 1307: } ! 1308: /* fall through */ ! 1309: ! 1310: case ASG AND: ! 1311: /* change meaning of AND to ~R&L - bic on pdp11/vax */ ! 1312: r = p->in.right; ! 1313: if( r->in.op==ICON && r->in.name[0]==0 ) { ! 1314: /* check for degenerate operations */ ! 1315: l = p->in.left; ! 1316: mask = (1 << tlen(l) * SZCHAR) - 1; ! 1317: if( o == ASG AND || ISUNSIGNED(r->in.type) ) { ! 1318: i = ~r->tn.lval & mask; ! 1319: if( i == 0 ) { ! 1320: /* redundant mask */ ! 1321: r->in.op = FREE; ! 1322: ncopy(p, l); ! 1323: l->in.op = FREE; ! 1324: break; ! 1325: } ! 1326: else if( i == mask ) ! 1327: /* all bits masked off */ ! 1328: goto zero; ! 1329: r->tn.lval = i; ! 1330: if( tlen(l) < SZINT/SZCHAR ){ ! 1331: /* sign extend */ ! 1332: if( r->tn.lval & (mask & ~(mask >> 1)) ) ! 1333: r->tn.lval |= ~mask; ! 1334: else ! 1335: r->tn.lval &= mask; ! 1336: } ! 1337: break; ! 1338: } ! 1339: else if( r->tn.lval == mask && ! 1340: tlen(l) < SZINT/SZCHAR ) { ! 1341: /* use movz instead of bic */ ! 1342: r->in.op = SCONV; ! 1343: r->in.left = l; ! 1344: r->in.right = 0; ! 1345: r->in.type = ENUNSIGN(l->in.type); ! 1346: r->in.su = l->in.su > 1 ? l->in.su : 1; ! 1347: ncopy(p, r); ! 1348: p->in.left = r; ! 1349: p->in.type = INT; ! 1350: break; ! 1351: } ! 1352: /* complement constant */ ! 1353: r->tn.lval = ~r->tn.lval; ! 1354: } ! 1355: else if( r->in.op==COMPL ) { /* ~~A => A */ ! 1356: r->in.op = FREE; ! 1357: p->in.right = r->in.left; ! 1358: } ! 1359: else { /* insert complement node */ ! 1360: p->in.right = l = talloc(); ! 1361: l->in.op = COMPL; ! 1362: l->in.rall = NOPREF; ! 1363: l->in.type = r->in.type; ! 1364: l->in.left = r; ! 1365: l->in.right = NULL; ! 1366: } ! 1367: break; ! 1368: ! 1369: case SCONV: ! 1370: l = p->in.left; ! 1371: #if defined(FORT) || defined(SPRECC) ! 1372: if( p->in.type == FLOAT || p->in.type == DOUBLE || ! 1373: l->in.type == FLOAT || l->in.type == DOUBLE ) ! 1374: return; ! 1375: #else ! 1376: if( mixtypes(p, l) ) return; ! 1377: #endif ! 1378: if( l->in.op == PCONV ) ! 1379: return; ! 1380: if( (l->in.op == CALL || l->in.op == UNARY CALL) && ! 1381: l->in.type != INT && l->in.type != UNSIGNED ) ! 1382: return; ! 1383: ! 1384: /* Only trust it to get it right if the size is the same */ ! 1385: if( tlen(p) != tlen(l) ) ! 1386: return; ! 1387: ! 1388: /* clobber conversion */ ! 1389: if( l->in.op != FLD ) ! 1390: l->in.type = p->in.type; ! 1391: ncopy( p, l ); ! 1392: l->in.op = FREE; ! 1393: ! 1394: break; ! 1395: ! 1396: case ASSIGN: ! 1397: /* ! 1398: * Conversions are equivalent to assignments; ! 1399: * when the two operations are combined, ! 1400: * we can sometimes zap the conversion. ! 1401: */ ! 1402: r = p->in.right; ! 1403: l = p->in.left; ! 1404: if ( r->in.op == SCONV && ! 1405: !mixtypes(l, r) && ! 1406: l->in.op != FLD && ! 1407: tlen(l) == tlen(r) ) { ! 1408: p->in.right = r->in.left; ! 1409: r->in.op = FREE; ! 1410: } ! 1411: break; ! 1412: ! 1413: case ULE: ! 1414: case ULT: ! 1415: case UGE: ! 1416: case UGT: ! 1417: p->in.op -= (UGE-GE); ! 1418: if( degenerate(p) ) ! 1419: break; ! 1420: p->in.op += (UGE-GE); ! 1421: break; ! 1422: ! 1423: case EQ: ! 1424: case NE: ! 1425: case LE: ! 1426: case LT: ! 1427: case GE: ! 1428: case GT: ! 1429: if( p->in.left->in.op == SCONV && ! 1430: p->in.right->in.op == SCONV ) { ! 1431: l = p->in.left; ! 1432: r = p->in.right; ! 1433: if( l->in.type == DOUBLE && ! 1434: l->in.left->in.type == FLOAT && ! 1435: r->in.left->in.type == FLOAT ) { ! 1436: /* nuke the conversions */ ! 1437: p->in.left = l->in.left; ! 1438: p->in.right = r->in.left; ! 1439: l->in.op = FREE; ! 1440: r->in.op = FREE; ! 1441: } ! 1442: /* more? */ ! 1443: } ! 1444: (void) degenerate(p); ! 1445: break; ! 1446: ! 1447: case DIV: ! 1448: if( p->in.right->in.op == ICON && ! 1449: p->in.right->tn.name[0] == '\0' && ! 1450: ISUNSIGNED(p->in.right->in.type) && ! 1451: (unsigned) p->in.right->tn.lval >= 0x80000000 ) { ! 1452: /* easy to do here, harder to do in zzzcode() */ ! 1453: p->in.op = UGE; ! 1454: break; ! 1455: } ! 1456: case MOD: ! 1457: case ASG DIV: ! 1458: case ASG MOD: ! 1459: /* ! 1460: * optimize DIV and MOD ! 1461: * ! 1462: * basically we spot UCHAR and USHORT and try to do them ! 1463: * as signed ints... apparently div+mul+sub is always ! 1464: * faster than ediv for finding MOD on the VAX, when ! 1465: * full unsigned MOD isn't needed. ! 1466: * ! 1467: * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub ! 1468: * are faster for unsigned dividend and a constant divisor ! 1469: * in the right range (.5 to 1 of dividend's range for the ! 1470: * first, .333+ to .5 for the second). full unsigned is ! 1471: * already done cmp+sub in the appropriate case; the ! 1472: * other cases are less common and require more ambition. ! 1473: */ ! 1474: if( degenerate(p) ) ! 1475: break; ! 1476: l = p->in.left; ! 1477: r = p->in.right; ! 1478: if( !ISUNSIGNED(r->in.type) || ! 1479: tlen(l) >= SZINT/SZCHAR || ! 1480: !(tlen(r) < SZINT/SZCHAR || ! 1481: (r->in.op == ICON && r->tn.name[0] == '\0')) ) ! 1482: break; ! 1483: if( r->in.op == ICON ) ! 1484: r->tn.type = INT; ! 1485: else { ! 1486: NODE *t = talloc(); ! 1487: t->in.left = r; ! 1488: r = t; ! 1489: r->in.op = SCONV; ! 1490: r->in.type = INT; ! 1491: r->in.right = 0; ! 1492: p->in.right = r; ! 1493: } ! 1494: if( o == DIV || o == MOD ) { ! 1495: NODE *t = talloc(); ! 1496: t->in.left = l; ! 1497: l = t; ! 1498: l->in.op = SCONV; ! 1499: l->in.type = INT; ! 1500: l->in.right = 0; ! 1501: p->in.left = l; ! 1502: } ! 1503: /* handle asgops in table */ ! 1504: break; ! 1505: ! 1506: case RS: ! 1507: case ASG RS: ! 1508: case LS: ! 1509: case ASG LS: ! 1510: /* pick up degenerate shifts */ ! 1511: l = p->in.left; ! 1512: r = p->in.right; ! 1513: if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) ! 1514: break; ! 1515: i = r->tn.lval; ! 1516: if( i < 0 ) ! 1517: /* front end 'fixes' this? */ ! 1518: if( o == LS || o == ASG LS ) ! 1519: o += (RS-LS); ! 1520: else ! 1521: o += (LS-RS); ! 1522: if( (o == RS || o == ASG RS) && ! 1523: !ISUNSIGNED(l->in.type) ) ! 1524: /* can't optimize signed right shifts */ ! 1525: break; ! 1526: if( o == LS ) { ! 1527: if( i < SZINT ) ! 1528: break; ! 1529: } ! 1530: else { ! 1531: if( i < tlen(l) * SZCHAR ) ! 1532: break; ! 1533: } ! 1534: zero: ! 1535: if( !asgop( o ) ) ! 1536: if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { ! 1537: /* no side effects */ ! 1538: tfree(l); ! 1539: ncopy(p, r); ! 1540: r->in.op = FREE; ! 1541: p->tn.lval = 0; ! 1542: } ! 1543: else { ! 1544: p->in.op = COMOP; ! 1545: r->tn.lval = 0; ! 1546: } ! 1547: else { ! 1548: p->in.op = ASSIGN; ! 1549: r->tn.lval = 0; ! 1550: } ! 1551: break; ! 1552: } ! 1553: } ! 1554: ! 1555: degenerate(p) register NODE *p; { ! 1556: int o; ! 1557: int result, i; ! 1558: int lower, upper; ! 1559: register NODE *l, *r; ! 1560: ! 1561: /* ! 1562: * try to keep degenerate comparisons with constants ! 1563: * out of the table. ! 1564: */ ! 1565: r = p->in.right; ! 1566: l = p->in.left; ! 1567: if( r->in.op != ICON || ! 1568: r->tn.name[0] != '\0' || ! 1569: tlen(l) >= tlen(r) ) ! 1570: return (0); ! 1571: switch( l->in.type ) { ! 1572: case CHAR: ! 1573: lower = -(1 << SZCHAR - 1); ! 1574: upper = (1 << SZCHAR - 1) - 1; ! 1575: break; ! 1576: case UCHAR: ! 1577: lower = 0; ! 1578: upper = (1 << SZCHAR) - 1; ! 1579: break; ! 1580: case SHORT: ! 1581: lower = -(1 << SZSHORT - 1); ! 1582: upper = (1 << SZSHORT - 1) - 1; ! 1583: break; ! 1584: case USHORT: ! 1585: lower = 0; ! 1586: upper = (1 << SZSHORT) - 1; ! 1587: break; ! 1588: default: ! 1589: cerror("unsupported type in degenerate()"); ! 1590: } ! 1591: i = r->tn.lval; ! 1592: switch( o = p->in.op ) { ! 1593: case DIV: ! 1594: case ASG DIV: ! 1595: case MOD: ! 1596: case ASG MOD: ! 1597: /* DIV and MOD work like EQ */ ! 1598: case EQ: ! 1599: case NE: ! 1600: if( lower == 0 && (unsigned) i > upper ) ! 1601: result = o == NE; ! 1602: else if( i < lower || i > upper ) ! 1603: result = o == NE; ! 1604: else ! 1605: return (0); ! 1606: break; ! 1607: case LT: ! 1608: case GE: ! 1609: if( lower == 0 && (unsigned) i > upper ) ! 1610: result = o == LT; ! 1611: else if( i <= lower ) ! 1612: result = o != LT; ! 1613: else if( i > upper ) ! 1614: result = o == LT; ! 1615: else ! 1616: return (0); ! 1617: break; ! 1618: case LE: ! 1619: case GT: ! 1620: if( lower == 0 && (unsigned) i >= upper ) ! 1621: result = o == LE; ! 1622: else if( i < lower ) ! 1623: result = o != LE; ! 1624: else if( i >= upper ) ! 1625: result = o == LE; ! 1626: else ! 1627: return (0); ! 1628: break; ! 1629: default: ! 1630: cerror("unknown op in degenerate()"); ! 1631: } ! 1632: ! 1633: if( o == MOD || o == ASG MOD ) { ! 1634: r->in.op = FREE; ! 1635: ncopy(p, l); ! 1636: l->in.op = FREE; ! 1637: } ! 1638: else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { ! 1639: /* no side effects */ ! 1640: tfree(l); ! 1641: ncopy(p, r); ! 1642: r->in.op = FREE; ! 1643: p->tn.lval = result; ! 1644: } ! 1645: else { ! 1646: if( o == ASG DIV ) ! 1647: p->in.op = ASSIGN; ! 1648: else { ! 1649: p->in.op = COMOP; ! 1650: r->tn.type = INT; ! 1651: } ! 1652: r->tn.lval = result; ! 1653: } ! 1654: if( logop(o) ) ! 1655: p->in.type = INT; ! 1656: ! 1657: return (1); ! 1658: } ! 1659: ! 1660: /* added by jwf */ ! 1661: struct functbl { ! 1662: int fop; ! 1663: TWORD ftype; ! 1664: char *func; ! 1665: } opfunc[] = { ! 1666: DIV, TANY, "udiv", ! 1667: MOD, TANY, "urem", ! 1668: ASG DIV, TANY, "audiv", ! 1669: ASG MOD, TANY, "aurem", ! 1670: 0, 0, 0 }; ! 1671: ! 1672: hardops(p) register NODE *p; { ! 1673: /* change hard to do operators into function calls. */ ! 1674: register NODE *q; ! 1675: register struct functbl *f; ! 1676: register o; ! 1677: NODE *old,*temp; ! 1678: ! 1679: o = p->in.op; ! 1680: if( ! (optype(o)==BITYPE && ! 1681: (ISUNSIGNED(p->in.left->in.type) || ! 1682: ISUNSIGNED(p->in.right->in.type))) ) ! 1683: return; ! 1684: ! 1685: for( f=opfunc; f->fop; f++ ) { ! 1686: if( o==f->fop ) goto convert; ! 1687: } ! 1688: return; ! 1689: ! 1690: convert: ! 1691: if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) ! 1692: /* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */ ! 1693: /* save a subroutine call -- use at most 5 instructions */ ! 1694: return; ! 1695: if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) ! 1696: /* optim2() will modify the op into an ordinary int op */ ! 1697: return; ! 1698: if( asgop( o ) ) { ! 1699: old = NIL; ! 1700: switch( p->in.left->in.op ){ ! 1701: case FLD: ! 1702: q = p->in.left->in.left; ! 1703: /* ! 1704: * rewrite (lval.fld /= rval); as ! 1705: * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); ! 1706: * else the compiler will evaluate lval twice. ! 1707: */ ! 1708: if( q->in.op == UNARY MUL ){ ! 1709: /* first allocate a temp storage */ ! 1710: temp = talloc(); ! 1711: temp->in.op = OREG; ! 1712: temp->tn.rval = TMPREG; ! 1713: temp->tn.lval = BITOOR(freetemp(1)); ! 1714: temp->in.type = INCREF(p->in.type); ! 1715: #ifdef FLEXNAMES ! 1716: temp->in.name = ""; ! 1717: #else ! 1718: temp->in.name[0] = '\0'; ! 1719: #endif ! 1720: old = q->in.left; ! 1721: q->in.left = temp; ! 1722: } ! 1723: /* fall thru ... */ ! 1724: ! 1725: case REG: ! 1726: case NAME: ! 1727: case OREG: ! 1728: /* change ASG OP to a simple OP */ ! 1729: q = talloc(); ! 1730: q->in.op = NOASG p->in.op; ! 1731: q->in.rall = NOPREF; ! 1732: q->in.type = p->in.type; ! 1733: q->in.left = tcopy(p->in.left); ! 1734: q->in.right = p->in.right; ! 1735: p->in.op = ASSIGN; ! 1736: p->in.right = q; ! 1737: p = q; ! 1738: f -= 2; /* Note: this depends on the table order */ ! 1739: /* on the right side only - replace *temp with ! 1740: *(temp = &lval), build the assignment node */ ! 1741: if( old ){ ! 1742: temp = q->in.left->in.left; /* the "*" node */ ! 1743: q = talloc(); ! 1744: q->in.op = ASSIGN; ! 1745: q->in.left = temp->in.left; ! 1746: q->in.right = old; ! 1747: q->in.type = old->in.type; ! 1748: #ifdef FLEXNAMES ! 1749: q->in.name = ""; ! 1750: #else ! 1751: q->in.name[0] = '\0'; ! 1752: #endif ! 1753: temp->in.left = q; ! 1754: } ! 1755: break; ! 1756: ! 1757: case UNARY MUL: ! 1758: /* avoid doing side effects twice */ ! 1759: q = p->in.left; ! 1760: p->in.left = q->in.left; ! 1761: q->in.op = FREE; ! 1762: break; ! 1763: ! 1764: default: ! 1765: cerror( "hardops: can't compute & LHS" ); ! 1766: } ! 1767: } ! 1768: ! 1769: /* build comma op for args to function */ ! 1770: q = talloc(); ! 1771: q->in.op = CM; ! 1772: q->in.rall = NOPREF; ! 1773: q->in.type = INT; ! 1774: q->in.left = p->in.left; ! 1775: q->in.right = p->in.right; ! 1776: p->in.op = CALL; ! 1777: p->in.right = q; ! 1778: ! 1779: /* put function name in left node of call */ ! 1780: p->in.left = q = talloc(); ! 1781: q->in.op = ICON; ! 1782: q->in.rall = NOPREF; ! 1783: q->in.type = INCREF( FTN + p->in.type ); ! 1784: #ifndef FLEXNAMES ! 1785: strcpy( q->in.name, f->func ); ! 1786: #else ! 1787: q->in.name = f->func; ! 1788: #endif ! 1789: q->tn.lval = 0; ! 1790: q->tn.rval = 0; ! 1791: ! 1792: } ! 1793: ! 1794: zappost(p) NODE *p; { ! 1795: /* look for ++ and -- operators and remove them */ ! 1796: ! 1797: register int o, ty; ! 1798: register NODE *q; ! 1799: o = p->in.op; ! 1800: ty = optype( o ); ! 1801: ! 1802: switch( o ){ ! 1803: ! 1804: case INCR: ! 1805: case DECR: ! 1806: q = p->in.left; ! 1807: p->in.right->in.op = FREE; /* zap constant */ ! 1808: ncopy( p, q ); ! 1809: q->in.op = FREE; ! 1810: return; ! 1811: ! 1812: } ! 1813: ! 1814: if( ty == BITYPE ) zappost( p->in.right ); ! 1815: if( ty != LTYPE ) zappost( p->in.left ); ! 1816: } ! 1817: ! 1818: fixpre(p) NODE *p; { ! 1819: ! 1820: register int o, ty; ! 1821: o = p->in.op; ! 1822: ty = optype( o ); ! 1823: ! 1824: switch( o ){ ! 1825: ! 1826: case ASG PLUS: ! 1827: p->in.op = PLUS; ! 1828: break; ! 1829: case ASG MINUS: ! 1830: p->in.op = MINUS; ! 1831: break; ! 1832: } ! 1833: ! 1834: if( ty == BITYPE ) fixpre( p->in.right ); ! 1835: if( ty != LTYPE ) fixpre( p->in.left ); ! 1836: } ! 1837: ! 1838: /*ARGSUSED*/ ! 1839: NODE * addroreg(l) NODE *l; ! 1840: /* OREG was built in clocal() ! 1841: * for an auto or formal parameter ! 1842: * now its address is being taken ! 1843: * local code must unwind it ! 1844: * back to PLUS/MINUS REG ICON ! 1845: * according to local conventions ! 1846: */ ! 1847: { ! 1848: cerror("address of OREG taken"); ! 1849: /*NOTREACHED*/ ! 1850: } ! 1851: ! 1852: ! 1853: ! 1854: # ifndef ONEPASS ! 1855: main( argc, argv ) char *argv[]; { ! 1856: return( mainp2( argc, argv ) ); ! 1857: } ! 1858: # endif ! 1859: ! 1860: strip(p) register NODE *p; { ! 1861: NODE *q; ! 1862: ! 1863: /* strip nodes off the top when no side effects occur */ ! 1864: for( ; ; ) { ! 1865: switch( p->in.op ) { ! 1866: case SCONV: /* remove lint tidbits */ ! 1867: q = p->in.left; ! 1868: ncopy( p, q ); ! 1869: q->in.op = FREE; ! 1870: break; ! 1871: /* could probably add a few more here */ ! 1872: default: ! 1873: return; ! 1874: } ! 1875: } ! 1876: } ! 1877: ! 1878: myreader(p) register NODE *p; { ! 1879: strip( p ); /* strip off operations with no side effects */ ! 1880: canon( p ); /* expands r-vals for fields */ ! 1881: walkf( p, hardops ); /* convert ops to function calls */ ! 1882: walkf( p, optim2 ); ! 1883: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.