|
|
1.1 ! root 1: ! 2: #ifndef lint ! 3: static char sccsid[] = "@(#)stackops.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: ! 15: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); } ! 16: ! 17: #define ispushop(o) ((o)->type_o == T_PREDEC && (o)->value_o == SPREG) ! 18: #define ispopop(o) ((o)->type_o == T_POSTINC && (o)->value_o == SPREG) ! 19: ! 20: extern int bytesize[]; ! 21: #define BYTESIZE( s ) (bytesize[ (int)(s)]) ! 22: ! 23: /* ! 24: * replace ! 25: * (b)->move X,sp@- ! 26: * ... ! 27: * (n)->move sp@+,Rn ! 28: * with ! 29: * (b)->move X,Rn ! 30: * ... ! 31: * (n) deleted ! 32: * Note that if Rn is live after (n), it now becomes live ! 33: * at all of the points in between (b) and (n). ! 34: */ ! 35: ! 36: static NODE * ! 37: movedef(b,n,ip) ! 38: register NODE *b; ! 39: NODE *n; ! 40: struct ins_bkt *ip; ! 41: { ! 42: register NODE *p; ! 43: regmask l; ! 44: ! 45: if (b->nref == 2) ! 46: freeoperand(b->ref[1]); ! 47: else ! 48: b->nref = 2; ! 49: b->ref[1] = newoperand(n->ref[1]); ! 50: installinstruct(b,ip); ! 51: n = deletenode(n); ! 52: l = n->forw->rlive; ! 53: for (p = n; p != b; p = p->back) { ! 54: l = p->rlive = compute_normal(p, l); ! 55: } ! 56: return n; ! 57: } ! 58: ! 59: /* ! 60: * replace ! 61: * (b)->pea X ! 62: * ... ! 63: * (n)->move sp@+,dn ! 64: * with ! 65: * (b)->lea X,ar ! 66: * movl ar,dn ! 67: * ... ! 68: * (n) (deleted) ! 69: * ! 70: * This is like the previous transformation with an ! 71: * adjustment for the fact that 'lea' does not work ! 72: * with a d-register destination. ! 73: */ ! 74: static NODE* ! 75: movedef2(b, n, ar, ip) ! 76: register NODE *b; ! 77: register NODE *n; ! 78: int ar; ! 79: struct ins_bkt *ip; ! 80: { ! 81: register NODE *p; ! 82: register struct oper *o; ! 83: regmask l; ! 84: ! 85: /* ! 86: * rewrite (b) as "lea X,ar" ! 87: */ ! 88: b->nref = 2; ! 89: o = newoperand(n->ref[1]); ! 90: o->value_o = ar; ! 91: b->ref[1] = o; ! 92: installinstruct(b,ip); ! 93: /* ! 94: * insert "movl ar,dn" following (b) ! 95: */ ! 96: p = new(); ! 97: p->nref = 2; ! 98: o = newoperand(o); ! 99: o->value_o = ar; ! 100: p->ref[0] = o; ! 101: o = newoperand(o); ! 102: o->value_o = n->ref[1]->value_o; ! 103: p->ref[1] = o; ! 104: cannibalize(p, "movl"); ! 105: insert(p,b); ! 106: /* ! 107: * delete (n), update register lifetime information ! 108: */ ! 109: n = deletenode(n); ! 110: l = n->forw->rlive; ! 111: for (p = n; p != b; p = p->back) { ! 112: l = p->rlive = compute_normal(p, l); ! 113: } ! 114: return n; ! 115: } ! 116: ! 117: ! 118: /* ! 119: * replace ! 120: * (b)->move X,sp@- ! 121: * ... ! 122: * (n)-><op> sp@+,... ! 123: * with ! 124: * (b) (deleted) ! 125: * ... ! 126: * (n)-><op> X,... ! 127: * Note that if X is a register, it now becomes live ! 128: * at all of the points in between (b) and (n). ! 129: */ ! 130: static NODE * ! 131: moveuse(b, n, srce, ip) ! 132: NODE *b,*n; ! 133: struct oper *srce; ! 134: struct ins_bkt *ip; ! 135: { ! 136: register NODE *p; ! 137: regmask l; ! 138: ! 139: freeoperand(n->ref[0]); ! 140: n->ref[0] = srce; ! 141: b = deletenode(b); ! 142: installinstruct(n,ip); ! 143: l = n->forw->rlive; ! 144: for (p = n; p != b; p = p->back) { ! 145: l = p->rlive = compute_normal(p, l); ! 146: } ! 147: return(n); ! 148: } ! 149: ! 150: ! 151: /* ! 152: * returns the "extended mode" instruction, if any, ! 153: * corresponding to the the instruction described by (ip). ! 154: */ ! 155: struct ins_bkt * ! 156: extendedop(ip) ! 157: struct ins_bkt *ip; ! 158: { ! 159: char buf[64]; ! 160: ! 161: (void)strcpy(buf, ip->text_i); ! 162: buf[strlen(buf)-1] = 'x'; ! 163: return(sopcode(buf)); ! 164: } ! 165: ! 166: /* ! 167: * returns 1 if operands (op1) and (op2) may overlap ! 168: */ ! 169: int ! 170: mayoverlap(op1, op2, subop1, subop2) ! 171: register struct oper *op1; ! 172: register struct oper *op2; ! 173: subop_t subop1; ! 174: subop_t subop2; ! 175: { ! 176: int r1, r2; ! 177: struct sym_bkt *sym1, *sym2; ! 178: int lb1, lb2, ub1, ub2; /* byte offset bounds of op1 and op2 */ ! 179: int glb, lub; /* greatest lower & least upper bounds */ ! 180: ! 181: r1 = -1; ! 182: r2 = -1; ! 183: lb1 = 0; ! 184: lb2 = 0; ! 185: sym1 = NULL; ! 186: sym2 = NULL; ! 187: switch(op1->type_o) { ! 188: case T_IMMED: ! 189: return(0); ! 190: case T_REG: ! 191: return(op2->type_o == T_REG && op1->value_o == op2->value_o); ! 192: case T_POSTINC: ! 193: case T_PREDEC: ! 194: /* assume sp@+ and sp@- only overlap with each other */ ! 195: if (op1->value_o == SPREG) { ! 196: if (op2->type_o == T_POSTINC || op2->type_o == T_PREDEC) ! 197: return(op2->value_o == SPREG); ! 198: return(0); ! 199: } ! 200: return(1); ! 201: case T_DISPL: ! 202: r1 = op1->reg_o; ! 203: /* fall through */ ! 204: case T_ABSS: ! 205: case T_ABSL: ! 206: case T_NORMAL: ! 207: sym1 = op1->sym_o; ! 208: lb1 = op1->value_o; ! 209: ub1 = lb1 + BYTESIZE(subop1)-1; ! 210: break; ! 211: case T_DEFER: ! 212: r1 = op1->value_o; ! 213: ub1 = lb1 + BYTESIZE(subop1)-1; ! 214: break; ! 215: } ! 216: switch(op2->type_o) { ! 217: case T_IMMED: ! 218: case T_REG: ! 219: return(0); ! 220: case T_POSTINC: ! 221: case T_PREDEC: ! 222: return(op2->value_o != SPREG); ! 223: case T_DISPL: ! 224: r2 = op2->reg_o; ! 225: /* fall through */ ! 226: case T_ABSS: ! 227: case T_ABSL: ! 228: case T_NORMAL: ! 229: sym2 = op2->sym_o; ! 230: lb2 = op2->value_o; ! 231: ub2 = lb2 + BYTESIZE(subop2)-1; ! 232: goto compute_overlap; ! 233: case T_DEFER: ! 234: r2 = op2->value_o; ! 235: ub2 = lb2 + BYTESIZE(subop2)-1; ! 236: /* fall through */ ! 237: compute_overlap: ! 238: if (r1 != r2 || sym1 != sym2) ! 239: return(1); ! 240: ub1 = lb1 + BYTESIZE(subop1)-1; ! 241: ub2 = lb2 + BYTESIZE(subop2)-1; ! 242: glb = lb1 > lb2 ? lb1 : lb2; ! 243: lub = ub1 < ub2 ? ub1 : ub2; ! 244: return(glb <= lub); ! 245: default: ! 246: return(1); ! 247: } ! 248: } ! 249: ! 250: /* ! 251: * returns 1 if two operands are in adjacent *addressable* words ! 252: */ ! 253: int ! 254: adjacent(op1, op2) ! 255: register struct oper *op1,*op2; ! 256: { ! 257: int w; ! 258: struct oper temp; ! 259: ! 260: if (op1->type_o != op2->type_o) { ! 261: /* make DEFER operands look like DISPL operands */ ! 262: if (op1->type_o == T_DEFER) { ! 263: temp.type_o = T_DISPL; ! 264: temp.reg_o = op1->value_o; ! 265: temp.value_o = 0; ! 266: op1 = &temp; ! 267: } else if (op2->type_o == T_DEFER) { ! 268: temp.type_o = T_DISPL; ! 269: temp.reg_o = op2->value_o; ! 270: temp.value_o = 0; ! 271: op2 = &temp; ! 272: } else { ! 273: return 0; ! 274: } ! 275: } ! 276: switch (op1->type_o){ ! 277: case T_IMMED: ! 278: case T_NORMAL: ! 279: case T_ABSS: ! 280: case T_ABSL: ! 281: if (op1->sym_o != op2->sym_o) return 0; /* oops -- complex*/ ! 282: /* fall through */ ! 283: case T_REG: ! 284: case T_DEFER: ! 285: case T_POSTINC: ! 286: case T_PREDEC: ! 287: if (op1->value_o + sizeof(long) != op2->value_o) return 0; ! 288: break; ! 289: case T_INDEX: ! 290: if (op1->disp_o + sizeof(long) != op2->disp_o) return 0; ! 291: /* fall through */ ! 292: case T_DISPL: ! 293: if (op1->reg_o != op2->reg_o) return 0; ! 294: if (op1->value_o + sizeof(long) != op2->value_o) return 0; ! 295: break; ! 296: default: ! 297: return 0; ! 298: } ! 299: return 1; ! 300: } ! 301: ! 302: /* ! 303: * returns 1 if node (n) may use/modify operand (o) ! 304: */ ! 305: int ! 306: may_touch(n, o, osubop, touchmask) ! 307: register NODE *n; ! 308: register struct oper *o; ! 309: int osubop; /* subop of instruction using (o) */ ! 310: register touchmask; ! 311: { ! 312: register int i,v; ! 313: regmask l; ! 314: ! 315: switch(o->type_o) { ! 316: case T_IMMED: ! 317: return 0; ! 318: case T_REG: ! 319: if (touchmask&RMASK == touchmask) ! 320: return inmask(o->value_o,n->ruse); ! 321: if (touchmask&WMASK == touchmask) ! 322: return inmask(o->value_o,n->rset); ! 323: if (touchmask) ! 324: return inmask(o->value_o,addmask(n->rset,n->ruse)); ! 325: return 0; ! 326: default: ! 327: /* ! 328: * for each operand modified by (n), see if ! 329: * a potential overlap with (o) exists. ! 330: */ ! 331: if (n->op == OP_CALL) ! 332: return 1; ! 333: v = make_touchop(n, n->instr->touchop_i); ! 334: for (i = 0; i < n->nref; i++) { ! 335: if (v&touchmask) { ! 336: if (mayoverlap(o, n->ref[i], osubop, n->subop)) ! 337: return 1; ! 338: } ! 339: v >>= TOUCHWIDTH; ! 340: } ! 341: } ! 342: return 0; ! 343: } ! 344: ! 345: ! 346: /* ! 347: * reduce stack traffic exposed by inline expansion ! 348: * of procedures ! 349: */ ! 350: int ! 351: stackops() ! 352: { ! 353: register NODE *n; ! 354: register NODE *p,*b; ! 355: register struct ins_bkt *ip; ! 356: register struct oper *o; ! 357: register int regno; ! 358: extern NODE *deletenode(); ! 359: int changes; ! 360: regmask l; ! 361: int offset; ! 362: int r; ! 363: ! 364: changes = 0; ! 365: for (n=first.forw; n != &first; n=n->forw) { ! 366: ! 367: /* ! 368: * Pattern #0: ! 369: * (0) sub #X,sp ! 370: * (1) add #Y,sp -or- (1) lea sp@(Y),sp ! 371: * Rewrite: ! 372: * delete both, or use a single addql, subql, or lea ! 373: */ ! 374: if (n->op == OP_SUB ! 375: && n->ref[1]->type_o == T_REG && n->ref[1]->value_o == SPREG ! 376: && n->ref[0]->type_o == T_IMMED) { ! 377: p = n->forw; ! 378: switch(p->op) { ! 379: case OP_ADD: ! 380: o = p->ref[1]; ! 381: if (o->type_o == T_REG && o->value_o == SPREG ! 382: && p->ref[0]->type_o == T_IMMED) { ! 383: goto delete_adjust; ! 384: } ! 385: break; ! 386: case OP_LEA: ! 387: o = p->ref[1]; ! 388: if (o->type_o == T_REG && o->value_o == SPREG ! 389: && p->ref[0]->type_o == T_DISPL ! 390: && p->ref[0]->reg_o == SPREG ) { ! 391: goto delete_adjust; ! 392: } ! 393: break; ! 394: delete_adjust: ! 395: offset = n->ref[0]->value_o - p->ref[0]->value_o; ! 396: p = deletenode(p); ! 397: if (offset == 0) { ! 398: n = deletenode(n); ! 399: } else if (offset >= 1 && offset <= 8) { ! 400: n->ref[0]->value_o = offset; ! 401: installinstruct(n, sopcode("addql")); ! 402: } else if (offset <= -8 && offset >= -1) { ! 403: n->ref[0]->value_o = -offset; ! 404: installinstruct(n, sopcode("subql")); ! 405: } else { ! 406: o = n->ref[0]; ! 407: o->type_o = T_DISPL; ! 408: o->reg_o = SPREG; ! 409: o->value_o = offset; ! 410: installinstruct(n, sopcode("lea")); ! 411: } ! 412: continue; ! 413: } ! 414: } ! 415: ! 416: /* ! 417: * Pattern #1: ! 418: * (b) movl X,sp@- ! 419: * ... ! 420: * (n) <op> sp@+,... ! 421: * ! 422: * if possible, rewrite as ! 423: * (b) (deleted) ! 424: * ... ! 425: * (n) <op> X,... ! 426: * ! 427: * Requirements: ! 428: * X must not be a control register or i/o device. ! 429: * X must not be modified in the interim. ! 430: * Side effects of X must not be used in the interim. ! 431: */ ! 432: if (ISINSTRUC(n->op) && n->ref[0] != NULL && ispopop(n->ref[0])) { ! 433: b = n; ! 434: o = NULL; ! 435: do { ! 436: previ(b); ! 437: if (b->op == OP_FIRST || b->op == OP_LABEL ! 438: || ISBRANCH(b->op)) { ! 439: /* flow of control to reach this point is unknown */ ! 440: break; ! 441: } ! 442: if (b->op == OP_PEA) { ! 443: switch(b->ref[0]->type_o) { ! 444: case T_ABSS: ! 445: case T_ABSL: ! 446: case T_NORMAL: ! 447: /* ! 448: * srce is #X ! 449: */ ! 450: o = newoperand(b->ref[0]); ! 451: o->type_o = T_IMMED; ! 452: b->subop = SUBOP_L; ! 453: } ! 454: break; ! 455: } ! 456: if (b->op == OP_CLR && ispushop(b->ref[0])) { ! 457: /* ! 458: * srce is #0 ! 459: */ ! 460: o = newoperand(b->ref[0]); ! 461: o->type_o = T_IMMED; ! 462: o->value_o = 0; ! 463: break; ! 464: } ! 465: if (b->op == OP_MOVE && ispushop(b->ref[1])) { ! 466: o = newoperand(b->ref[0]); ! 467: break; ! 468: } ! 469: if (inmask(SPREG,b->rset) || inmask(SPREG,b->ruse)) { ! 470: /* unknown use/modification of sp */ ! 471: break; ! 472: } ! 473: } while(1); ! 474: /* ! 475: * If the preceding search yielded a usable operand, ! 476: * determine whether its use can be moved from node ! 477: * (b) to (n). ! 478: */ ! 479: if (o != NULL) { ! 480: l = submask(b->rset, MAKEWMASK(SPREG, LW)); ! 481: if ( o->type_o == T_REG && !datareg(o->value_o) ! 482: || o->type_o != T_IMMED && o->type_o != T_REG && !cancache(o) ! 483: || !emptymask(andmask(l, b->forw->rlive))) { ! 484: /* ! 485: * x is a control register or might be an i/o device, ! 486: * or has non-trivial side effects: cannot move. ! 487: */ ! 488: freeoperand(o); ! 489: o = NULL; ! 490: } else { ! 491: /* search for defs of X and defs affecting access to X */ ! 492: l = submask(b->ruse, MAKERMASK(SPREG, LR)); ! 493: p = n; ! 494: previ(p); ! 495: while (p != b) { ! 496: if (may_touch(p, o, b->subop, WMASK)) { ! 497: freeoperand(o); /* bail out */ ! 498: o = NULL; ! 499: break; ! 500: } ! 501: if (!emptymask(andmask(l, p->rset))) { ! 502: /* ! 503: * (p) defines register used at (b); if (p) ! 504: * is a simple register load, and if the lifetime ! 505: * of the register is restricted to (p)..(n), ! 506: * we may be able to use a different register, ! 507: * eliminating the conflict ! 508: */ ! 509: int r1,r2; ! 510: if (p->op != OP_MOVE ! 511: || p->ref[1]->type_o != T_REG ) { ! 512: freeoperand(o); /* bail out */ ! 513: o = NULL; ! 514: break; ! 515: } ! 516: r1 = p->ref[1]->value_o; ! 517: r2 = find_freereg(p, n, reg_access[r1]); ! 518: if (r2 == -1 || !can_reassign_reg(p, n, r1, r2)) { ! 519: freeoperand(o); /* bail out */ ! 520: o = NULL; ! 521: break; ! 522: } ! 523: reassign_reg(p, n, r1, r2); ! 524: } ! 525: previ(p); ! 526: } ! 527: } ! 528: } ! 529: /* ! 530: * If it is feasible to move the use of the operand X, ! 531: * find out whether X is a suitable source operand of ! 532: * the instruction at (n). ! 533: */ ! 534: if (o != NULL) { ! 535: if (BYTESIZE(b->subop) == BYTESIZE(n->subop) ! 536: && operand_ok(n->instr, o, n->ref[1], n->ref[2])) { ! 537: n = moveuse(b, n, o, n->instr); ! 538: changes++; ! 539: continue; ! 540: } ! 541: /* ! 542: * if X is a floating point register, try rewriting ! 543: * node (n) using an extended floating point opcode ! 544: */ ! 545: if (o->type_o == T_REG && freg(o->value_o)) { ! 546: ip = extendedop(n->instr); ! 547: if (ip != NULL ! 548: && operand_ok(ip, o, n->ref[1], n->ref[2])) { ! 549: n = moveuse(b, n, o, ip); ! 550: changes++; ! 551: continue; ! 552: } ! 553: } ! 554: /* ! 555: * if X is an addressable double operand and the ! 556: * the use of sp@+ occurs in a double precision ! 557: * floating point operation, use X directly. ! 558: */ ! 559: if (n->subop == SUBOP_D && o->type_o != T_REG ! 560: && b->back->op == OP_MOVE ! 561: && b->back->subop == SUBOP_L ! 562: && ispushop(b->back->ref[1]) ! 563: && adjacent(o, b->back->ref[0])) { ! 564: (void) deletenode(b->back); ! 565: n = moveuse(b, n, o, n->instr); ! 566: changes++; ! 567: continue; ! 568: } ! 569: freeoperand(o); /* give up */ ! 570: } /* if o != NULL */ ! 571: } /* if ISINSTRUCT... */ ! 572: ! 573: /* ! 574: * Other patterns assume the instruction at (n) is a move. ! 575: */ ! 576: if (n->op != OP_MOVE) ! 577: continue; ! 578: ! 579: /* ! 580: * Pattern #2: ! 581: * (b) move X,sp@- ! 582: * .... ! 583: * (n) move sp@+,rn ! 584: * If possible, rewrite as: ! 585: * (b) move X,rn ! 586: * .... ! 587: * (n) (deleted) ! 588: * Requirements: ! 589: * Rn must neither be used nor set in the interim. ! 590: * If rn is an a-register, condition codes must not ! 591: * be live immediately following (b). ! 592: * If rn is not an a-register, condition codes must not ! 593: * be live immediately following (n). ! 594: */ ! 595: o = n->ref[0]; ! 596: regno = n->ref[1]->value_o; ! 597: if(ispopop(o) && n->ref[1]->type_o == T_REG ! 598: && !(dreg(regno) && inmask(CCREG,n->forw->rlive)) ! 599: && !(freg(regno) && inmask(FPCCREG, n->forw->rlive))) { ! 600: b = n; ! 601: do { ! 602: previ(b); ! 603: if (b->op == OP_FIRST || b->op == OP_LABEL ! 604: || ISBRANCH(b->op)) { ! 605: /* flow of control to reach this point is unknown */ ! 606: break; ! 607: } ! 608: if (b->op == OP_PEA) { ! 609: /* note: PEA does not set the condition codes */ ! 610: if (areg(regno)) { ! 611: /* ! 612: * rewrite as: lea <srce>,areg ! 613: */ ! 614: n = movedef(b,n,sopcode("lea")); ! 615: changes++; ! 616: } else if ((r = dead_areg(b)) != -1 ! 617: && !inmask(CCREG,b->forw->rlive)) { ! 618: /* ! 619: * rewrite as: lea <srce>,areg; ! 620: * movl areg,rn ! 621: */ ! 622: n = movedef2(b,n,r,sopcode("lea")); ! 623: changes++; ! 624: } else { ! 625: switch(b->ref[0]->type_o) { ! 626: case T_ABSS: ! 627: case T_ABSL: ! 628: case T_NORMAL: ! 629: /* ! 630: * rewrite as: movl #<srce>,reg ! 631: */ ! 632: b->ref[0]->type_o = T_IMMED; ! 633: n = movedef(b,n,sopcode("movl")); ! 634: changes++; ! 635: } ! 636: } ! 637: break; ! 638: } ! 639: if (b->op == OP_CLR && ispushop(b->ref[0]) ! 640: && b->subop == SUBOP_L ! 641: && !(areg(regno) && inmask(CCREG,b->forw->rlive))) { ! 642: /* ! 643: * rewrite as: movl #0,reg ! 644: */ ! 645: b->ref[0]->type_o = T_IMMED; ! 646: b->ref[0]->value_o = 0; ! 647: n = movedef(b,n,sopcode("movl")); ! 648: changes++; ! 649: break; ! 650: } ! 651: if (b->op == OP_MOVE && ispushop(b->ref[1]) ! 652: && b->subop == SUBOP_L ! 653: && !(areg(regno) && inmask(CCREG,b->forw->rlive))) { ! 654: /* ! 655: * try to change into MOVE <srce>,reg ! 656: * beware floating point register operands ! 657: */ ! 658: if (!freg(regno)) { ! 659: /* reg is a-reg or d-reg */ ! 660: if (b->subop == SUBOP_D || b->subop == SUBOP_X) { ! 661: /* can't move doubles to a register pair */ ! 662: } else if (areg(regno) ! 663: && b->ref[0]->type_o == T_REG ! 664: && freg(b->ref[0]->value_o)) { ! 665: /* can't move fp reg to a-reg */ ! 666: } else if (b->subop == n->subop) { ! 667: /* easy case */ ! 668: n = movedef(b,n,n->instr); ! 669: changes++; ! 670: } ! 671: } else { ! 672: o = b->ref[0]; ! 673: if (o->type_o == T_REG && freg(o->value_o)) { ! 674: /* ! 675: * freg-freg move ! 676: */ ! 677: n = movedef(b,n,sopcode("fmovex")); ! 678: } else if (b->subop == n->subop ! 679: && BYTESIZE(n->subop) <= sizeof(long) ! 680: && !(o->type_o == T_REG && areg(o->value_o))) { ! 681: /* ! 682: * move single word to freg ! 683: */ ! 684: n = movedef(b,n,n->instr); ! 685: changes++; ! 686: } else if (n->subop == SUBOP_D ! 687: && o->type_o != T_REG ! 688: && b->back->op == OP_MOVE ! 689: && b->back->subop == SUBOP_L ! 690: && ispushop(b->back->ref[1]) ! 691: && adjacent(o, b->back->ref[0])) { ! 692: /* ! 693: * move addressable double operand to freg ! 694: */ ! 695: (void) deletenode(b->back); ! 696: b->subop = SUBOP_D; ! 697: n = movedef(b,n,n->instr); ! 698: changes++; ! 699: } ! 700: /* else forget it! */ ! 701: } ! 702: break; ! 703: } ! 704: if (inmask(regno,b->rset) || inmask(regno,b->ruse)) { ! 705: /* dest reg was used or modified along the way */ ! 706: break; ! 707: } ! 708: if (inmask(SPREG,b->rset) || inmask(SPREG,b->ruse)) { ! 709: /* some other use/modification of sp */ ! 710: break; ! 711: } ! 712: } while(1); ! 713: } ! 714: ! 715: /* ! 716: * Pattern #3: ! 717: * (b) move sp@+,rn ! 718: * .... ! 719: * (n) move rn,sp@- ! 720: * ! 721: * if possible, rewrite as ! 722: * (b) move sp@,rn ! 723: * .... ! 724: * (n) (deleted) ! 725: * ! 726: * requirements: ! 727: * Rn must not be used or set in the interim. ! 728: * Condition codes must not be live after either (b) or (n). ! 729: */ ! 730: o = n->ref[1]; ! 731: if (ispushop(o) && n->ref[0]->type_o == T_REG ! 732: && datareg(n->ref[0]->value_o) ! 733: && !inmask(CCREG,n->forw->rlive) ! 734: && !inmask(FPCCREG, n->forw->rlive)) { ! 735: regno = n->ref[0]->value_o; ! 736: b = n; ! 737: do { ! 738: previ(b); ! 739: if (b->op == OP_FIRST || b->op == OP_LABEL ! 740: || ISBRANCH(b->op)) { ! 741: /* flow of control to reach this point is unknown */ ! 742: break; ! 743: } ! 744: if (b->op == OP_MOVE && ispopop(b->ref[0]) ! 745: && b->subop == n->subop ! 746: && sameops(b->ref[1], n->ref[0]) ! 747: && !inmask(CCREG, b->forw->rlive) ! 748: && !inmask(FPCCREG, b->forw->rlive)) { ! 749: /* pushing same value that was just popped */ ! 750: n = deletenode(n); ! 751: b->ref[0]->type_o = T_DEFER; ! 752: installinstruct(b, b->instr); ! 753: l = n->forw->rlive; ! 754: for (p = n; p != b; p = p->back) { ! 755: l = p->rlive = compute_normal(p, l); ! 756: } ! 757: changes++; ! 758: break; ! 759: } ! 760: if (inmask(regno,b->rset) || inmask(regno,b->ruse)) { ! 761: /* reg was used/modified along the way */ ! 762: break; ! 763: } ! 764: if (inmask(SPREG,b->rset) || inmask(SPREG,b->ruse)) { ! 765: /* some other use/modification of sp */ ! 766: break; ! 767: } ! 768: } while(1); ! 769: } /* if */ ! 770: ! 771: } /* for */ ! 772: return(changes); ! 773: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.