|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)optim2.c 1.1 86/02/03 Copyr 1985 Sun Micro"; ! 3: #endif ! 4: ! 5: /* ! 6: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 7: */ ! 8: ! 9: #include "cpass2.h" ! 10: ! 11: /* ! 12: * routines to detect and to deal with doubly-indexed OREGs. ! 13: * Initially, these were all stolen from the vax code. ! 14: */ ! 15: ! 16: base( p ) ! 17: register NODE *p; ! 18: { ! 19: register int o = p->in.op; ! 20: register v,maxoff; ! 21: register NODE *lp,*rp; ! 22: ! 23: if ( BTYPE(p->in.type) == DOUBLE ) ! 24: maxoff = 123; ! 25: else ! 26: maxoff = 127; ! 27: if ( o==REG && isbreg( p->tn.rval )) ! 28: return( p->tn.rval ); ! 29: lp = p->in.left; ! 30: rp = p->in.right; ! 31: if ((o==PLUS || o==MINUS) ! 32: && lp->in.op==REG && isbreg( lp->tn.rval ) ! 33: && rp->in.op==ICON && rp->in.name[0] == '\0' ! 34: && (use68020 || (v=rp->tn.lval) <= maxoff && v >= -128) ! 35: ) ! 36: return( lp->tn.rval ); ! 37: return( -1 ); ! 38: } ! 39: ! 40: offset( p, notused ) ! 41: register NODE *p; ! 42: int notused; ! 43: { ! 44: if ( p->in.op==REG ) { ! 45: if ( p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type) ) { ! 46: return( p->tn.rval ); ! 47: } ! 48: if ( p->in.type==SHORT ) { ! 49: /* ! 50: * result is: short index flag + xreg ! 51: */ ! 52: return( (1<<8) + p->tn.rval ); ! 53: } ! 54: } ! 55: if (use68020) { ! 56: /* ! 57: * test for scaled indexing ! 58: */ ! 59: int count; ! 60: NODE *lp = p->in.left; ! 61: NODE *rp = p->in.right; ! 62: if ( p->in.op==LS && lp->in.op==REG ! 63: && (lp->in.type==INT || lp->in.type==UNSIGNED || lp->in.type == SHORT ) ! 64: && (rp->in.op==ICON && rp->in.name[0]=='\0') ! 65: && (count = rp->tn.lval) >= 0 && count <= 3 ) { ! 66: int scale = (1 << count); ! 67: if ( p->in.type == SHORT ) { ! 68: /* ! 69: * result is: short index flag + scale factor + xreg ! 70: */ ! 71: return( (1<<8) + (scale<<4) + lp->tn.rval ); ! 72: } ! 73: /* ! 74: * result is: scale factor + xreg ! 75: */ ! 76: return( (scale<<4) + lp->tn.rval ); ! 77: } ! 78: } ! 79: return( -1 ); ! 80: } ! 81: ! 82: makeor2( p, basenode, breg, scale_plus_xreg ) ! 83: register NODE *p; /* node to be rewritten */ ! 84: register NODE *basenode; /* base node (usually a ptr) */ ! 85: int breg; /* base register */ ! 86: int scale_plus_xreg; /* scale factor + index register */ ! 87: { ! 88: register NODE *t; /* from which tn.lval, tn.name are obtained */ ! 89: register int i; ! 90: NODE *f; ! 91: ! 92: register flags; ! 93: int scale, xreg, shortx, ibit; ! 94: ! 95: ibit = 0; ! 96: shortx= (scale_plus_xreg >> 8) & 1; ! 97: scale = (scale_plus_xreg >> 4) & 017; ! 98: xreg = scale_plus_xreg & 017; ! 99: ! 100: p->in.op = OREG; ! 101: f = p->in.left; /* have to free this subtree later */ ! 102: ! 103: /* init base */ ! 104: switch (basenode->in.op) { ! 105: case ICON: ! 106: case REG: ! 107: case OREG: ! 108: t = basenode; ! 109: break; ! 110: ! 111: case MINUS: ! 112: basenode->in.right->tn.lval = -basenode->in.right->tn.lval; ! 113: case PLUS: ! 114: t = basenode->in.right; ! 115: break; ! 116: ! 117: case INCR: ! 118: case ASG MINUS: ! 119: t = basenode->in.left; ! 120: break; ! 121: ! 122: case UNARY MUL: ! 123: t = basenode->in.left->in.left; ! 124: break; ! 125: ! 126: default: ! 127: cerror("illegal makeor2"); ! 128: } ! 129: ! 130: p->tn.lval = t->tn.lval; ! 131: #ifndef FLEXNAMES ! 132: for(i=0; i<NCHNAM; ++i) ! 133: p->in.name[i] = t->in.name[i]; ! 134: #else ! 135: p->in.name = t->in.name; ! 136: #endif ! 137: ! 138: /* ! 139: * For 68020, R2UPK3 encodes the following data: ! 140: * int shortx:1; short index ! 141: * int ibit:1; memory indirect mode (unused) ! 142: * int scale:4; scale factor (1,2,4,8) ! 143: * For 68010, only the short index flag is encoded. ! 144: */ ! 145: R2PACKFLGS(flags,shortx,ibit,scale); ! 146: p->tn.rval = R2PACK( breg, xreg, flags ); ! 147: ! 148: tfree(f); ! 149: return; ! 150: } ! 151: ! 152: ! 153: /* ! 154: * Multiply a value by a constant. ! 155: * Multiplies are slow on the 68010, so do some shifting and ! 156: * adding here. ! 157: * For each 1-bit in the constant the value is shifted ! 158: * by n where 2**n equals the bit. ! 159: * The shifted value is then added into an accumulated value. ! 160: * One tricky part is for runs of three or more consecutive ! 161: * bits. For a number like 7, it is cheaper to calculate ! 162: * (8 - 1), than it is (3 + 2 + 1) ! 163: */ ! 164: conmul(p, cookie) ! 165: register NODE *p; ! 166: { ! 167: register const; /* The constant value */ ! 168: register int curpos; /* Position of last one bit */ ! 169: register int power; /* The bit being tested */ ! 170: int run; /* Num of consecutive one bits */ ! 171: int nbits; /* Num of bits since the last one bit */ ! 172: int negconst; /* Is the constant <0 ? */ ! 173: char * destreg; /* name of "AL" register */ ! 174: char * helper; /* name of "A1" register */ ! 175: int helperreg; ! 176: TWORD ltype; ! 177: char typechar; ! 178: int t; ! 179: ! 180: /* ! 181: * first determine how many instructions we will need to do ! 182: * it in line. Cost estimator is: # single bits + 2* # of multi bit ! 183: * runs. If this exceeds 5, then it is more compact to use a ! 184: * multiply instruction or routine. ! 185: */ ! 186: const = p->in.right->tn.lval; ! 187: if (const<0){ ! 188: negconst = 1; ! 189: const = - const; ! 190: } else ! 191: negconst = 0; ! 192: run = const & (const>>1); /* each run shortened by one bit */ ! 193: run = cntbits( run ^ (run>>1) ) + (run&1); /* 2*# multibit runs */ ! 194: nbits = cntbits( const ^ (const>>1)) +(const&1); /* 2* #total runs*/ ! 195: run += nbits; /* 2* estimator */ ! 196: ltype = p->in.left->in.type; ! 197: if ((ttype(ltype,TUCHAR|TCHAR|TUSHORT|TSHORT) && run>6) || (run > 10)){ ! 198: /* old-fashioned way */ ! 199: if (tshape( p->in.right, SSCON ) ){ ! 200: if (negconst){ ! 201: expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); ! 202: p->in.right->tn.lval = const; ! 203: } ! 204: if (ttype(ltype, TSHORT|TCHAR)){ ! 205: expand( p, cookie, " muls #CR,AL\nZv"); ! 206: } else if (ttype(ltype, TUSHORT|TUCHAR)){ ! 207: expand( p, cookie, " mulu #CR,AL\n"); ! 208: } else if (use68020) { ! 209: if (ISUNSIGNED(p->in.type)) { ! 210: expand( p, cookie, " mulul #CR,AL\n"); ! 211: } else { ! 212: expand( p, cookie, " mulsl #CR,AL\nZv"); ! 213: } ! 214: } else { ! 215: ! 216: expand( p, cookie, ! 217: "\tmovl\tAL,A1\n\tswap\tA1\n\tmulu\t#CR,AL\n"); ! 218: fputs( ttype(ltype, TULONG|TUNSIGNED|TUCHAR|TPOINT) ! 219: ? "\tmulu" : "\tmuls", stdout); ! 220: expand( p, cookie, ! 221: "\t#CR,A1\n\tswap\tA1\n\tclrw\tA1\n\taddl\tA1,AL\nZv"); ! 222: } ! 223: } else if (use68020) { ! 224: if (ISUNSIGNED(p->in.type)) { ! 225: expand( p, cookie, " mulul #CR,AL\n"); ! 226: } else { ! 227: expand( p, cookie, " mulsl #CR,AL\nZv"); ! 228: } ! 229: } else { ! 230: order( p->in.right, INTAREG ); ! 231: order( p, INAREG|INTAREG ); ! 232: } ! 233: return; ! 234: } ! 235: typechar = (((t=p->in.type)==CHAR)||t==UCHAR) ? 'b' ! 236: : (t==SHORT||t==USHORT) ? 'w' ! 237: : 'l'; ! 238: /* ! 239: * if the result type is larger than the operand type, we must expand ! 240: * the operand before doing the operation. ! 241: */ ! 242: switch( p->in.left->tn.type){ ! 243: case UCHAR: ! 244: case USHORT: ! 245: if (typechar=='b' || typechar=='w') break; ! 246: expand( p->in.left, INAREG|INTAREG, " andl #0xffff,AL\n"); ! 247: break; ! 248: case CHAR: ! 249: case SHORT: ! 250: if (typechar=='b' || typechar=='w') break; ! 251: expand( p->in.left, INAREG|INTAREG, " extl AL\n"); ! 252: break; ! 253: } ! 254: p->in.left->tn.type = t; ! 255: nbits = ffs( const )-1; ! 256: power = 0; ! 257: helperreg = resc[0].tn.rval ; ! 258: helper = rnames[ helperreg ]; ! 259: destreg = rnames[ p->in.left->tn.rval]; ! 260: if (negconst){ ! 261: expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); ! 262: } ! 263: if (nbits>0){ ! 264: shiftreg( nbits, destreg, helperreg , 1, typechar, t); ! 265: const >>= nbits; ! 266: } ! 267: if (const==1) return; ! 268: /* ! 269: * the first time is special (ask Ann Landers). If it is a run, ! 270: * then we move, negate, shift add. Otherwise, we don't negate. ! 271: */ ! 272: run = ffs( ~const) -1; ! 273: expand(p, cookie, " movZB AL,A1\n"); ! 274: switch (run){ ! 275: case 2: ! 276: shiftreg( 1, helper, -1, 1, typechar, t); ! 277: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 278: /* fall through */ ! 279: case 1: ! 280: curpos = 0; ! 281: break; ! 282: default: ! 283: shiftreg( run, helper, -1, 1, typechar, t); ! 284: expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); ! 285: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 286: curpos = 1; ! 287: break; ! 288: } ! 289: for ( const >>= run; const >>= (power=ffs(const))-1; const >>= run){ ! 290: run = ffs(~const)-1; ! 291: switch(run) { ! 292: case 1: ! 293: shiftreg( power-curpos, helper, -1, 1, typechar, t); ! 294: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 295: curpos = 0; ! 296: break; ! 297: case 2: ! 298: shiftreg( power-curpos, helper, -1, 1, typechar, t); ! 299: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 300: shiftreg( 1, helper, -1, 1, typechar, t); ! 301: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 302: curpos = 0; ! 303: break; ! 304: default: ! 305: shiftreg( power-curpos, helper, -1, 1, typechar, t); ! 306: expand( p, cookie, "\tsubZB\tA1,AL\nZv"); ! 307: shiftreg( run, helper, -1, 1, typechar, t); ! 308: expand( p, cookie, "\taddZB\tA1,AL\nZv"); ! 309: curpos = 1; ! 310: break; ! 311: } ! 312: } ! 313: } ! 314: ! 315: /* ! 316: * divide a signed number by a constant. ! 317: * divides are really slow on this machine, so we really want to avoid them. ! 318: * the only interesting case is divide by power-of-two. Others, we really ! 319: * have to do the division. ! 320: */ ! 321: void ! 322: condiv( p, cookie ) register NODE *p; ! 323: { ! 324: char sizechar; ! 325: register const; ! 326: register TWORD ltype; ! 327: int lab1f; ! 328: char * lname = rnames[p->in.left->tn.rval]; ! 329: const = p->in.right->tn.lval; ! 330: ltype = p->in.left->tn.type; ! 331: if (const & (const-1)){ ! 332: /* too bad -- not a positive power of two */ ! 333: switch (ltype){ ! 334: case CHAR: ! 335: print_str_str_nl( " extw ", lname ); ! 336: /* fall through */ ! 337: case SHORT: ! 338: print_str_str_nl( " extl ", lname ); ! 339: printf( " divs #%d,%s\n", const, lname); ! 340: break; ! 341: default: ! 342: if (use68020) { ! 343: printf( " divsl #%d,%s\n", ! 344: const, lname); ! 345: } else { ! 346: order( p->in.right, INTAREG ); ! 347: order( p, INTAREG ); ! 348: } ! 349: break; ! 350: } ! 351: return; ! 352: } ! 353: switch (ltype){ ! 354: case CHAR: sizechar = 'b'; break; ! 355: case SHORT: sizechar = 'w'; break; ! 356: default: sizechar = 'l'; ! 357: } ! 358: lab1f = getlab(); ! 359: printf(" tst%c %s\n jge L%d\n", sizechar, lname, lab1f); ! 360: print_str((const >= 1 && const <= 8) ? " addq" : " add"); ! 361: printf("%c #%d,%s\n", sizechar, const-1, lname ); ! 362: deflab(lab1f); ! 363: const = ffs(const)-1; ! 364: /* like shiftreg(), but for right, arithmetic shifts */ ! 365: while (const > 0){ ! 366: if (const> 8){ ! 367: printf(" asr%c #8,%s\n", sizechar, lname ); ! 368: const -= 8; ! 369: } else { ! 370: printf(" asr%c #%d,%s\n", sizechar, const, lname ); ! 371: const = 0; ! 372: } ! 373: } ! 374: return; ! 375: } ! 376: ! 377: ! 378: /* ! 379: * remainder a signed number by a constant. ! 380: * remainders are really slow on this machine, so we really want to avoid them. ! 381: * the only interesting case is powers-of-two. Others, we really ! 382: * have to do the division. ! 383: */ ! 384: void ! 385: conrem( p, cookie ) register NODE *p; ! 386: { ! 387: char sizechar, opchar; ! 388: register const; ! 389: register TWORD ltype; ! 390: char * lname = rnames[p->in.left->tn.rval]; ! 391: char * helper, u; ! 392: int lab1f, lab2f; ! 393: const = p->in.right->tn.lval; ! 394: ltype = p->in.left->tn.type; ! 395: if (const & (const-1)){ ! 396: /* too bad -- not a positive power of two */ ! 397: switch (ltype){ ! 398: case CHAR: ! 399: print_str_str_nl( " extw ", lname ); ! 400: /* fall through */ ! 401: case SHORT: ! 402: print_str_str_nl( " extl ", lname ); ! 403: printf( " divs #%d,%s\n", const, lname); ! 404: print_str_str_nl( " swap ", lname ); ! 405: break; ! 406: case UCHAR: ! 407: print_str_str_nl(" andl #0xff,", lname ); ! 408: goto divu; ! 409: case USHORT: ! 410: print_str_str_nl(" andl #0xffff,", lname ); ! 411: divu: printf(" divu #%d,%s\n", const, lname); ! 412: print_str_str_nl(" swap ", lname); ! 413: break; ! 414: default: ! 415: if (use68020) { ! 416: helper = rnames[resc[0].tn.rval]; ! 417: printf(" %s #%d,%s:%s\n", ! 418: (ISUNSIGNED(ltype)? "divull" : "divsll"), ! 419: const, helper, lname); ! 420: printf(" movl %s,%s\n", helper, lname); ! 421: } else { ! 422: order( p->in.right, INTAREG ); ! 423: order( p, INTAREG ); ! 424: } ! 425: break; ! 426: } ! 427: return; ! 428: } ! 429: helper = rnames[resc[0].tn.rval]; ! 430: u = 0; ! 431: switch (ltype){ ! 432: case UCHAR: u = 1; /* fall through */ ! 433: case CHAR: sizechar = 'b'; opchar = 'w'; break; ! 434: case USHORT: u = 1; /* fall through */ ! 435: case SHORT: sizechar = 'w'; opchar = 'w'; break; ! 436: case UNSIGNED: u = 1; /* fall through */ ! 437: default: sizechar = 'l'; opchar = 'l'; ! 438: } ! 439: if (!u){ ! 440: lab1f = getlab(); ! 441: lab2f = getlab(); ! 442: } ! 443: if (const<=128 && const >=-128){ ! 444: printf(" moveq #%d,%s\n", const-1, helper); ! 445: if (!u){ ! 446: printf(" tst%c %s\n jge L%d\n neg%c %s\n", ! 447: sizechar, lname, lab1f, sizechar, lname); ! 448: printf(" and%c %s,%s\n neg%c %s\n jra L%d\n", ! 449: opchar, helper, lname, opchar, lname, lab2f ); ! 450: deflab( lab1f ); ! 451: } ! 452: printf(" and%c %s,%s\n", opchar, helper, lname); ! 453: if (!u){ deflab(lab2f);} ! 454: } else { ! 455: if (!u){ ! 456: printf(" mov%c %s,%s\n jge L%d\n neg%c %s\n", ! 457: sizechar, lname, helper, lab1f, sizechar, lname); ! 458: deflab(lab1f); ! 459: } ! 460: printf(" and%c #%d,%s\n", opchar, const-1, lname ); ! 461: if (!u){ ! 462: printf(" tst%c %s\n jge L%d\n neg%c %s\n", ! 463: sizechar, helper, lab2f, opchar, lname ); ! 464: deflab(lab2f); ! 465: } ! 466: } ! 467: return; ! 468: } ! 469: ! 470: optim2( p ) ! 471: register NODE *p; ! 472: { ! 473: register NODE *q; ! 474: register NODE *r; ! 475: register long v; ! 476: register op; ! 477: int w; ! 478: int lsize, rsize; ! 479: NODE *rl, *rr, *qq; ! 480: TWORD t; ! 481: ! 482: /* ! 483: * reduction of strength on integer constant operands ! 484: * this is a practical, fruitful area of peephole code optimization, ! 485: * since there are so many easy things that can be done. ! 486: * we also check for possible single-o OREGs in a place where ! 487: * the oreg2() should but does not. ! 488: */ ! 489: op = p->in.op; ! 490: switch (optype(op)) { ! 491: case LTYPE: ! 492: break; ! 493: case UTYPE: ! 494: optim2(p->in.left); ! 495: break; ! 496: case BITYPE: ! 497: optim2(p->in.left); ! 498: optim2(p->in.right); ! 499: break; ! 500: } ! 501: switch (op){ ! 502: case LS: ! 503: case ASG LS: ! 504: case RS: ! 505: case ASG RS: ! 506: /* if rhs is an extending SCONV, don't bother converting */ ! 507: r = p->in.right; ! 508: if (isconv(r, SHORT, USHORT) || isconv(r, CHAR, UCHAR)) { ! 509: q = r->in.left; ! 510: *r = *q; ! 511: q->in.op = FREE; ! 512: } ! 513: /* one interesting case: <lhs> <op> 0 */ ! 514: if (r->tn.op != ICON ) break; ! 515: if (r->tn.lval == 0 && r->tn.name[0] == '\0' ){ ! 516: promoteleft: ! 517: t = p->in.type; ! 518: q = p->in.left; ! 519: *p = *q; /* paint over */ ! 520: p->in.type = t; ! 521: q->in.op = r->in.op = FREE; ! 522: } ! 523: /* could test for count of 1, too, but this is easier to do later on */ ! 524: break; ! 525: ! 526: case UNARY MUL: ! 527: /* in case this wasn't done earlier... */ ! 528: if (p->in.left->in.op == ICON) { ! 529: q = p->in.left; ! 530: t = p->in.type; ! 531: *p = *q; ! 532: p->in.op = NAME; ! 533: p->in.type = t; ! 534: q->in.op = FREE; ! 535: break; ! 536: } ! 537: /* ! 538: * put potential double index OREG trees into a canonical ! 539: * form: ( <base> + <offset> ) + <index> ! 540: */ ! 541: p = p->in.left; ! 542: if (p->in.op != PLUS) ! 543: break; ! 544: q = p->in.left; ! 545: r = p->in.right; ! 546: if ( ISPTR(r->in.type) ) { ! 547: /* ! 548: * put the pointer on the left ! 549: */ ! 550: p->in.left = r; ! 551: p->in.right = q; ! 552: q = p->in.left; ! 553: r = p->in.right; ! 554: } ! 555: if ( ISPTR(q->in.type) ! 556: && (r->in.op == PLUS || r->in.op == MINUS) ! 557: && !ISPTR(r->in.left->in.type) ! 558: && r->in.right->in.op == ICON ) { ! 559: /* ! 560: * <ptr exp> + ( <int exp> [+-] ICON ) ! 561: * rewrite as ! 562: * (<ptr exp> [+-] ICON) + <int exp> ! 563: */ ! 564: p->in.right = r->in.left; ! 565: r->in.left = q; ! 566: p->in.left = r; ! 567: r->in.type = q->in.type; ! 568: break; ! 569: } ! 570: if (r->in.op == LS ! 571: && ( (rr = r->in.right)->in.op == ICON ) ! 572: && ( (rl = r->in.left)->in.op == PLUS ! 573: || rl->in.op == MINUS ) ! 574: && !ISPTR(rl->in.left->in.type) ! 575: && rl->in.right->in.op == ICON ) { ! 576: /* ! 577: * <ptr exp> + ((<int exp> [+-] ICON) << ICON) ! 578: * rewrite as ! 579: * (<ptr exp> [+-] ICON*) + (<int exp> << ICON) ! 580: */ ! 581: r->in.left = rl->in.left; ! 582: rl->in.left = q; ! 583: p->in.left = rl; ! 584: rl->in.type = q->in.type; ! 585: rl->in.right->tn.lval <<= rr->tn.lval; ! 586: break; ! 587: } ! 588: break; ! 589: ! 590: case PLUS: ! 591: case ASG PLUS: ! 592: case MINUS: ! 593: case ASG MINUS: ! 594: /* ! 595: * one interesting cases: <lhs> <op> 0. ! 596: * <address reg> + SCONV( <short> ) is a good one, too, ! 597: * but is best done later on. ! 598: */ ! 599: if (((r=p->in.right)->tn.op == ICON ! 600: && r->tn.lval == 0 && r->tn.name[0] == '\0' ) ! 601: || (r->tn.op == FCON && r->fpn.dval == 0.0 )) { ! 602: goto promoteleft; ! 603: } ! 604: break; ! 605: ! 606: case MUL: ! 607: /* ! 608: * put constants on the right ! 609: */ ! 610: if (p->in.left->in.op == ICON && p->in.right->in.op != ICON) { ! 611: r = p->in.right; ! 612: p->in.right = p->in.left; ! 613: p->in.left = r; ! 614: } ! 615: /* fall through */ ! 616: ! 617: case ASG MUL: ! 618: case DIV: ! 619: case ASG DIV: ! 620: case MOD: ! 621: case ASG MOD: ! 622: /* ! 623: * two interesting case: <lhs> <op> 1 ! 624: * and: small multiplies that can be handled by ! 625: * the feeble instructions. ! 626: */ ! 627: if (((r=p->in.right)->tn.op == ICON ! 628: && r->tn.lval == 1 && r->tn.name[0] == '\0') ! 629: || (r->tn.op == FCON && r->fpn.dval == 1.0 )) { ! 630: switch (op){ ! 631: case MOD: ! 632: case ASG MOD: ! 633: /* ! 634: * x%1 == 0 ! 635: * BUT x might have side effects, so... ! 636: * x%1 ==> (x,0) ! 637: */ ! 638: p->in.op = COMOP; ! 639: if (r->tn.op==FCON) ! 640: r->fpn.dval = 0.0; ! 641: else ! 642: r->tn.lval = 0; ! 643: break; ! 644: default: ! 645: goto promoteleft; ! 646: } ! 647: break; ! 648: } ! 649: if (op == DIV || op == ASG DIV){ ! 650: /* ! 651: * a very particular case: a difference of two ! 652: * pointers, divided by a power of two should ! 653: * always give an integral result (this is ! 654: * pointer subtraction, with the implied divide ! 655: * by sizeof( *p ) ). So, we can change this ! 656: * into a shift, if we ever see it. ! 657: * AND... ! 658: * a less peculiar case: unsigned divide by a power of 2. ! 659: */ ! 660: if ( ! 661: (p->in.type == UNSIGNED && r->in.op ==ICON ) ! 662: || ((p->in.type == INT || p->in.type == UNSIGNED) ! 663: && r->in.op == ICON && (q = p->in.left)->in.op == MINUS ! 664: && ISPTR(q->in.left->in.type) ! 665: && ISPTR(q->in.right->in.type)) ! 666: ){ ! 667: if (cntbits( v=r->tn.lval )==1 && r->in.name[0]=='\0' ){ ! 668: /* well, looks like we found one */ ! 669: w = ffs( v ) - 1; ! 670: p->in.op = op += RS - DIV; /* keep ASG if present */ ! 671: r->tn.lval = w; ! 672: break; ! 673: } ! 674: } ! 675: } ! 676: /* the other good case is multiply by a power of two, ! 677: and thats already being handled in the front end */ ! 678: /* ! 679: * many multiplies ! 680: * can be done directly in the hardware: ! 681: * {SHORT, USHORT, CHAR, UCHAR} x ! 682: * {SHORT, USHORT, CHAR, UCHAR, ICON} ! 683: * ! 684: * so can the corresponding divides. ! 685: */ ! 686: if (p->in.type != INT && p->in.type != UNSIGNED && ! 687: !ISPTR(p->in.type)) ! 688: break; ! 689: q = p->in.left; ! 690: if ( isconv(q, SHORT, USHORT ) ) lsize = 2; ! 691: else if (isconv(q, CHAR, UCHAR )) lsize = 1; ! 692: else if (q->in.type == SHORT) lsize = 0; ! 693: else break; ! 694: if ( isconv(r, SHORT, USHORT ) || ! 695: special(r, SSCON) ) rsize = 2; ! 696: else if (isconv(r, CHAR, UCHAR )) rsize = 1; ! 697: else break; ! 698: /* we've looked at both sides and it looks plausable */ ! 699: /* rearrange lhs */ ! 700: if (lsize == 1){ ! 701: /* diddle SCONV, but leave it in place */ ! 702: q->in.type = (q->in.left->tn.type==UCHAR)?USHORT:SHORT; ! 703: } else if(lsize == 2){ ! 704: p->in.left = q->in.left; ! 705: q->in.op = FREE; ! 706: } ! 707: /* now rearrange rhs */ ! 708: if (rsize == 1){ ! 709: r->in.type = (r->in.left->tn.type==UCHAR)?USHORT:SHORT; ! 710: } else if (r->tn.op == ICON){ ! 711: r->tn.type = SHORT; ! 712: } else { ! 713: p->in.right = r->in.left; ! 714: r->in.op = FREE; ! 715: } ! 716: /* ! 717: * The result of the mul[us] instructions are ints ! 718: * anyway, so leave the type of the MUL node alone. ! 719: * But DIV must be acknowleged as short. ! 720: */ ! 721: if ( (op==DIV || op== ASG DIV || op==MOD || op==ASG MOD) ! 722: && p->in.type != SHORT && p->in.type != USHORT){ ! 723: w = (p->in.right->tn.type==SHORT && p->in.left->tn.type==SHORT) ? SHORT : USHORT; ! 724: q = talloc(); ! 725: *q = *p; ! 726: p->in.op = SCONV; ! 727: q->in.type = w; ! 728: p->in.left = q; ! 729: p->in.right = 0; ! 730: } ! 731: break; ! 732: case SCONV: ! 733: /* ! 734: * conversions from float to double ! 735: * in a coprocessor register are vacuous ! 736: */ ! 737: q = p->in.left; ! 738: if (p->in.type == DOUBLE && q->in.type == FLOAT ! 739: && q->in.op == REG && iscreg(q->tn.rval)) { ! 740: TWORD t = p->in.type; ! 741: *p = *q; ! 742: p->in.type = t; ! 743: q->in.op = FREE; ! 744: return; ! 745: } ! 746: /* ! 747: * John Gilmore memorial hack ! 748: * ! 749: * garbage-can case: ! 750: * if this is a shorten of a simple calculation ! 751: * whose (2) operands are no larger than the ! 752: * result type, then we can do the operation more ! 753: * cheaply, no? ! 754: * The architypical case looks like: ! 755: * (SCONV<short> (+<int> (SCONV<int> NAME<short> ) ICON )) ! 756: * p^ q^ r^ ! 757: */ ! 758: if ( q->in.type!=INT && q->in.type!=UNSIGNED ) return; ! 759: switch (q->in.op){ ! 760: case PLUS: ! 761: case MINUS: ! 762: case MUL: ! 763: case DIV: ! 764: case MOD: ! 765: case LS: ! 766: case RS: ! 767: case AND: ! 768: case OR: ! 769: case ER: ! 770: break; ! 771: default: ! 772: return; ! 773: } ! 774: if ( p->in.type==SHORT || p->in.type==USHORT ){ ! 775: w = 2; ! 776: v = 0x7fff; ! 777: }else if ( p->in.type==CHAR || p->in.type==UCHAR ){ ! 778: w = 1; ! 779: v = 0x7f; ! 780: }else break; ! 781: qq = q; ! 782: r = q->in.right; ! 783: q = q->in.left; ! 784: if ( isconv(q, SHORT, USHORT ) ) lsize = 2; ! 785: else if (isconv(q, CHAR, UCHAR )) lsize = 1; ! 786: else if (q->in.op == ICON) ! 787: if (q->tn.name[0] == '\0' ! 788: && ((q->tn.lval | v)==v || (q->tn.lval|v)==-1)) ! 789: lsize = 0; ! 790: else break; ! 791: else if (tlen(q) < sizeof(long)) lsize = -1; ! 792: else break; ! 793: if ( isconv(r, SHORT, USHORT ) ) rsize = 2; ! 794: else if (isconv(r, CHAR, UCHAR )) rsize = 1; ! 795: else if (r->in.op == ICON) ! 796: if (r->tn.name[0] == '\0' ! 797: && ((r->tn.lval | v)==v || (r->tn.lval|v)==-1)) ! 798: rsize = 0; ! 799: else break; ! 800: else if (tlen(r) < sizeof(long)) rsize = -1; ! 801: else break; ! 802: if (lsize == -1) { ! 803: NODE *t = talloc(); ! 804: t->in.op = SCONV; ! 805: t->in.type = qq->in.type; ! 806: t->in.left = q; ! 807: lsize = tlen(q); ! 808: q = t; ! 809: qq->in.left = q; ! 810: } ! 811: if (rsize == -1) { ! 812: NODE *t = talloc(); ! 813: t->in.op = SCONV; ! 814: t->in.type = qq->in.type; ! 815: t->in.left = r; ! 816: rsize = tlen(r); ! 817: r = t; ! 818: qq->in.right = r; ! 819: } ! 820: if (rsize > w || lsize > w) { ! 821: /* must preserve top SCONV, but weaken operation */ ! 822: p = p->in.left; ! 823: if (rsize >lsize){ ! 824: p->in.type = r->in.left->in.type ; ! 825: w = rsize; ! 826: } else { ! 827: p->in.type = q->in.left->in.type; ! 828: w = lsize; ! 829: } ! 830: } else { ! 831: /* clobber SCONV */ ! 832: NODE * t = p->in.left; ! 833: TWORD tt = p->in.type; ! 834: *p = *t; /* paint over */ ! 835: p->in.type = tt; /* except type */ ! 836: t->in.op = FREE; /* give a node back */ ! 837: } ! 838: /* now weaken or elide child convs */ ! 839: switch (lsize){ ! 840: case 0: /* ICON -- diddle type */ ! 841: q->in.type = p->in.type; break; ! 842: case 1: /* char */ ! 843: if (lsize <w){ ! 844: /* retain SCONV but weaken */ ! 845: q->in.type = p->in.type; break; ! 846: } ! 847: /* else fall through */ ! 848: case 2: /* same size -- elide SCONV */ ! 849: { NODE * t = q->in.left; ! 850: *q = *t; ! 851: t->in.op = FREE; ! 852: } ! 853: } ! 854: switch (rsize){ ! 855: case 0: /* ICON -- diddle type */ ! 856: r->in.type = p->in.type; break; ! 857: case 1: /* char */ ! 858: if (rsize <w){ ! 859: /* retain SCONV but weaken */ ! 860: r->in.type = p->in.type; break; ! 861: } ! 862: /* else fall through */ ! 863: case 2: /* same size -- elide SCONV */ ! 864: { NODE * t = r->in.left; ! 865: *r = *t; ! 866: t->in.op = FREE; ! 867: } ! 868: } ! 869: break; ! 870: case CHK: ! 871: /* ! 872: * A CHK with constant bounds, of which the left-hand-side ! 873: * is an SCONV that widens a shorter type can be converted ! 874: * to an SCONV over a CHK. This lets us use weaker CHK ! 875: * instructions. ! 876: */ ! 877: if (p->in.type != INT && p->in.type != UNSIGNED) break; ! 878: q = p->in.left; ! 879: if (!isconv(q, CHAR, UCHAR) && !isconv(q, SHORT, USHORT) )break; ! 880: r = p->in.right; ! 881: rr = r->in.right; ! 882: rl = r->in.left; ! 883: if (rr->in.op != ICON || rl->in.op != ICON) break; ! 884: /* ! 885: * make bounds smaller using the type of the ! 886: * converted operand ! 887: */ ! 888: t = q->in.left->in.type; ! 889: switch(t) { ! 890: case CHAR: ! 891: if (reduce_bounds(-128, 127, rl, rr)) ! 892: goto delete_check; ! 893: break; ! 894: case UCHAR: ! 895: if (reduce_bounds(0, 255, rl, rr)) ! 896: goto delete_check; ! 897: break; ! 898: case SHORT: ! 899: if (reduce_bounds(-32768, 32767, rl, rr)) ! 900: goto delete_check; ! 901: break; ! 902: case USHORT: ! 903: if (reduce_bounds(0, 65535, rl, rr)) ! 904: goto delete_check; ! 905: break; ! 906: delete_check: ! 907: *p = *q; ! 908: q->in.op = FREE; ! 909: tfree(r); ! 910: return; ! 911: } ! 912: /* ! 913: * weaken the conversion by ! 914: * exchanging CHK and SCONV nodes ! 915: */ ! 916: *p = *q; /* p becomes SCONV node */ ! 917: p->in.left = q; ! 918: q->in.op = CHK; ! 919: q->in.right = r; ! 920: q->in.type = r->in.type = rl->tn.type = rr->tn.type = t; ! 921: break; ! 922: ! 923: case INIT: ! 924: /* ! 925: * not an optimization, but prevents an ! 926: * infinite loop later on in code generation... ! 927: */ ! 928: q = p->in.left; ! 929: if (q->in.op != ICON && q->in.op != FCON) { ! 930: uerror("Illegal initialization"); ! 931: tfree(q); ! 932: q = talloc(); ! 933: q->in.type = p->in.type; ! 934: if (ISFLOATING(p->in.type)) { ! 935: q->in.op = FCON; ! 936: q->fpn.dval = 0.0; ! 937: } else { ! 938: q->in.op = ICON; ! 939: q->tn.name = ""; ! 940: q->tn.lval = 0; ! 941: } ! 942: p->in.left = q; ! 943: } ! 944: break; ! 945: ! 946: case FORCE: ! 947: /* ! 948: * if the type of a FORCE op is {u}char or {u}short, ! 949: * extend it into an INT. ! 950: */ ! 951: switch(p->in.type){ ! 952: case CHAR: ! 953: case UCHAR: ! 954: case SHORT: ! 955: case USHORT: ! 956: q = talloc(); ! 957: q->in.op = SCONV; ! 958: q->in.type = INT; ! 959: q->in.left = p->in.left; ! 960: q->in.right = NULL; ! 961: p->in.left = q; ! 962: p->in.type = INT; ! 963: break; ! 964: } ! 965: break; ! 966: ! 967: } /* switch */ ! 968: } ! 969: ! 970: /* ! 971: * reduce bounds of a range check using ! 972: * the known bounds of the domain type ! 973: */ ! 974: int ! 975: reduce_bounds(domain_min, domain_max, range_min, range_max) ! 976: register CONSZ domain_min, domain_max; ! 977: register NODE *range_min, *range_max; ! 978: { ! 979: /* do the domain and range intersect? */ ! 980: if (domain_min > range_max->tn.lval || domain_max < range_min->tn.lval) { ! 981: /* expression value is known to lie outside required range */ ! 982: werror("expression value is out of range"); ! 983: } ! 984: /* range := intersection(range, domain) */ ! 985: if (domain_min > range_min->tn.lval) ! 986: range_min->tn.lval = domain_min; ! 987: if (domain_max < range_max->tn.lval) ! 988: range_max->tn.lval = domain_max; ! 989: /* if domain is a subset of range, range check is unnecessary */ ! 990: if (domain_min >= range_min->tn.lval && domain_max <= range_max->tn.lval) { ! 991: return(1); ! 992: } ! 993: return(0); ! 994: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.