|
|
1.1 ! root 1: /* @(#) w2opt.c: 1.6 4/28/84 */ ! 2: /* w2opt.c ! 3: ** ! 4: ** 3B20S optimizer -- two instruction peephole window ! 5: ** ! 6: ** ! 7: ** This module contains the code that improves two-instruction ! 8: ** sequences. The general scheme is to put those improvements ! 9: ** first which result in removing code, followed by the others. ! 10: ** ! 11: ** In some cases we play around with the live/dead information ! 12: ** to convince the one-instruction window not to throw away ! 13: ** code we need. This is particularly evident when we remove ! 14: ** redundant compares: we want to make sure that the instruction ! 15: ** that calculates the result indicators does not get deleted. ! 16: */ ! 17: ! 18: /* Some general caveats (learned the hard way): ! 19: ** ! 20: ** 1. When instructions get interchanged, we must take care that ! 21: ** we don't alter the condition codes that would have resulted ! 22: ** when executing the instructions in their original order. ! 23: ** 2. We can't move adds to %sp, since we may move them after the ! 24: ** place which refers to the newly allocated space on the stack. ! 25: */ ! 26: ! 27: /* #include "defs" -- optim.h takes care of this */ ! 28: #include "optim.h" ! 29: #include "optutil.h" ! 30: ! 31: extern int sprintf(); ! 32: /* w2opt -- 2-instruction peephole window */ ! 33: ! 34: boolean /* true if changes made */ ! 35: w2opt(pf,pl) ! 36: register NODE * pf; /* first instruction node of window */ ! 37: register NODE * pl; /* second instruction node */ ! 38: { ! 39: int cop1 = pf->op; /* op code number of first inst. */ ! 40: int cop2 = pl->op; /* op code number of second inst. */ ! 41: ! 42: int opn; /* op code number (for istriadic) */ ! 43: char * opst; /* op code string (for istriadic) */ ! 44: ! 45: boolean f; /* temporary boolean used to ! 46: ** distinguish cases below ! 47: */ ! 48: int temp; /* general integer temporary */ ! 49: long templ; /* general long temporary */ ! 50: int src1, dst1; /* sizes of movX source, destination */ ! 51: int src2, dst2; /* sizes of second such movX */ ! 52: /* merge moves back into triadic ! 53: ** ! 54: ** opw3 O1,O2,R ! 55: ** movw R,O3 -> op3 O1,O2,O3 ! 56: ** ! 57: ** if R dead ! 58: ** ! 59: ** We depend on the 1-instruction peephole to break such instructions ! 60: ** apart again if appropriate. ! 61: */ ! 62: ! 63: ! 64: if ( ! 65: istriadic(pf,&opn,&opst) ! 66: && cop2 == MOVW ! 67: && isdead(pl->op1,pl) /* also tests whether reg. */ ! 68: && strcmp(pf->op3,pl->op1) == 0 ! 69: && ! usesreg(pl->op2,pl->op1) /* register not used in destination */ ! 70: ) ! 71: { ! 72: wchange(); /* making a change */ ! 73: pf->op3 = pl->op2; /* copy operand pointer */ ! 74: makedead(pl->op1,pf); /* turn off liveness of R in op3 */ ! 75: if (! isdead(pl->op2,pl)) ! 76: makelive(pl->op2,pf); /* turn on liveness of O3, in case ! 77: ** it's a register ! 78: */ ! 79: lmrgin1(pf,pl,pf); /* preserve line number info */ ! 80: mvlivecc(pl); /* preserve condition code info */ ! 81: DELNODE(pl); /* delete second node */ ! 82: return(true); ! 83: } ! 84: /* Combine two dyadics into a triadic, if possible. ! 85: ** ! 86: ** This improvement is useful on processors for which triadics are ! 87: ** better than dyadics. ! 88: ** ! 89: ** movw O2,O3 ! 90: ** opw2 O1,O3 -> op3 O1,O2,O3 ! 91: ** ! 92: ** if O1 does not use O3 in any way ! 93: */ ! 94: ! 95: #ifdef IMPTRIAD ! 96: #ifdef M32 /* applies only to BELLMAC-32 */ ! 97: ! 98: if ( cop1 == MOVW ! 99: && totriadic(pl, &opn, &opst) /* check whether dyadic can go ! 100: ** to triadic ! 101: */ ! 102: && strcmp(pf->op2, pl->op2) == 0 ! 103: && ! usesvar(pl->op1, pf->op2) ! 104: && ( isiros(pf->op1) || isiros(pl->op1) ) ! 105: && isiros(pf->op2) /* safe from mmio */ ! 106: ) ! 107: { ! 108: wchange(); /* we're changing something */ ! 109: ! 110: /* make changes to second instruction */ ! 111: ! 112: pl->op3 = pl->op2; /* make room for new operand */ ! 113: pl->op2 = pf->op1; /* copy from first inst. */ ! 114: chgop(pl, opn, opst); /* change opcode to triadic */ ! 115: lmrgin2(pf,pl,pl); /* preserve line number info */ ! 116: mvlivecc(pf); /* preserve condition code info */ ! 117: DELNODE(pf); /* delete first inst. */ ! 118: return(true); ! 119: } ! 120: ! 121: #endif /* def M32 */ ! 122: #endif /* IMPTRIAD */ ! 123: /* Remove unnecessary movw's before compares. ! 124: ** ! 125: ** movw O1,R ! 126: ** cmpw O2,R -> cmpw O2,O1 ! 127: ** or ! 128: ** ! 129: ** movw O1,R ! 130: ** cmpw R,O2 -> cmpw O1,O2 ! 131: ** ! 132: ** if R dead after cmpw ! 133: **/ ! 134: ! 135: if ( ! 136: cop1 == MOVW ! 137: && cop2 == CMPW ! 138: && isdead(pf->op2,pl) /* (implicit isreg test, too) */ ! 139: && ( ! 140: ( (f = samereg(pf->op2,pl->op1)) ! 141: && ! usesreg(pl->op2,pl->op1) ! 142: && ( isiros(pf->op1) || isiros(pl->op2) ) ! 143: /* safe from mmio */ ! 144: ) ! 145: || ( samereg(pf->op2,pl->op2) && ! usesreg(pl->op1,pl->op2) ) ! 146: ) ! 147: ) ! 148: { ! 149: wchange(); /* flag changes */ ! 150: if (f) /* true if second case above */ ! 151: pl->op1 = pf->op1; ! 152: else ! 153: pl->op2 = pf->op1; ! 154: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 155: mvlivecc(pf); /* preserve condition code info */ ! 156: DELNODE(pf); /* discard movw */ ! 157: return(true); ! 158: } ! 159: /* Eliminate compares against zero if preceded by instruction that ! 160: ** sets result indicators. Because some 3B20S instructions do not ! 161: ** set all result indicators, we can only discard compares after ! 162: ** those instructions that set all of the relevant ones. w3opt ! 163: ** takes care of those which set a limited range of result indicators, ! 164: ** but which are followed by a suitable conditional jump. ! 165: ** ! 166: ** None of the arithmetic operations set the "unsigned" result indicators, ! 167: ** so we retain compares before any unsigned-conditional jump. ! 168: ** ! 169: ** op O1,O2[,O3] -> op O1,O2[,O3] ! 170: ** cmpX O[2|3],&0 ! 171: ** ! 172: **/ ! 173: ! 174: if ( ! 175: (cop2 == CMPW || cop2 == CMPH || cop2 == CMPB) ! 176: && strcmp(pl->op2,"&0") == 0 ! 177: && strcmp(dst(pf),pl->op1) == 0 ! 178: && (MOVB <= cop1 && cop1 <= ARSW3) ! 179: && stype(cop1) == stype(cop2) ! 180: && (pl->forw->op < JLU || pl->forw->op > JGEU) ! 181: && isiros(pl->op1) /* safe from mmio */ ! 182: ) ! 183: { ! 184: wchange(); /* changing window */ ! 185: lmrgin3(pf,pl,pf); /* preserve line number info */ ! 186: mvlivecc(pl); /* preserve condition code info */ ! 187: DELNODE(pl); /* delete the compare */ ! 188: return(true); /* announce success */ ! 189: } ! 190: /* Eliminate compares against zero if preceding instruction sets condition ! 191: ** codes (special cases). ! 192: ** ! 193: ** movw O1,O2 ! 194: ** cmpw O1,&0 -> movw O1,O2 ! 195: ** ! 196: ** or ! 197: ** call &n,O ! 198: ** cmpw %r0,&0 -> call &n,O ! 199: ** ! 200: ** This last improvement is moderately dangerous. It depends on the ! 201: ** fact that, in C, a function returning a value puts the value in r0 ! 202: ** just before exiting. The return indicators would then be set correctly. ! 203: ** An assembly coder could blow this assumption to pieces. ! 204: ** Once again we have to watch out for unsigned tests following the cmpw, ! 205: ** since a "movw" in the called function would not set the unsigned ! 206: ** result indicators. ! 207: */ ! 208: ! 209: ! 210: if ( ! 211: cop2 == CMPW ! 212: && strcmp(pl->op2,"&0") == 0 ! 213: && ( ! 214: ( ! 215: cop1 == MOVW ! 216: && strcmp(pf->op1,pl->op1) == 0 ! 217: && ! usesvar(pf->op1,pf->op2) ! 218: /* O1 cannot use O2 in any way */ ! 219: && isiros(pf->op1) /* safe for mmio */ ! 220: ) ! 221: #ifdef CALLCMPW /* make this a selectable option */ ! 222: || ! 223: ( ! 224: cop1 == CALL ! 225: && strcmp(pl->op1,"%r0") == 0 ! 226: ) ! 227: #endif /* def CALLCMPW */ ! 228: ) ! 229: && ! (JLU <= pl->forw->op && pl->forw->op <= JGEU) ! 230: /* disallow unsigned jump after cmpw */ ! 231: ) ! 232: { ! 233: wchange(); ! 234: lmrgin3(pf,pl,pf); /* preserve line number info */ ! 235: mvlivecc(pl); /* preserve condition code info */ ! 236: DELNODE(pl); ! 237: return(true); ! 238: } ! 239: /* One of the assumptions about eliminating "cmpw" after a "call" ! 240: ** is that all functions set result indicators upon returning a value. ! 241: ** If the value is set by a bit-field extract, this is not so. ! 242: ** Therefore, we must insert an extra "cmpw" to compensate: ! 243: ** ! 244: ** extzv O1,O2,O3,%r0 --> extzv O1,O2,O3,%r0 ! 245: ** --> cmpw %r0,&0 ! 246: ** ret --> ret ! 247: */ ! 248: ! 249: #ifdef CALLCMPW /* only if this is enabled */ ! 250: ! 251: if ( ! 252: cop1 == EXTZV ! 253: && cop2 == RET ! 254: && strcmp(pf->op4,"%r0") == 0 ! 255: ) ! 256: { ! 257: NODE * newnode = insert(pf); /* create new node after extzv */ ! 258: ! 259: wchange(); /* making a change */ ! 260: chgop(newnode,CMPW,"cmpw"); /* set op code number and string */ ! 261: newnode->op1 = "%r0"; /* set up instruction */ ! 262: newnode->op2 = "&0"; ! 263: newnode->nlive = pf->nlive; /* save live/dead as predecessor */ ! 264: pf->nlive &= ~CONCODES; /* killing condition codes */ ! 265: return(true); /* made a change */ ! 266: } ! 267: #endif /* def CALLCMPW */ ! 268: /* This next set of improvements deals with pairs of move's. */ ! 269: ! 270: /* case 1: redundant movw ! 271: ** ! 272: ** movw O1,O2 ! 273: ** movw O2,O1 -> movw O1,O2 ! 274: ** or ! 275: ** ! 276: ** movw O1,O2 ! 277: ** movw O1,O2 -> movw O1,O2 (second one) ! 278: ** ! 279: ** Note that, for the second improvement, O2 cannot be used by O1. ! 280: */ ! 281: if (cop1 == MOVW && cop2 == MOVW) ! 282: { ! 283: if ( strcmp(pf->op1,pl->op2) == 0 /* first case */ ! 284: && strcmp(pf->op2,pl->op1) == 0 ! 285: && isiros(pf->op1) ! 286: && isiros(pf->op2) /* safe from mmio */ ! 287: ) ! 288: { ! 289: wchange(); /* change window */ ! 290: lmrgin3(pf,pl,pf); /* preserve line number info */ ! 291: mvlivecc(pl); /* perserve conditions codes live info */ ! 292: DELNODE(pl); /* delete second inst. */ ! 293: return(true); ! 294: } ! 295: ! 296: if ( strcmp(pf->op1,pl->op1) == 0 /* second case */ ! 297: && strcmp(pf->op2,pl->op2) == 0 ! 298: && ! usesvar(pl->op1,pf->op2) ! 299: && isiros(pf->op1) ! 300: && isiros(pf->op2) /* safe from mmio */ ! 301: ) ! 302: { ! 303: wchange(); ! 304: lmrgin3(pf,pl,pl); /* preserve line number info */ ! 305: mvlivecc(pf); /* perserve conditions codes live info */ ! 306: DELNODE(pf); /* delete first inst. */ ! 307: return(true); ! 308: } ! 309: } ! 310: /* Case 2: arbitrary size moves with intermediate register ! 311: ** ! 312: ** The idea here is to collapse pairs of moves, possibly with different ! 313: ** sized operands, into one correct move. We assume that a register ! 314: ** is used unnecessarily in the operation. That is, we are looking at ! 315: ** ! 316: ** movX O1,R ! 317: ** movY R,O2 -> movZ O1,O2 ! 318: ** ! 319: ** if R dead after movY and O2 doesn't use R ! 320: ** or O2 is same register as R ! 321: ** ! 322: ** where X, Y, and Z are things like "twb" (as in, "movtwb"), "h", ! 323: ** and "bbw". The trick is to choose the correct move based on the ! 324: ** sizes of the operands. There are 81 (gasp!) combinations of four ! 325: ** operands, with three choices per operand. The code below is ! 326: ** correct, but misses one obscure case: ! 327: ** ! 328: ** movtbh O1,R ! 329: ** movtwh R,O2 -> movh O1,O2 ! 330: */ ! 331: ! 332: if ( ! 333: ismove(pf,&src1,&dst1) /* test, get source, dest. sizes */ ! 334: && ismove(pl,&src2,&dst2) ! 335: && isreg(pf->op2) ! 336: && samereg(pf->op2, pl->op1) ! 337: && ( ! 338: ( isdead(pl->op1,pl) && ! usesreg(pl->op2,pl->op1) ) ! 339: || samereg(pl->op1,pl->op2) ! 340: ) ! 341: ) ! 342: /* fall through to sub-cases */ ! 343: { ! 344: /* sub-case 1: ! 345: ** Sizes of movX source and movY destination are equal. Source of ! 346: ** movX no larger than destination, source of movY no smaller than its ! 347: ** destination. ("Size" here refers to number of bytes in effective ! 348: ** operand.) Example: ! 349: ** ! 350: ** movbbw O1,R s = 1; d = 4 ! 351: ** movthb R,O2 -> movb O1,O2 s = 2; d = 1 ! 352: ** ! 353: ** (More common case...) ! 354: ** ! 355: ** movw O1,R s = 4; d = 4 ! 356: ** movw R,O2 -> movw O1,O2 s = 4; d = 4 ! 357: */ ! 358: ! 359: if ( ! 360: src1 == dst2 ! 361: && src1 <= dst1 ! 362: && src2 >= dst2 ! 363: ) ! 364: { ! 365: wchange(); ! 366: pl->op1 = pf->op1; /* copy down first operand */ ! 367: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 368: mvlivecc(pf); /* perserve conditions codes live info */ ! 369: DELNODE(pf); /* delete first node */ ! 370: switch (src1) /* choose correct new instruction */ ! 371: { ! 372: case 1: /* byte to byte */ ! 373: chgop(pl,MOVB,"movb"); break; ! 374: ! 375: case 2: /* halfword to halfword */ ! 376: chgop(pl,MOVH,"movh"); break; ! 377: ! 378: case 4: /* word to word */ ! 379: chgop(pl,MOVW,"movw"); break; ! 380: } ! 381: return(true); ! 382: } ! 383: /* sub-case 2: ! 384: ** Both sources are the same size, and either the destinations are ! 385: ** the same size or destination of movX larger than source. ! 386: ** Examples: ! 387: ** ! 388: ** movzbw O1,R s = 1; d = 4 ! 389: ** movb R,O2 -> movb O1,O2 s = 1; d = 1 ! 390: ** ! 391: ** movtwh O1,R s = 4; d = 2 ! 392: ** movtwh R,O2 -> movtwh O1,O2 s = 4; d = 2 ! 393: */ ! 394: ! 395: if ( ! 396: src1 == src2 /* source sizes equal */ ! 397: && ( ! 398: src1 <= dst1 ! 399: || dst1 == dst2 ! 400: ) ! 401: ) ! 402: { ! 403: wchange(); /* making a change */ ! 404: pl->op1 = pf->op1; /* copy operand */ ! 405: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 406: mvlivecc(pf); /* perserve conditions codes live info */ ! 407: DELNODE(pf); /* delete first node */ ! 408: return(true); ! 409: } ! 410: /* sub-case 3: ! 411: ** Destination 1, source 2, and destination 2 are all the same size. ! 412: ** Example: ! 413: ** ! 414: ** movzhw O1,R s = 2; d = 4 ! 415: ** movw R,O2 -> movzhw O1,O2 s = 4; d = 4 ! 416: */ ! 417: ! 418: if ( ! 419: dst1 == src2 ! 420: && src2 == dst2 ! 421: ) ! 422: { ! 423: wchange(); ! 424: pf->op2 = pl->op2; /* copy up second operand */ ! 425: makelive(pf->op2,pf); /* make sure first inst. won't now ! 426: ** go away ! 427: */ ! 428: lmrgin1(pf,pl,pf); /* preserve line number info */ ! 429: mvlivecc(pl); /* perserve conditions codes live info */ ! 430: DELNODE(pl); /* delete second node */ ! 431: return(true); ! 432: } ! 433: } /* end move-move merging */ ! 434: /* Merge register move into indirect reference. ! 435: ** ! 436: ** The purpose of this improvement is to eliminate a movw if it is ! 437: ** used to load a register which is then used exclusively for an ! 438: ** indirect reference. Examples: ! 439: ** ! 440: ** movw O1,R ! 441: ** op2 0(R),O2 -> op2 *O1,O2 ! 442: ** ! 443: ** if R dead after op2 ! 444: ** if R not used in O2, except as 0(R) ! 445: ** ! 446: ** We use utility routine 'doindirect' to do this in a general way ! 447: ** for, in fact, any instruction and not just op2. ! 448: */ ! 449: ! 450: if ( cop1 == MOVW && isreg(pf->op2)) ! 451: { ! 452: /* use utility routine to check for feasibility. Replace ! 453: ** 0(R) with suitable indirection from O1 ! 454: */ ! 455: ! 456: if (doindirect(pl,pf->op2,pf->op1)) ! 457: { ! 458: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 459: mvlivecc(pf); /* perserve conditions codes live info */ ! 460: DELNODE(pf); /* success. delete first node */ ! 461: return(true); ! 462: } ! 463: } ! 464: /* Address arithmetic: ! 465: ** ! 466: ** This transformation merges instructions of the form ! 467: ** ! 468: ** addw2 &m,R ! 469: ** ! 470: ** with operands of the form ! 471: ** ! 472: ** n(R) ! 473: ** ! 474: ** yielding a replacement operand of the form ! 475: ** ! 476: ** m+n(R) ! 477: ** ! 478: ** We do this in a general way, transforming all of the operands in the ! 479: ** instruction that follows the addw2 (subw2) that can be transformed. ! 480: ** The transformation cannot be performed if the second instruction uses ! 481: ** R in any other way. Note that dyadic instructions like ! 482: ** ! 483: ** addw2 a,R ! 484: ** ! 485: ** use R implicitly: a + R -> R. ! 486: ** However, for moves and triadics, the last operand is only a destination, ! 487: ** not an operand, so having R as the last operand does not impede our ! 488: ** transformation. ! 489: ** ! 490: ** In general we don't delete the addw2 (subw2) node but simply move it ! 491: ** past its successor after transforming the operands. At first this ! 492: ** would seem to be a waste of time. However, if R is dead after the ! 493: ** second instruction, we can discard the addw2 (subw2). Thus we ! 494: ** can propagate the addw2 (subw2) through a series of offsets: ! 495: ** ! 496: ** addw2 &4,%r0 ! 497: ** movw 0(%r0),0(%r1) ! 498: ** movw 4(%r0),4(%r1) ! 499: ** ! 500: ** | ! 501: ** V ! 502: ** movw 4(%r0),0(%r1) ! 503: ** addw2 &4,%r0 ! 504: ** movw 4(%r0),4(%r1) ! 505: ** ! 506: ** | ! 507: ** V ! 508: ** movw 4(%r0),0(%r1) ! 509: ** movw 8(%r0),4(%r1) ! 510: ** addw2 &4,%r0 ! 511: ** ! 512: ** and the addw2 could be discarded if %r0 is dead now. Notice that no ! 513: ** particular performance penalty is incurred by doing this transformation ! 514: ** if we fail to discard the addw2 (subw2), but we will win if we can ! 515: ** throw it out. NOTE, however, that we cannot move the add/sub if ! 516: ** there is a conditional branch or compare following the second instruction, ! 517: ** since we will provide different condition codes from the original sequence. ! 518: */ ! 519: /* Begin address arithmetic transformation */ ! 520: ! 521: if ( ! 522: (cop1 == ADDW2 || cop1 == SUBW2) ! 523: && isnumlit(pf->op1) ! 524: && isreg(pf->op2) ! 525: && strcmp(pf->op2,"%sp") != 0 /* not stack pointer */ ! 526: && ! isbr(pl) /* don't move add/sub past branch! */ ! 527: ) ! 528: { ! 529: char * reg = pf->op2; /* point at register name (R) */ ! 530: int destreg = 0; /* number of destination operand, ! 531: ** zero if none ! 532: */ ! 533: int idxmask = 0; /* bit mask of operands to change */ ! 534: long idxval[MAXOPS+1]; /* current indices for each (indexed ! 535: ** 1 to MAXOPS, not 0 to MAXOPS-1) ! 536: */ ! 537: int i; /* loop index */ ! 538: long m = atol(pf->op1+1); /* literal in addw2 &m,R */ ! 539: NODE * nextinst = pl->forw; /* pointer to inst. after window */ ! 540: ! 541: ! 542: /* Check for conditional branch or compare following second instruction in ! 543: ** situation where we can't delete the add/sub. Don't do improvement ! 544: ** if we find one. ! 545: */ ! 546: ! 547: f = ( isdead(reg,pl) || strcmp(dst(pl),reg) == 0 ); ! 548: if ( (! f) && ( ! isdeadcc(pl) || iscompare(nextinst)) ) ! 549: goto noindex; /* won't delete and have cond. br. */ ! 550: ! 551: if (cop1 == SUBW2) ! 552: m = -m; /* negate literal if subtract */ ! 553: ! 554: /* Determine in which instructions we allow ourselves to see R as an ! 555: ** operand (destination) and remember which operand number it is. ! 556: */ ! 557: ! 558: if (istriadic(pl,&opn,&opst)) ! 559: destreg = 3; /* in triadics, is third operand */ ! 560: else if (ismove(pl,&src1,&dst1)) ! 561: destreg = 2; /* in moves, is second */ ! 562: /* in all others, not allowed */ ! 563: ! 564: /* Now we loop through all possible operands in an instruction, looking ! 565: ** for indexed uses of R (i.e., n(R) ). If we find, instead, a use of ! 566: ** R which is not in the "destreg" position, we cannot do the transform. ! 567: */ ! 568: ! 569: for (i = MAXOPS; i > 0; i--) ! 570: { ! 571: char * t = pl->ops[i]; /* point at new operand */ ! 572: ! 573: if (t == NULL) ! 574: continue; /* disregard null operands */ ! 575: ! 576: if (isindex(t,reg)) /* this is what we seek */ ! 577: { ! 578: idxmask |= (1<<i); /* remember where we saw it */ ! 579: if(*t == '*') ! 580: t++; ! 581: idxval[i] = atol(t); /* remember current index value ! 582: ** (i.e., n from n(R) ! 583: */ ! 584: } ! 585: else if (samereg(t,reg) && i != destreg) ! 586: goto noindex; /* instruction uses register in ! 587: ** non-transformable way ! 588: */ ! 589: } ! 590: /* We now know there have been only valid uses of R in the second ! 591: ** instruction. If there are any uses of R at all, transform the ! 592: ** second instruction. ! 593: */ ! 594: ! 595: /* Define maximum size of new operand. */ ! 596: ! 597: #define NEWSIZE (11+1+3+1+1) /* for "ddddddddddd(%rn)\0" */ ! 598: ! 599: if (idxmask == 0) ! 600: goto noindex; /* nothing to do if no uses of R */ ! 601: ! 602: wchange(); /* we may just move/delete the add */ ! 603: for (i = MAXOPS; i>0; i--) /* find operands to alter */ ! 604: { ! 605: char * t; ! 606: if ((idxmask & (1<<i)) == 0) ! 607: continue; /* ignore this operand: not n(R) */ ! 608: ! 609: t = pl->ops[i]; ! 610: pl->ops[i] = getspace(NEWSIZE); ! 611: /* get space for new operand */ ! 612: if(*t == '*') ! 613: (void) sprintf(pl->ops[i],"*%d(%s)",(int)(m+idxval[i]),reg); ! 614: else ! 615: (void) sprintf(pl->ops[i],"%d(%s)",(int)(m+idxval[i]),reg); ! 616: /* build new operand string */ ! 617: } ! 618: ! 619: /* Discard add/sub if R is dead after second instruction, or if that ! 620: ** instruction set a new value. ! 621: */ ! 622: ! 623: if (f) /* conditions permit deleting */ ! 624: { ! 625: ldelin(pf); /* preserve line number info */ ! 626: mvlivecc(pf); /* perserve conditions codes live info */ ! 627: DELNODE(pf); } /* delete add/sub */ ! 628: else { ! 629: lexchin(pf,pl); /* preserve line number info */ ! 630: exchange(pf); /* otherwise exchange add/sub and ! 631: ** second inst. ! 632: */ ! 633: swplivecc(pf,pl); /* swaping the condition codes live/dead info */ ! 634: } ! 635: return(true); ! 636: } ! 637: noindex: ! 638: /* Address arithmetic, case 2: ! 639: ** ! 640: ** addw3 &n,R1,R2 ! 641: ** pushw R2 -> pushaw n(R1) ! 642: ** or ! 643: ** ! 644: ** subw3 &n,R1,R2 ! 645: ** pushw R2 -> pushaw -n(R1) ! 646: ** ! 647: ** if R2 dead after pushw ! 648: ** ! 649: ** (Sigh! These aren't safe in general, but for the specific cases ! 650: ** where R2 is sp, fp, or ap, we can be sure we're pushing an ! 651: ** address and not the result of an integer computation. pushaw ! 652: ** doesn't do 32 bit arithmetic.) ! 653: */ ! 654: ! 655: if ( ! 656: (cop1 == ADDW3 || cop1 == SUBW3) ! 657: && cop2 == PUSHW ! 658: && *pf->op1 == '&' ! 659: && isreg(pf->op2) ! 660: && ( ! 661: strcmp(pf->op2,"%fp") == 0 ! 662: || strcmp(pf->op2,"%ap") == 0 ! 663: || strcmp(pf->op2,"%sp") == 0 ! 664: ) ! 665: && isreg(pf->op3) ! 666: && samereg(pf->op3,pl->op1) ! 667: && isdead(pf->op3,pl) ! 668: ) ! 669: { ! 670: /* allocate space for new operand: room for constant, less room ! 671: ** for &, plus room for possible sign, plus room for parens and ! 672: ** register declaration, plus room for null. ! 673: */ ! 674: char * ts = getspace( ! 675: strlen(pf->op1)-1+1 /* less &, plus sign */ ! 676: + 1 + strlen(pf->op2) + 1 /* ( reg ) */ ! 677: + 1 /* null */ ! 678: ); ! 679: ! 680: char * operand = pf->op1 + 1; /* point past & at operand */ ! 681: ! 682: int msign = 0; /* non-zero if minus sign required */ ! 683: ! 684: wchange(); ! 685: ! 686: /* create new operand */ ! 687: ! 688: if (*operand == '-') ! 689: { ! 690: msign = 1; /* - sign required */ ! 691: operand++; /* skip past - in operand */ ! 692: } ! 693: if (cop1 == SUBW3) /* invert sign if op was subtract */ ! 694: msign = 1-msign; ! 695: ! 696: (void) sprintf(ts,"%s%s(%s)", ! 697: (msign != 0 ? "-" : ""), ! 698: operand, /* string for constant, no & */ ! 699: pf->op2); ! 700: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 701: mvlivecc(pf); /* perserve conditions codes live info */ ! 702: DELNODE(pf); /* discard add/sub */ ! 703: chgop(pl,PUSHAW,"pushaw"); /* change op code */ ! 704: pl->op1 = ts; /* change operand */ ! 705: return(true); ! 706: } ! 707: /* Collapse bit test/branch combination ! 708: ** ! 709: ** bitw &2^n,O ! 710: ** je to -> jbc &n,O,to ! 711: ** ! 712: ** bitw &2^n,O ! 713: ** jne to -> jbs &n,O,to ! 714: ** ! 715: ** jz is a synonym for je. ! 716: ** jnz is a synonym for jne. ! 717: */ ! 718: ! 719: /* ----------- FLASH ------------- ! 720: ** It turns out that these "improvements" aren't: they are slower than ! 721: ** the sequences they would replace. If someday that condition changes, ! 722: ** remove the conditionals. ! 723: */ ! 724: ! 725: #ifdef FASTJBCJBS ! 726: ! 727: if ( ! 728: cop1 == BITW ! 729: && ( ! 730: (f = (cop2 == JE)) ! 731: || (f = (cop2 == JZ)) ! 732: || cop2 == JNE ! 733: || cop2 == JNZ ! 734: ) ! 735: && (temp = getbit(pf->op1)) >= 0 ! 736: ) ! 737: { ! 738: wchange(); ! 739: pl->op3 = pl->op1; /* shift operands */ ! 740: pl->op2 = pf->op2; ! 741: /* build new operand: &n */ ! 742: pl->op1 = getspace(1+2+1); /* space for "&dd\0" */ ! 743: (void) sprintf(pl->op1,"&%d",temp); ! 744: if (f) /* f true for je/jz */ ! 745: chgop(pl,JBC,"jbc"); ! 746: else ! 747: chgop(pl,JBS,"jbs"); ! 748: ! 749: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 750: mvlivecc(pf); /* perserve conditions codes live info */ ! 751: DELNODE(pf); /* discard bitw */ ! 752: return(true); ! 753: } ! 754: ! 755: #endif /* def FASTJBCJBS */ ! 756: ! 757: #ifdef UCODE50 /* with 5.0 microcode (3B20) only */ ! 758: ! 759: /* Increment and test improvement ! 760: ** ! 761: ** addw2 &n,R ! 762: ** cmpw R,O -> inctst R,&n-1,O ! 763: ** ! 764: ** if O doesn't use R (this may be unnecessarily restrictive, ! 765: ** depending on when the effective address of O is calculated, ! 766: ** but it would be a strange use, anyway) ! 767: ** ! 768: */ ! 769: ! 770: if ( ! 771: cop1 == ADDW2 ! 772: && cop2 == CMPW ! 773: && isreg(pf->op2) ! 774: && samereg(pl->op1,pf->op2) ! 775: && isnumlit(pf->op1) ! 776: && 1 <= (templ = atol(pf->op1+1)) && templ <= 16 ! 777: /* can't use isnib here: allow for ! 778: ** 16, disallow 0 ! 779: */ ! 780: && ! usesreg(pl->op2,pf->op2) ! 781: ) ! 782: { ! 783: wchange(); /* making a change */ ! 784: chgop(pl,INCTST,"inctst"); /* new op code number, string */ ! 785: pl->op3 = pl->op2; /* shift operand */ ! 786: pl->op2 = getspace(1+2+1); /* for "&dd\0" */ ! 787: (void) sprintf(pl->op2,"&%d",(int)(templ-1)); ! 788: /* literal in inctmp is 1 less */ ! 789: lmrgin3(pf,pl,pl); /* preserve line number info */ ! 790: DELNODE( pf ); /* delete ADDW2 */ ! 791: return(true); ! 792: } ! 793: #endif /* def UCODE50 */ ! 794: ! 795: #ifdef UCODE50 /* if 5.0 microcode (3B20) only */ ! 796: ! 797: /* Use increment/decrement pointer ! 798: ** ! 799: ** llsw2 &1,R1 ! 800: ** addw2 R1,R2 -> incpth R2,R1 ! 801: ** ! 802: ** llsw2 &2,R1 ! 803: ** addw2 R1,R2 -> incptw R2,R1 ! 804: ** ! 805: ** llsw2 &1,R1 ! 806: ** subw2 R1,R2 -> decpth R2,R1 ! 807: ** ! 808: ** llsw2 &2,R1 ! 809: ** subw2 R1,R2 -> decptw R2,R1 ! 810: ** ! 811: ** if R1 dead after addw2/subw2 ! 812: ** if R1 and R2 different ! 813: */ ! 814: ! 815: if ( ! 816: cop1 == LLSW2 ! 817: && (cop2 == ADDW2 || cop2 == SUBW2) ! 818: && isreg(pl->op1) ! 819: && isreg(pl->op2) ! 820: && isdead(pf->op2,pl) ! 821: && samereg(pl->op1,pf->op2) ! 822: && ! samereg(pl->op1,pl->op2) ! 823: && ( ! 824: (f = (strcmp(pf->op1,"&2") == 0)) ! 825: || strcmp(pf->op1,"&1") == 0 ! 826: ) ! 827: ) ! 828: { ! 829: wchange(); ! 830: pl->op1 = pl->op2; /* switch operands */ ! 831: pl->op2 = pf->op2; ! 832: ! 833: /* select new op code for merged instruction */ ! 834: ! 835: if (cop2 == ADDW2) /* do incpt cases */ ! 836: { ! 837: if (f) /* true for word incr. */ ! 838: chgop(pl,INCPTW,"incptw"); ! 839: else ! 840: chgop(pl,INCPTH,"incpth"); ! 841: } ! 842: else /* decpt case */ ! 843: { ! 844: if (f) /* true for word decr. */ ! 845: chgop(pl,DECPTW,"decptw"); ! 846: else ! 847: chgop(pl,DECPTH,"decpth"); ! 848: } ! 849: ! 850: lmrgin1(pf,pl,pl); /* preserve line number info */ ! 851: DELNODE( pf ); /* delete shift */ ! 852: return(true); ! 853: } ! 854: #endif /* def UCODE50 */ ! 855: /******************************************************************** ! 856: ** ! 857: ** Begin improvements that alter code, rather than deleting it. ! 858: ** ! 859: *********************************************************************** ! 860: */ ! 861: ! 862: /* Use register in pushw if possible ! 863: ** ! 864: ** movw R,O -> movw R,O ! 865: ** pushw O -> pushw R ! 866: ** ! 867: ** if O is not a register. ! 868: */ ! 869: ! 870: if ( ! 871: cop1 == MOVW ! 872: && cop2 == PUSHW ! 873: && strcmp(pf->op2,pl->op1) == 0 ! 874: && isreg(pf->op1) ! 875: && !isreg(pl->op1) ! 876: && isiros(pf->op2) /* safe from mmio */ ! 877: ) ! 878: { ! 879: wchange(); ! 880: makelive((pl->op1 = pf->op1),pl); /* propagate liveness of R */ ! 881: return(true); ! 882: } ! 883: /* Use register if possible in op2 or op3 ! 884: ** ! 885: ** movw R,O1 -> movw R,O1 ! 886: ** op2 O1,O2 -> op2 R,O2 ! 887: ** ! 888: ** if O1 not a register ! 889: ** or ! 890: ** ! 891: ** movw R,O1 -> movw R,O1 ! 892: ** op3 O1,O2,O3 -> op3 R,O2,O3 ! 893: ** ! 894: ** if O1 is not a register ! 895: ** or ! 896: ** ! 897: ** movw R,O2 -> movw R,O2 ! 898: ** op3 O1,O2,O3 -> op3 O1,R,O3 ! 899: ** ! 900: ** if O2 is not a register ! 901: */ ! 902: ! 903: if ( ! 904: cop1 == MOVW ! 905: && isreg(pf->op1) ! 906: && ! isreg(pf->op2) ! 907: ) ! 908: { ! 909: if ( ! 910: ( ! 911: isdyadic(pl) ! 912: && (f = (strcmp(pf->op2,pl->op1) == 0)) ! 913: && (CMPW <= cop2 && cop2 <= UMODW3) ! 914: && ( ismove( pl, &src2, &dst2 ) && src2 == stype(cop1) || ! 915: !ismove( pl, &src2, &dst2 ) && stype(cop2) == stype(cop1) ! 916: ) ! 917: && isiros(pf->op2) /* safe from mmio */ ! 918: ) ! 919: || ! 920: ( ! 921: istriadic(pl,&opn,&opst) ! 922: && ( ! 923: (f = (strcmp(pf->op2,pl->op1) == 0)) ! 924: || strcmp(pf->op2,pl->op2) == 0 ! 925: ) ! 926: && isiros(pf->op2) /* safe from mmio */ ! 927: ) ! 928: ) ! 929: { ! 930: wchange(); ! 931: if (f) /* f true if we modify first operand */ ! 932: pl->op1 = pf->op1; ! 933: else ! 934: pl->op2 = pf->op1; ! 935: makelive(pf->op2,pl); /* propagate liveness into op2/3 */ ! 936: return(true); ! 937: } ! 938: } ! 939: /* This transformation propagates a register use back into a triadic. ! 940: ** ! 941: ** op3 O1,O2,O3 -> op3 O1,O2,R ! 942: ** movw O3,R -> movw R,O3 (possibly deleted) ! 943: ** ! 944: ** if R not used by O3 ! 945: ** ! 946: ** If O3 is a register that is dead after movw, we can change ! 947: ** this to just the op3. If O3 is a register that is not dead, ! 948: ** we can't do the transformation, because it will oscillate. ! 949: */ ! 950: ! 951: if ( ! 952: istriadic(pf,&opn,&opst) ! 953: && cop2 == MOVW ! 954: && isreg(pl->op2) ! 955: && strcmp(pf->op3,pl->op1) == 0 ! 956: && ! usesreg(pf->op3,pl->op2) ! 957: && ( /* avoid oscillation case */ ! 958: ! ( f = isreg(pl->op1) ) ! 959: || isdead(pl->op1,pl) ! 960: ) ! 961: && isiros(pf->op3) /* safe from mmio */ ! 962: ) ! 963: { ! 964: wchange(); ! 965: ! 966: pf->op3 = pl->op2; ! 967: makelive(pf->op3,pf); /* make R live after op3 */ ! 968: ! 969: lmrgin2(pf,pl,pf); /* preserve line number info */ ! 970: /* lmrgin2 works here ! 971: because it sets the uniqid of the ! 972: non-result (i.e. pl) to IDVAL */ ! 973: if (f) /* true if O3 was a register */ ! 974: { mvlivecc(pl); /* preserve conditions codes live info */ ! 975: DELNODE(pl); } ! 976: else /* O3 not a register */ ! 977: { ! 978: pl->op2 = pl->op1; ! 979: pl->op1 = pf->op3; /* pf->op3 contains R from first move */ ! 980: } ! 981: return(true); ! 982: } ! 983: /* Use register in second of two moves, if possible. ! 984: ** ! 985: ** This improvement attempts to propagate a register use, if possible. ! 986: ** We do this in a general way for pairs of moves. Here's the case ! 987: ** we're considering: ! 988: ** ! 989: ** movX R,O1 -> movX R,O1 ! 990: ** movY O1,O2 -> movY R,O2 ! 991: ** ! 992: ** We don't bother with this improvement if O1 is already a register. ! 993: ** ! 994: ** We can make the identical improvement if "R" is really a nibble. ! 995: ** ! 996: ** We can do this when (using earlier terminology) the destination ! 997: ** of movX and the source of movY are the same size. There are three ! 998: ** sub-cases: ! 999: ** ! 1000: ** 1. destination1 == source2 == destination2. ! 1001: ** 2. source1 >= destination1 == source2 . ! 1002: ** (remember, source1 is register or nibble) ! 1003: ** 3. source1 >= destination2. ! 1004: ** ! 1005: ** Examples: ! 1006: ** ! 1007: ** movbbh R,O1 s = 1; d = 2 ! 1008: ** movthb O1,O2 -> movb R,O2 s = 2; d = 1 ! 1009: ** ! 1010: ** movbbh R,O1 s = 1; d = 2 ! 1011: ** movh O1,O2 -> movbbh R,O2 s = 2; d = 2 ! 1012: ** ! 1013: */ ! 1014: ! 1015: if ( ! 1016: ismove(pf, &src1, &dst1) ! 1017: && ismove(pl, &src2, &dst2) ! 1018: && src2 == dst1 ! 1019: && ( isreg(pf->op1) || isnib(pf->op1) ) /* R can be reg. or nibble */ ! 1020: && ! isreg(pf->op2) /* this is "don't bother" test */ ! 1021: && strcmp(pf->op2, pl->op1) == 0 ! 1022: && isiros(pf->op2) /* safe from mmio */ ! 1023: ) ! 1024: /* fall through to sub-cases */ ! 1025: { ! 1026: ! 1027: /* sub-case 1: source2 and destination2 same */ ! 1028: ! 1029: if (src2 == dst2) ! 1030: { ! 1031: wchange(); ! 1032: chgop(pl,pf->op,pf->opcode); /* copy instruction of first node */ ! 1033: pl->op1 = pf->op1; /* propagate register/nibble use */ ! 1034: makelive(pl->op1,pl); /* mark it as live */ ! 1035: return(true); ! 1036: } ! 1037: ! 1038: /* sub-case 2: source1 >= destination1 */ ! 1039: ! 1040: if (src1 >= dst1) ! 1041: { ! 1042: wchange(); ! 1043: pl->op1 = pf->op1; /* propagate register/nibble */ ! 1044: makelive(pl->op1,pl); /* make register live after pl */ ! 1045: return(true); ! 1046: } ! 1047: ! 1048: /* sub-case 3: source1 >= destination2 */ ! 1049: ! 1050: if (src1 >= dst2) ! 1051: { ! 1052: wchange(); ! 1053: switch (dst2) /* choose correct new instruction */ ! 1054: { ! 1055: case 1: ! 1056: chgop(pl,MOVB,"movb"); break; ! 1057: case 2: ! 1058: chgop(pl,MOVH,"movh"); break; ! 1059: case 4: ! 1060: chgop(pl,MOVW,"movw"); break; ! 1061: } ! 1062: pl->op1 = pf->op1; /* propagate register/nibble use */ ! 1063: makelive(pl->op1,pl); /* make this register live here */ ! 1064: return(true); ! 1065: } ! 1066: } ! 1067: /* More paired move improvements ! 1068: ** ! 1069: ** This improvement propagates the use of a register, if possible from ! 1070: ** one move to a following one. It also has the potential of killing ! 1071: ** off the liveness of a register. Example: ! 1072: ** ! 1073: ** movX O,R1 -> movX O,R1 ! 1074: ** movY O,R2 -> movY R1,R2 ! 1075: ** ! 1076: ** Since we are trying to kill registers off early, these special ! 1077: ** conditions apply if O is a register: ! 1078: ** 1) O must be dead after movY or be the same as R2. ! 1079: ** 2) R1 must be live after movY. ! 1080: ** If O is a register, it must be live after movY or be the same ! 1081: ** register as R2. ! 1082: ** O may not use R1. ! 1083: ** ! 1084: ** The size of source1 must be the same as source2, ! 1085: ** and destination1 must be at least as large as source2. ! 1086: */ ! 1087: ! 1088: if ( ! 1089: ismove(pf,&src1,&src2) ! 1090: && ismove(pl,&src2,&src2) ! 1091: && strcmp(pf->op1,pl->op1) == 0 ! 1092: && isreg(pf->op2) ! 1093: && isreg(pl->op2) ! 1094: && ! usesreg(pl->op1,pf->op2) ! 1095: && src1 == src2 ! 1096: && src2 <= dst1 ! 1097: && ( ! 1098: ! isreg(pl->op1) /* O not a register */ ! 1099: || ( ! 1100: ( ! 1101: samereg(pl->op1,pl->op2)/* O same as R2 */ ! 1102: || isdead(pl->op1,pl) /* O dead after movY */ ! 1103: ) ! 1104: ! 1105: && ! isdead(pf->op2,pl) /* R1 live after movY */ ! 1106: ) ! 1107: ) ! 1108: && isiros(pf->op1) /* safe from mmio */ ! 1109: ) ! 1110: { ! 1111: wchange(); ! 1112: makelive(pl->op1 = pf->op2,pf); /* copy operand, make register live ! 1113: ** after movX ! 1114: */ ! 1115: return(true); ! 1116: } ! 1117: /* Re-order pairs of instructions to make better use of registers. ! 1118: ** ! 1119: ** This improvement reverses a dyadic and a movw to make better use of ! 1120: ** registers. The canonical sequence is: ! 1121: ** ! 1122: ** op2 O1,O2 -> movw O1,R ! 1123: ** movw O1,R -> op2 R,O2 ! 1124: ** ! 1125: ** if O1 and O2 don't use R ! 1126: ** if R live after movw ! 1127: ** if instruction following movw is not a conditional branch ! 1128: ** (since we're changing the instruction that sets codes) ! 1129: ** ! 1130: ** op2 can also be CMPW ! 1131: */ ! 1132: ! 1133: if ( ! 1134: ( cop1 == CMPW ! 1135: || ( isdyadic(pf) ! 1136: && ! ismove(pf,&src1,&dst1) ! 1137: ) ! 1138: ) ! 1139: /* since moves are handled elsewhere ! 1140: ** and this would tend to undo them ! 1141: */ ! 1142: && cop2 == MOVW ! 1143: && strcmp(pf->op1,pl->op1) == 0 ! 1144: && isreg(pl->op2) ! 1145: && ! isdead(pl->op2,pl) ! 1146: && ! usesreg(pf->op1,pl->op2) ! 1147: && ! usesreg(pf->op2,pl->op2) ! 1148: && ! usesvar(pf->op1,pf->op2) /* O1 cannot use O2 in any way */ ! 1149: && isdeadcc( pl ) ! 1150: && isiros(pf->op1) /* safe from mmio */ ! 1151: ) ! 1152: { ! 1153: wchange(); ! 1154: pf->op1 = pl->op2; /* copy operand first */ ! 1155: lexchin(pf,pl); /* preserve line number info */ ! 1156: exchange(pf); /* switch the two instructions */ ! 1157: swplivecc(pf,pl); /* switch the live/dead info on condition codes */ ! 1158: makelive(pl->op2,pf); /* show register as live after op2 */ ! 1159: return(true); ! 1160: } ! 1161: /* Similar to the above, this transformation reverses a triadic and a ! 1162: ** movw: ! 1163: ** ! 1164: ** op3 O1,O2,O3 -> movw [O1 | O2],R ! 1165: ** movw [O1 | O2],R -> op3 [O1 | R], [O2 | R], O3 ! 1166: ** ! 1167: ** That is, it inserts a register reference into op3. ! 1168: ** R must not be used in O1, O2, or O3. ! 1169: ** O3 cannot be the same as R, nor can O1/O2 use O3 in any way. ! 1170: ** Instruction after movw must not be conditional branch, since we're ! 1171: ** setting different condition codes. ! 1172: ** Don't bother if R dead after movw, since the inst. will go away eventually. ! 1173: */ ! 1174: ! 1175: if ( ! 1176: istriadic(pf,&opn,&opst) ! 1177: && cop2 == MOVW ! 1178: && isreg(pl->op2) ! 1179: && ! isdead(pl->op2,pl) ! 1180: && ( ! 1181: (f = (strcmp(pl->op1,pf->op1) == 0)) ! 1182: || strcmp(pl->op1,pf->op2) == 0 ! 1183: ) ! 1184: && ! usesreg(pf->op1,pl->op2) ! 1185: && ! usesreg(pf->op2,pl->op2) ! 1186: && ! usesreg(pf->op3,pl->op2) ! 1187: && ! usesvar(pl->op1,pf->op3) ! 1188: && ! usesvar(pl->op2,pf->op3) ! 1189: && isdeadcc( pl ) ! 1190: && isiros(pl->op1) /* safe from mmio */ ! 1191: ) ! 1192: { ! 1193: wchange(); ! 1194: if (f) /* true if first operand is R ref. */ ! 1195: pf->op1 = pl->op2; ! 1196: else ! 1197: pf->op2 = pl->op2; /* second operand refers to R */ ! 1198: makelive(pl->op2,pf); /* R now (will be) live after op3 ! 1199: ** since we knew it was live after movw ! 1200: */ ! 1201: lexchin(pf,pl); /* preserve line number info */ ! 1202: exchange(pf); /* exchange the instructions */ ! 1203: swplivecc(pf,pl); /* switch the live/dead info on condition codes */ ! 1204: return(true); ! 1205: } ! 1206: /* Merge successive adds. ! 1207: ** ! 1208: ** This improvement occurs in address arithmetic and in some funny ! 1209: ** expressions. ! 1210: ** ! 1211: ** addw3 X,Y,R1 -> addw2 X,R2 ! 1212: ** addw2 R1,R2 -> addw2 Y,R2 ! 1213: ** ! 1214: ** if R1 dead after addw2, R1 and R2 are different. ! 1215: ** neither X nor Y can use R1 ! 1216: ** ! 1217: ** Unfortunately, we learn the hard way of special cases we hadn't ! 1218: ** thought of earlier, to wit: ! 1219: ** ! 1220: ** addw3 X,R2,R1 -> addw2 R2,R2 ! 1221: ** addw2 R1,R2 -> addw2 X,R2 ! 1222: ** ! 1223: ** If X is R2, we can't do this at all! ! 1224: */ ! 1225: ! 1226: if ( ! 1227: cop1 == ADDW3 ! 1228: && cop2 == ADDW2 ! 1229: && isdead(pf->op3,pl) /* also tests register-ness */ ! 1230: && samereg(pf->op3,pl->op1) ! 1231: && isreg(pl->op2) ! 1232: && ! samereg(pl->op1,pl->op2) ! 1233: && strcmp(pf->op1,pf->op2) != 0 /* different operands */ ! 1234: && ! usesreg(pf->op1,pf->op3) ! 1235: && ! usesreg(pf->op2,pf->op3) ! 1236: ) ! 1237: { ! 1238: wchange(); ! 1239: if (! samereg(pl->op2,pf->op2)) /* check special case */ ! 1240: pl->op1 = pf->op2; /* not special: move Y to 2nd inst. */ ! 1241: else ! 1242: { ! 1243: pl->op1 = pf->op1; /* special case: move X to 2nd inst. */ ! 1244: pf->op1 = pf->op2; /* move R2 over in first */ ! 1245: } ! 1246: pf->op2 = pl->op2; /* move ultimate dest. into 1st inst. */ ! 1247: pf->op3 = NULL; /* clean up 1st inst. */ ! 1248: chgop(pf,ADDW2,"addw2"); /* change op code number and string */ ! 1249: lmrgin2(pf,pl,pf); /* preserve line number info */ ! 1250: /* again this works because pl->uniqid ! 1251: is set to IDVAL */ ! 1252: return(true); ! 1253: } ! 1254: /* Reverse adds/subtracts of literals and other adds/subtracts. ! 1255: ** ! 1256: ** This transformation facilitates other improvements by bubbling ! 1257: ** adds/subtracts of literals downward and other adds/subtracts upwards. ! 1258: ** ! 1259: ** addw2 &n,R -> addw2 O,R ! 1260: ** addw2 O,R -> addw2 &n,R ! 1261: ** ! 1262: ** if R not used in O, O not a literal. ! 1263: */ ! 1264: ! 1265: if ( ! 1266: (cop1 == ADDW2 || cop1 == SUBW2) ! 1267: && (cop2 == ADDW2 || cop2 == SUBW2) ! 1268: && isreg(pf->op2) ! 1269: && samereg(pf->op2,pl->op2) ! 1270: && *pf->op1 == '&' ! 1271: && ! usesreg(pl->op1,pl->op2) ! 1272: && *pl->op1 != '&' ! 1273: ) ! 1274: { ! 1275: wchange(); ! 1276: lexchin(pf,pl); /* preserve line number info */ ! 1277: exchange(pf); /* just exchange instructions */ ! 1278: swplivecc(pf,pl); /* switch the live/dead info on condition codes */ ! 1279: return(true); ! 1280: } ! 1281: /* Reverse adds/subtracts of literals and moves. ! 1282: ** ! 1283: ** This transformation facilitates address arithmetic transformations. ! 1284: ** ! 1285: ** addw2 &n,R -> movX O1,O2 ! 1286: ** movX O1,O2 -> addw2 &n,R ! 1287: ** ! 1288: ** if neither O1 nor O2 uses R ! 1289: ** if instruction following movX is not conditional branch, since we ! 1290: ** will set different condition codes ! 1291: */ ! 1292: ! 1293: if ( ! 1294: (cop1 == ADDW2 || cop2 == SUBW2) ! 1295: && isreg(pf->op2) ! 1296: && strcmp(pf->op2,"%sp") != 0 /* not stack pointer */ ! 1297: && isnumlit(pf->op1) /* only useful with numeric lits. */ ! 1298: && ismove(pl,&src1,&dst1) ! 1299: && ! (usesreg(pl->op1,pf->op2) || usesreg(pl->op2,pf->op2)) ! 1300: && isdeadcc( pl ) ! 1301: ) ! 1302: { ! 1303: wchange(); ! 1304: lexchin(pf,pl); /* preserve line number info */ ! 1305: exchange(pf); /* interchange instructions */ ! 1306: swplivecc(pf,pl); /* switch the live/dead info on condition codes */ ! 1307: /* leave live/dead information alone */ ! 1308: return(true); ! 1309: } ! 1310: return(false); ! 1311: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.