|
|
1.1 ! root 1: ! 2: #ifndef lint ! 3: static char sccsid[] = "@(#)coalesce.c 1.1 86/02/03 Copyr 1985 Sun Micro"; ! 4: #endif ! 5: ! 6: /* ! 7: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 8: */ ! 9: ! 10: #include "as.h" ! 11: #include "c2.h" ! 12: ! 13: extern struct oper *newoperand(); ! 14: extern struct ins_bkt *moveq; ! 15: ! 16: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); } ! 17: #define nexti( p ) { do p=p->forw; while( ISDIRECTIVE(p->op) ); } ! 18: ! 19: #define ispushop(o) ((o)->type_o == T_PREDEC && (o)->value_o == SPREG) ! 20: #define ispopop(o) ((o)->type_o == T_POSTINC && (o)->value_o == SPREG) ! 21: ! 22: extern int bytesize[]; ! 23: #define BYTESIZE( s ) (bytesize[ (int)(s)]) ! 24: ! 25: /* ! 26: * Can register r1 be replaced by a new register r2? ! 27: * The answer is yes, provided that: ! 28: * 1. all uses of r1 in (p) are explicit ! 29: * 2. r1 and r2 are of the same type (a-reg, d-reg, or fp-reg) ! 30: * Certain exceptions to rule 2 are permissible if both r1 and r2 are ! 31: * a-regs or d-regs. ! 32: */ ! 33: int ! 34: can_replace(p, r1, r2) ! 35: register NODE *p; ! 36: register r1,r2; ! 37: { ! 38: register struct oper *o; ! 39: register i; ! 40: int r1_found; ! 41: ! 42: /* search for explicit uses of r1 */ ! 43: r1_found = 0; ! 44: for (i = 0; i < p->nref; i++) { ! 45: o = p->ref[i]; ! 46: switch(o->type_o) { ! 47: case T_REG: ! 48: if (o->value_o == r1) { ! 49: r1_found++; ! 50: if ((p->op == OP_MOVE || p->op == OP_ADD || p->op == OP_SUB) ! 51: && p->subop == SUBOP_L ! 52: && !inmask(CCREG, p->forw->rlive) ! 53: && !inmask(FPCCREG, p->forw->rlive)) { ! 54: int ok; ! 55: o->value_o = r2; ! 56: ok = operand_ok(p->instr, p->ref[0], p->ref[1], 0); ! 57: o->value_o = r1; ! 58: if (ok) continue; ! 59: } ! 60: if (reg_access[r1] == reg_access[r2]) { ! 61: continue; ! 62: } ! 63: return 0; ! 64: } ! 65: continue; ! 66: case T_DEFER: ! 67: case T_POSTINC: ! 68: case T_PREDEC: ! 69: if (o->value_o == r1) { ! 70: return 0; ! 71: } ! 72: continue; ! 73: case T_DISPL: ! 74: if (o->reg_o == r1) { ! 75: return 0; ! 76: } ! 77: continue; ! 78: case T_INDEX: ! 79: if (o->reg_o == r1) { ! 80: return 0; ! 81: } ! 82: if (o->value_o == r1) { ! 83: /* a-regs and d-regs can be used interchangeably here */ ! 84: r1_found++; ! 85: } ! 86: continue; ! 87: case T_REGPAIR: ! 88: if (o->reg_o == r1 || o->value_o == r1) { ! 89: return 0; ! 90: } ! 91: continue; ! 92: } ! 93: if (o->flags_o&O_BFLD) { ! 94: if (o->flags_o&O_BFOREG && o->bfoffset_o == r1) { ! 95: return 0; ! 96: } ! 97: if (o->flags_o&O_BFWREG && o->bfwidth_o == r1) { ! 98: return 0; ! 99: } ! 100: } ! 101: } ! 102: /* ! 103: * we know that r1 is used or set by p, ! 104: * but if r1_found == 0, we haven't found an ! 105: * explicit use. In this case we should bail out. ! 106: */ ! 107: return(r1_found); ! 108: } ! 109: ! 110: void ! 111: replace(p, r1, r2) ! 112: register NODE *p; ! 113: register r1, r2; ! 114: { ! 115: register struct oper *o; ! 116: register i; ! 117: ! 118: /* search for explicit uses of r1 */ ! 119: for (i = 0; i < p->nref; i++) { ! 120: o = p->ref[i]; ! 121: switch(o->type_o) { ! 122: case T_REG: ! 123: case T_DEFER: ! 124: case T_POSTINC: ! 125: case T_PREDEC: ! 126: if (o->value_o == r1) { ! 127: o->value_o = r2; ! 128: } ! 129: continue; ! 130: case T_DISPL: ! 131: if (o->reg_o == r1) { ! 132: o->reg_o = r2; ! 133: } ! 134: continue; ! 135: case T_INDEX: ! 136: case T_REGPAIR: ! 137: if (o->reg_o == r1) { ! 138: o->reg_o = r2; ! 139: } ! 140: if (o->value_o == r1) { ! 141: o->value_o = r2; ! 142: } ! 143: continue; ! 144: } ! 145: if (o->flags_o&O_BFLD) { ! 146: if (o->flags_o&O_BFOREG && o->bfoffset_o == r1) { ! 147: o->bfoffset_o = r2; ! 148: } ! 149: if (o->flags_o&O_BFWREG && o->bfwidth_o == r1) { ! 150: o->bfwidth_o = r2; ! 151: } ! 152: continue; ! 153: } /* if */ ! 154: } /* for */ ! 155: installinstruct(p, p->instr); ! 156: } /* replace */ ! 157: ! 158: int ! 159: next_member(regtype, regset) ! 160: int regtype; ! 161: regmask regset; ! 162: { ! 163: register regno; ! 164: ! 165: switch(regtype) { ! 166: case AM_DREG: ! 167: /* try for d-reg first */ ! 168: for(regno = D0REG; regno <= D7REG; regno++) { ! 169: if (inmask(regno,regset)) ! 170: return(regno); ! 171: } ! 172: for(regno = A0REG; regno < A6REG; regno++) { ! 173: if (inmask(regno,regset)) ! 174: return(regno); ! 175: } ! 176: break; ! 177: case AM_AREG: ! 178: /* try for a-reg first */ ! 179: for(regno = A0REG; regno < A6REG; regno++) { ! 180: if (inmask(regno,regset)) ! 181: return(regno); ! 182: } ! 183: for(regno = D0REG; regno <= D7REG; regno++) { ! 184: if (inmask(regno,regset)) ! 185: return(regno); ! 186: } ! 187: break; ! 188: case AM_FREG: ! 189: /* only another fp-reg will do */ ! 190: for(regno = FP0REG; regno <= FP7REG; regno++) { ! 191: if (inmask(regno,regset)) ! 192: return(regno); ! 193: } ! 194: break; ! 195: } ! 196: return(-1); ! 197: } ! 198: ! 199: /* ! 200: * look for a register that is not live anywhere in (b)..(n). ! 201: * regtype is the type of register preferred (or required, ! 202: * in the case of a floating point register). Returns -1 if ! 203: * no suitable register is found. ! 204: */ ! 205: int ! 206: find_freereg(b, n, regtype) ! 207: register NODE *b, *n; ! 208: int regtype; ! 209: { ! 210: register NODE *p,*bb; ! 211: regmask liveset; ! 212: register regno; ! 213: ! 214: bb = b->back; ! 215: liveset = n->rlive; ! 216: for (p = n; p != bb; p = p->back) { ! 217: liveset = addmask(liveset, p->rlive); ! 218: } ! 219: liveset = addmask(liveset, p->rlive); ! 220: return(next_member(regtype, notmask(liveset))); ! 221: } ! 222: ! 223: /* ! 224: * try to replace register r1 with register r2 in the ! 225: * set of nodes (b)..(n) (assumed to be a basic block). ! 226: * r2 is assumed to be available in (b)..(n). ! 227: * Returns 1 if the new assignment succeeds. ! 228: * Otherwise returns 0 and leaves (b)..(n) unchanged. ! 229: */ ! 230: int ! 231: can_reassign_reg(b,n,r1,r2) ! 232: register NODE *b,*n; ! 233: register r1; ! 234: register r2; ! 235: { ! 236: register NODE *p,*bb; ! 237: regmask l; ! 238: ! 239: if (!inmask(r1, b->rlive) && !inmask(r1, n->forw->rlive)) { ! 240: /* r1 and r2 must have the same type or must both be a/d regs */ ! 241: if (reg_access[r1] != reg_access[r2] ! 242: && (!dareg(r1) || !dareg(r2))) { ! 243: return(0); ! 244: } ! 245: /* (b)..(n) contains the lifetime of r1 */ ! 246: bb = b->back; ! 247: for (p = n; p != bb; p = p->back) { ! 248: if (ISINSTRUC(p->op)) { ! 249: if ((inmask(r1, p->ruse) || inmask(r1, p->rset)) ! 250: && !can_replace(p, r1, r2)) { ! 251: return(0); ! 252: } ! 253: } ! 254: } ! 255: return(1); ! 256: } ! 257: return(0); ! 258: } /* can_reassign_reg */ ! 259: ! 260: void ! 261: reassign_reg(b,n,r1,r2) ! 262: register NODE *b,*n; ! 263: register r1; ! 264: register r2; ! 265: { ! 266: register NODE *p,*bb; ! 267: regmask l; ! 268: ! 269: l = n->forw->rlive; ! 270: bb = b->back; ! 271: for (p = n; p != bb; p = p->back) { ! 272: if (ISINSTRUC(p->op) ! 273: && (inmask(r1, p->ruse) || inmask(r1, p->rset))) ! 274: replace(p, r1, r2); ! 275: l = p->rlive = compute_normal(p, l); ! 276: } ! 277: } ! 278: ! 279: ! 280: static struct ins_bkt * ! 281: move_inst(b,n,x,y) ! 282: register NODE *b, *n; ! 283: register struct oper *x, *y; ! 284: { ! 285: if (operand_ok(b->instr, x, y, 0)) { ! 286: return(b->instr); ! 287: } else if (operand_ok(n->instr, x, y, 0)) { ! 288: return(n->instr); ! 289: } else { ! 290: /* try special cases involving floating point */ ! 291: int Xisfp, Yisfp; ! 292: Xisfp = Yisfp = 0; ! 293: if (x->type_o==T_REG && freg(x->value_o)) ! 294: Xisfp = 1; ! 295: if (y->type_o==T_REG && freg(y->value_o)) ! 296: Yisfp = 1; ! 297: if (!Xisfp && !Yisfp ! 298: && !inmask(FPCCREG, n->forw->rlive)) { ! 299: /* rewrite as (b) mov{b,w,l} X,Y */ ! 300: switch(b->subop) { ! 301: case SUBOP_B: ! 302: return(sopcode("movb")); ! 303: case SUBOP_W: ! 304: return(sopcode("movw")); ! 305: case SUBOP_L: ! 306: case SUBOP_S: ! 307: return(sopcode("movl")); ! 308: default: ! 309: /* if larger than a word, forget it */ ! 310: return(NULL); ! 311: } ! 312: } else if (Xisfp && Yisfp) { ! 313: /* floating point reg-reg move */ ! 314: return(sopcode("fmovex")); ! 315: } ! 316: } ! 317: return(NULL); ! 318: } ! 319: ! 320: /* ! 321: * Is this instruction a reg-reg operation ? ! 322: * To be safe, we require the instruction to use all of ! 323: * both registers, with no data conversions. ! 324: */ ! 325: static int ! 326: reg_reg_op(p) ! 327: register NODE *p; ! 328: { ! 329: register struct oper *rm, *rn; ! 330: ! 331: if (p->nref == 2) { ! 332: rm = p->ref[0]; rn = p->ref[1]; ! 333: if(rm != NULL && rm->type_o == T_REG && datareg(rm->value_o) ! 334: && rn != NULL && rn->type_o == T_REG && datareg(rn->value_o)) { ! 335: switch (p->subop) { ! 336: case SUBOP_L: ! 337: return(dareg(rm->value_o) && dareg(rn->value_o)); ! 338: case SUBOP_X: ! 339: return(freg(rm->value_o) && freg(rn->value_o)); ! 340: } ! 341: } ! 342: } ! 343: return(0); ! 344: } ! 345: ! 346: static int ! 347: iscommuteop(p) ! 348: NODE *p; ! 349: { ! 350: char *s; ! 351: ! 352: switch(p->op){ ! 353: case OP_ADD: ! 354: case OP_AND: ! 355: case OP_OR: ! 356: case OP_EOR: ! 357: return(reg_reg_op(p)); ! 358: case OP_OTHER: ! 359: /* ! 360: * careful: multiplication isn't really commutative ! 361: * unless it is also known to be reg-reg ! 362: */ ! 363: s = p->instr->text_i; ! 364: if (!strcmp(s,"mulsl") || !strcmp(s,"mulul") ! 365: || !strcmp(s,"fmulx") || !strcmp(s, "faddx")) ! 366: return(reg_reg_op(p)); ! 367: } ! 368: return(0); ! 369: } ! 370: ! 371: /* ! 372: * returns 1 if an instruction does implied data conversion ! 373: * to match its destination operand (assumed to be the last operand). ! 374: * In the 68xxx processors this occurs in cases involving address ! 375: * registers or floating point registers. ! 376: */ ! 377: int ! 378: implied_conversion(p) ! 379: register NODE *p; ! 380: { ! 381: struct oper *o; ! 382: ! 383: if (p->nref > 0) { ! 384: o = p->ref[p->nref-1]; ! 385: if (datareg_addr(o)) { ! 386: if (areg(o->value_o)) return (p->subop != SUBOP_L); ! 387: if (freg(o->value_o)) return (p->subop != SUBOP_X); ! 388: } ! 389: } ! 390: return 0; ! 391: } ! 392: ! 393: /* ! 394: * coalesce register usage over subranges of a basic block, ! 395: * eliminating unnecessary reg-reg moves. ! 396: */ ! 397: int ! 398: coalesce() ! 399: { ! 400: register NODE *n; ! 401: register NODE *p,*b; ! 402: register struct oper *o; ! 403: register struct ins_bkt *ip; ! 404: struct oper *rm, *rn; ! 405: NODE *q; ! 406: register int regno; ! 407: extern NODE *deletenode(); ! 408: int changes; ! 409: regmask l; ! 410: ! 411: changes = 0; ! 412: for (n=first.forw; n != &first; n=n->forw) { ! 413: ! 414: /* ! 415: * Pattern #1: given ! 416: * (b) move X,rn ! 417: * .... ! 418: * (n) move rn,Y ! 419: * ! 420: * rewrite #1: if possible, rewrite as: ! 421: * (b) move X,Y ! 422: * .... ! 423: * (n) (deleted) ! 424: * ! 425: * rewrite #2: if possible, rewrite as: ! 426: * (b) (deleted) ! 427: * .... ! 428: * (n) move X,Y ! 429: * ! 430: * requirements: ! 431: * -- (b) and (n) must be moves of the same type ! 432: * -- (n) must not do sign-extension or other data conversion ! 433: * -- X must not be an immediate operand. ! 434: * -- Y must be a legal replacement for rn in (b). ! 435: * -- neither X nor Y can be a control register or i/o device ! 436: * -- rn must not be live at (n). ! 437: * -- rn must be neither used nor set in the interim. ! 438: * -- side effects of X and Y must not be used in the interim. ! 439: * -- condition codes should not be live at either (b) or (n). ! 440: * ! 441: * for #1: ! 442: * -- Y must not be used or modified in the interim. ! 443: * ! 444: * for #2: ! 445: * -- X must not be modified in the interim. ! 446: */ ! 447: o = n->ref[0]; ! 448: if (n->op == OP_MOVE && o->type_o == T_REG && datareg(o->value_o) ! 449: && !implied_conversion(n) ! 450: && !inmask(o->value_o, n->forw->rlive)) { ! 451: struct oper *x, *y; ! 452: x = y = NULL; ! 453: regno = o->value_o; ! 454: b = n; ! 455: do { ! 456: previ(b); ! 457: if (b->op == OP_FIRST || b->op == OP_LABEL ! 458: || ISBRANCH(b->op)) { ! 459: /* flow of control to reach this point is unknown */ ! 460: break; ! 461: } ! 462: if (b->op == OP_MOVE && b->subop == n->subop ! 463: && b->ref[1]->type_o == T_REG ! 464: && b->ref[1]->value_o == o->value_o) { ! 465: /* have move x,rn;...;move rn,y */ ! 466: x = b->ref[0]; ! 467: y = n->ref[1]; ! 468: /* do checks on x,y */ ! 469: if (x->type_o == T_IMMED ! 470: || x->type_o == T_REG && !datareg(x->value_o) ! 471: || y->type_o == T_REG && !datareg(y->value_o) ! 472: || inmask(CCREG, b->forw->rlive) ! 473: || inmask(CCREG, n->forw->rlive) ! 474: || inmask(FPCCREG, b->forw->rlive) ! 475: || inmask(FPCCREG, n->forw->rlive)) { ! 476: /* can't optimize */ ! 477: x = y = NULL; ! 478: } ! 479: break; ! 480: } ! 481: if (inmask(regno,b->rset) || inmask(regno,b->ruse)) { ! 482: /* unknown use/modification of regno */ ! 483: break; ! 484: } ! 485: } while (1); ! 486: /* ! 487: * if the preceding search yielded a suitable operand ! 488: * pair, try to delete either node (b) or node (n). ! 489: */ ! 490: if (y != NULL) { ! 491: int can_move_x = (x->type_o == T_REG || cancache(x)); ! 492: int can_move_y = (y->type_o == T_REG || cancache(y)); ! 493: /* determine side effects of (n) other than defining Y */ ! 494: if (y->type_o == T_REG) { ! 495: l = submask(n->rset, MAKEWMASK(y->value_o, BW|WW|LW)); ! 496: } else { ! 497: l = n->rset; ! 498: } ! 499: if (emptymask(andmask(l, n->forw->rlive))) { ! 500: /* ! 501: * search for defs/uses of Y and defs affecting access to Y; ! 502: * if none are found, move def of Y back to node (b). ! 503: */ ! 504: p = n; ! 505: previ(p); ! 506: while (p != b) { ! 507: if (may_touch(p, y, n->subop, RMASK|WMASK)) { ! 508: can_move_y = 0; ! 509: break; ! 510: } ! 511: if (!emptymask(andmask(n->ruse, p->rset))) { ! 512: /* try salvaging by reassigning registers */ ! 513: int r1, r2; ! 514: if (p->op != OP_MOVE ! 515: || p->ref[1]->type_o != T_REG ) { ! 516: /* def is implicit; give up */ ! 517: can_move_y = 0; ! 518: break; ! 519: } ! 520: r1 = p->ref[1]->value_o; ! 521: r2 = find_freereg(p, n, reg_access[r1]); ! 522: if (r2 == -1 || !can_reassign_reg(p, n, r1, r2)) { ! 523: can_move_y = 0; ! 524: break; ! 525: } ! 526: reassign_reg(p, n, r1, r2); ! 527: } ! 528: previ(p); ! 529: } ! 530: if (can_move_y && (ip = move_inst(b, n, x, y)) != NULL) { ! 531: /* rewrite */ ! 532: freeoperand(b->ref[1]); ! 533: b->ref[1] = newoperand(y); ! 534: installinstruct(b, ip); ! 535: n = deletenode(n); ! 536: changes++; ! 537: meter.redunm++; ! 538: if (ispopop(x) && ispushop(y)) { ! 539: b = deletenode(b); ! 540: changes++; ! 541: meter.redunm++; ! 542: } ! 543: l = n->forw->rlive; ! 544: for (p = n; p != b; p = p->back) { ! 545: l = p->rlive = compute_normal(p, l); ! 546: } ! 547: continue; ! 548: } /* if can_move_y */ ! 549: } /* if */ ! 550: /* ! 551: * search for defs of X and defs affecting access to X; ! 552: * if none are found, move use of X forward to node (n). ! 553: */ ! 554: p = n; ! 555: previ(p); ! 556: while (p != b) { ! 557: if (may_touch(p, x, n->subop, WMASK)) { ! 558: can_move_x = 0; ! 559: break; ! 560: } ! 561: if (!emptymask(andmask(b->ruse, p->rset))) { ! 562: /* try salvaging by reassigning registers */ ! 563: int r1, r2; ! 564: if (p->op != OP_MOVE ! 565: || p->ref[1]->type_o != T_REG ) { ! 566: /* def is implicit; give up */ ! 567: can_move_x = 0; ! 568: break; ! 569: } ! 570: r1 = p->ref[1]->value_o; ! 571: r2 = find_freereg(p, n, reg_access[r1]); ! 572: if (r2 == -1 || !can_reassign_reg(p, n, r1, r2)) { ! 573: can_move_x = 0; ! 574: break; ! 575: } ! 576: reassign_reg(p, n, r1, r2); ! 577: } ! 578: previ(p); ! 579: } ! 580: if (can_move_x && (ip = move_inst(b, n, x, y)) != NULL) { ! 581: /* rewrite */ ! 582: freeoperand(n->ref[0]); ! 583: n->ref[0] = newoperand(x); ! 584: installinstruct(n, ip); ! 585: b = deletenode(b); ! 586: changes++; ! 587: meter.redunm++; ! 588: if (ispopop(x) && ispushop(y)) { ! 589: n = deletenode(n); ! 590: changes++; ! 591: meter.redunm++; ! 592: } ! 593: l = n->forw->rlive; ! 594: for (p = n; p != b; p = p->back) { ! 595: l = p->rlive = compute_normal(p, l); ! 596: } ! 597: continue; ! 598: } /* if can_move_x */ ! 599: } /* y != NULL */ ! 600: } /* if */ ! 601: ! 602: /* ! 603: * Pattern #2: given ! 604: * (b) move X,rn ! 605: * .... ! 606: * (computations involving rn) ! 607: * .... ! 608: * (n) move rn,rm ! 609: * ! 610: * if possible, rewrite as: ! 611: * (b) move X,rm ! 612: * .... ! 613: * (all defs/uses of rn changed to def/use rm) ! 614: * .... ! 615: * (n) (deleted) ! 616: * ! 617: * requirements: ! 618: * -- rn must not be live at (n). ! 619: * -- condition codes should not be live at (n). ! 620: * -- rm must neither be used nor set in the interim. ! 621: * -- all defs/uses of rn in (b)..(n) must be replaceable with rm. ! 622: */ ! 623: o = n->ref[0]; ! 624: if (n->op == OP_MOVE && reg_reg_op(n) ! 625: && !inmask(CCREG, n->forw->rlive) ! 626: && !inmask(FPCCREG, n->forw->rlive) ! 627: && !inmask(o->value_o, n->forw->rlive)) { ! 628: regno = n->ref[1]->value_o; ! 629: b = n; ! 630: do { ! 631: previ(b); ! 632: if (b->op == OP_FIRST || b->op == OP_LABEL ! 633: || ISBRANCH(b->op)) { ! 634: /* flow of control to reach this point is unknown */ ! 635: break; ! 636: } ! 637: if (b->op == OP_MOVE && b->subop == n->subop ! 638: && sameops(o, b->ref[1]) ! 639: && !inmask(regno, b->forw->rlive)) { ! 640: /* have move x,rn;...;move rn,rm */ ! 641: if (can_reassign_reg(b, n, o->value_o, regno)) { ! 642: reassign_reg(b, n, o->value_o, regno); ! 643: b->ref[1]->value_o = regno; ! 644: n = deletenode(n); ! 645: changes++; ! 646: meter.redunm++; ! 647: l = n->forw->rlive; ! 648: for (p = n; p != b; p = p->back) { ! 649: l = p->rlive = compute_normal(p, l); ! 650: } ! 651: } ! 652: break; ! 653: } ! 654: if (inmask(regno,b->rset) || inmask(regno,b->ruse)) { ! 655: /* unknown use/modification of regno */ ! 656: break; ! 657: } ! 658: } while (1); ! 659: } /* if */ ! 660: ! 661: /* ! 662: * Pattern #3: (forward copy propagation) ! 663: * (n) move rm,rn (rm is dead after (n)) ! 664: * .... ! 665: * (computations involving rn) ! 666: * .... ! 667: * (p) lastuse(rn) (rn is dead after (p)) ! 668: * ! 669: * if possible, rewrite as: ! 670: * (n) (deleted) ! 671: * .... ! 672: * (all defs/uses of rn changed to def/use rm) ! 673: * .... ! 674: * (p) lastuse(rm) ! 675: * ! 676: * requirements: ! 677: * -- the move at (n) must not involve data conversions. ! 678: * -- rm must not be live after (n). ! 679: * -- rn must not be live after (p). ! 680: * -- rm must neither be used nor set in the interim. ! 681: * -- condition codes must not be live after (n). ! 682: * -- if condition codes are live at (p), rm and rn must be ! 683: * of the same type. ! 684: * -- all defs/uses of rn in (n)..(p) must be replaceable with rm. ! 685: */ ! 686: if (n->op == OP_MOVE && reg_reg_op(n) ! 687: && !inmask(CCREG, n->forw->rlive) ! 688: && !inmask(FPCCREG, n->forw->rlive) ! 689: && !inmask(n->ref[0]->value_o, n->forw->rlive)) { ! 690: rm = n->ref[0]; ! 691: rn = n->ref[1]; ! 692: regno = rn->value_o; ! 693: p = n; ! 694: do { ! 695: /* scan forward for last use of value in rn */ ! 696: nexti(p); ! 697: if (p->op == OP_FIRST || p->op == OP_LABEL ! 698: || ISBRANCH(p->op)) { ! 699: /* flow of control to reach this point is unknown */ ! 700: break; ! 701: } ! 702: if (!inmask(regno, p->forw->rlive)) { ! 703: if (can_reassign_reg(n, p, regno, rm->value_o)) { ! 704: reassign_reg(n, p, regno, rm->value_o); ! 705: n = deletenode(n); ! 706: changes++; ! 707: meter.redunm++; ! 708: n->rlive = compute_normal(n, n->forw->rlive); ! 709: } ! 710: break; ! 711: } ! 712: if (inmask(rm->value_o,p->rset)||inmask(rm->value_o,p->ruse)) { ! 713: /* unknown use/modification of rm */ ! 714: break; ! 715: } ! 716: } while(1); ! 717: } /* if */ ! 718: ! 719: /* ! 720: * Pattern #4: (similar to #3, but exploits commutativity) ! 721: * (n) move rm,rn ! 722: * (q) <op> ro,rn (ro is dead after (q)) ! 723: * .... ! 724: * (computations involving rn) ! 725: * .... ! 726: * (p) lastuse(rn) (rn is dead after (p)) ! 727: * ! 728: * if possible, rewrite as: ! 729: * (n) (deleted) ! 730: * (q) <op> rm,ro ! 731: * .... ! 732: * (all defs/uses of rn changed to def/use ro) ! 733: * .... ! 734: * (p) lastuse(ro) ! 735: * ! 736: * requirements: ! 737: * -- the move at (n) must not involve data conversions. ! 738: * -- <op> must be commutative ! 739: * -- ro must not be live after (q). ! 740: * -- condition codes must not be live after (q). ! 741: * -- if condition codes are live after (p), rn and ro ! 742: * must be registers of the same type. ! 743: * -- rn must not be live after (p). ! 744: * -- ro must neither be used nor set in the interim. ! 745: * -- all defs/uses of rn in (q)..(p) must be replaceable with ro. ! 746: */ ! 747: if (n->op == OP_MOVE && reg_reg_op(n)) { ! 748: rm = n->ref[0]; ! 749: rn = n->ref[1]; ! 750: q = n; ! 751: nexti(q); ! 752: if (iscommuteop(q) ! 753: && sameops(rn, q->ref[1]) ! 754: && operand_ok(q->instr, rm, (o = q->ref[0]), 0) ! 755: && !inmask(o->value_o, q->forw->rlive) ! 756: && !inmask(CCREG, q->forw->rlive) ! 757: && !inmask(FPCCREG, q->forw->rlive) ) { ! 758: /* ! 759: * ro is dead, and its last use is in ! 760: * a commutative operator with rn. Scan for ! 761: * the last use of the value in rn. ! 762: */ ! 763: regno = rn->value_o; ! 764: p = q; ! 765: do { ! 766: nexti(p); ! 767: if (p->op == OP_FIRST || p->op == OP_LABEL ! 768: || ISBRANCH(p->op)) { ! 769: /* flow of control to reach this point is unknown */ ! 770: break; ! 771: } ! 772: if (!inmask(regno, p->forw->rlive)) { ! 773: if (can_reassign_reg(n, p, regno, o->value_o)) { ! 774: /* ! 775: * use rm as the first operand of q, ! 776: * propagate ro through the lifetime of rn, ! 777: * and delete the move from rm to rn. ! 778: */ ! 779: q->ref[0] = newoperand(rm); ! 780: reassign_reg(n, p, regno, o->value_o); ! 781: freeoperand(o); ! 782: n = deletenode(n); ! 783: changes++; ! 784: meter.redunm++; ! 785: n->rlive = compute_normal(n, n->forw->rlive); ! 786: } ! 787: break; ! 788: } /* if */ ! 789: if(inmask(o->value_o,p->ruse)||inmask(o->value_o,p->rset)) { ! 790: /* unknown use/def of ro */ ! 791: break; ! 792: } ! 793: } while (1); ! 794: } /* if */ ! 795: } /* if */ ! 796: ! 797: } /* for */ ! 798: return(changes); ! 799: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.