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