|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)instruction.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 "as.h" ! 10: #include "c2.h" ! 11: ! 12: extern char *malloc(); ! 13: struct oper *newoperand(); ! 14: struct oper operands[OPERANDS_MAX]; ! 15: int numops; ! 16: void new_csect(), save_stabs(); ! 17: ! 18: NODE first = { OP_FIRST, SUBOP_Z, &first, &first }; ! 19: ! 20: #define nexti( p ) { do p=p->forw; while( ISDIRECTIVE(p->op) ); } ! 21: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); } ! 22: ! 23: extern int bytesize[]; ! 24: #define BYTESIZE( s ) (bytesize[ (int)(s)]) ! 25: ! 26: /* does this branch read the c or v bit of the condition code? */ ! 27: char read_cc_cv[]={ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 }; ! 28: static struct ins_bkt * moveq = NULL; ! 29: static err_code operand_error = E_NOERROR; ! 30: ! 31: extern struct ins_bkt *tstw, *tstl; ! 32: extern int ext_instruction_set; ! 33: ! 34: static int ! 35: numeric_immediate( op ) ! 36: struct oper *op; ! 37: { ! 38: if (op->type_o != T_IMMED || op->sym_o != NULL ) ! 39: return 0; ! 40: return 1; ! 41: } ! 42: ! 43: static int ! 44: immediate_value( op, value ) ! 45: struct oper *op; ! 46: int value; ! 47: { ! 48: if (op->type_o != T_IMMED || op->sym_o != NULL || op->flags_o&O_FLOAT || op->value_o != value) ! 49: return 0; ! 50: return 1; ! 51: } ! 52: ! 53: instruction( ip ) ! 54: struct ins_bkt *ip; ! 55: { ! 56: register NODE *np; ! 57: register i; ! 58: ! 59: if (ip->noper_i != numops && ip->noper_i <= OPERANDS_MAX){ ! 60: /* shifts are a special case...*/ ! 61: if ((ip->touchop_i&TOUCHMASK) == SPEC(2) || numops==1 || ip->subop_i==SUBOP_W) ! 62: i = 0; ! 63: else if ( (ip->touchop_i&TOUCH1(TOUCHMASK)) == TOUCH1(SPEC(7)) && numops==0 ) ! 64: /* so is rts */ ! 65: i = 0; ! 66: else ! 67: prog_error(E_NUMOPS); ! 68: } ! 69: if ( ISINSTRUC(ip->op_i) ){ ! 70: if (cur_csect_name != C_TEXT){ ! 71: /* non-text is not delt with -- echo it out directly */ ! 72: putinstr( ip ); ! 73: /* instruction in data space -- punt addressing */ ! 74: bc = 0x80000000; /* magic, negative number */ ! 75: return; ! 76: } ! 77: switch (numops){ ! 78: case 0: i = 1; break; ! 79: case 1: i = operand_ok( ip, &operands[0], (struct oper *)NULL, (struct oper *)NULL ); break; ! 80: case 2: i = operand_ok( ip, &operands[0], &operands[1], (struct oper *)NULL );break; ! 81: case 3: i = operand_ok( ip, &operands[0], &operands[1], &operands[2] );break; ! 82: } ! 83: if (!i) ! 84: prog_warning(operand_error); ! 85: } else { ! 86: switch ( ip->op_i ){ ! 87: case OP_TEXT: cur_csect_name = C_TEXT; new_csect(); return; ! 88: case OP_DATA: cur_csect_name = C_DATA; new_csect(); break; ! 89: case OP_DATA1: cur_csect_name = C_DATA1; new_csect(); break; ! 90: case OP_DATA2: cur_csect_name = C_DATA2; new_csect(); break; ! 91: case OP_BSS: cur_csect_name = C_BSS; new_csect(); break; ! 92: case OP_ASCII: ! 93: case OP_ASCIZ: bc += ascii(cur_csect_name)+(ip->op_i==OP_ASCIZ); break; ! 94: case OP_STABS: save_stabs(cur_csect_name); break; ! 95: default: bc += pseudo_size( ip ); break; ! 96: } ! 97: if (cur_csect_name != C_TEXT){ ! 98: /* non-text is not delt with -- echo it out directly */ ! 99: putinstr( ip ); ! 100: return; ! 101: } ! 102: } ! 103: np = new(); ! 104: np->nref = numops; ! 105: for (i=0; i<numops; i++){ ! 106: np->ref[i] = newoperand( &operands[i] ); ! 107: } ! 108: installinstruct( np, ip ); ! 109: addnode( np ); ! 110: } ! 111: ! 112: unsigned short ! 113: make_touchop( np, to ) ! 114: NODE *np; ! 115: unsigned short to; ! 116: { ! 117: /* ripped off from installinstruct, but not yet used by it */ ! 118: int i; ! 119: unsigned short tfield, tretval; ! 120: struct oper *o; ! 121: ! 122: tretval = 0; ! 123: for (i=np->nref-1; i >= 0; i--){ ! 124: o = np->ref[i]; ! 125: switch(tfield = (to>>(TOUCHWIDTH*i))&TOUCHMASK){ ! 126: case SPEC(0): /* bset, bclr, bcng */ ! 127: if (o->type_o==T_REG){ ! 128: tfield = touchselect(np->ref[0], BR+BW, WR+WW, LR+LW); ! 129: } else{ ! 130: tfield = (BR+BW); ! 131: } ! 132: break; ! 133: case SPEC(1): /* btst */ ! 134: if (o->type_o==T_REG){ ! 135: tfield = touchselect(np->ref[0], BR, WR, LR); ! 136: } else { ! 137: tfield = (BR); ! 138: } ! 139: break; ! 140: case SPEC(2): /* shifts */ ! 141: if (np->nref==1) ! 142: tfield = (WR+WW); ! 143: else ! 144: tfield = (WR); ! 145: break; ! 146: case SPEC(3): /* pea, link, unlk */ ! 147: tfield = 0; ! 148: break; ! 149: case SPEC(4): /* bfset bfins */ ! 150: tfield = (LW); ! 151: break; ! 152: case SPEC(5): /* bfext? bftst */ ! 153: tfield = (LR); ! 154: break; ! 155: case SPEC(6): /* mulsl, divsll */ ! 156: tfield = (LR+LW); ! 157: break; ! 158: } ! 159: tretval <<= TOUCHWIDTH; ! 160: tretval |= tfield; ! 161: } ! 162: return tretval; ! 163: } ! 164: ! 165: static int ! 166: touchselect( operand, b, w, l ) ! 167: struct oper *operand; ! 168: { ! 169: register v; ! 170: if (!numeric_immediate( operand )) return l; ! 171: v = operand->value_o; ! 172: if ( v >=0 && v < 16 ) ! 173: if (v < 8 ) return b; ! 174: else return w; ! 175: else return l; ! 176: } ! 177: ! 178: static subop_t ! 179: subopselect( touchword ) ! 180: { ! 181: switch (touchword&TOUCHMASK) { ! 182: case BR: ! 183: case BW: ! 184: case BR+BW: ! 185: return SUBOP_B; ! 186: case WR: ! 187: case WW: ! 188: case WR+WW: ! 189: return SUBOP_W; ! 190: } ! 191: return SUBOP_L; ! 192: } ! 193: ! 194: void ! 195: cannibalize( np, sp ) ! 196: NODE *np; ! 197: char *sp; ! 198: { ! 199: installinstruct( np, sopcode(sp) ); ! 200: } ! 201: ! 202: installinstruct( np, ip ) ! 203: register NODE *np; ! 204: register struct ins_bkt *ip; ! 205: { ! 206: register struct oper *o; ! 207: register unsigned short touchop; ! 208: regmask smask, umask; ! 209: register i; ! 210: static int regnames[] = { ! 211: D0REG, D0REG+1, ! 212: A0REG, A0REG+1, ! 213: FP0REG, FP0REG+1 ! 214: }; ! 215: ! 216: np->instr = ip; ! 217: np->op = ip->op_i; ! 218: np->subop = ip->subop_i; ! 219: umask = MAKERMASK( CCREG, (ip->cc_i&CCR)?BR:0); ! 220: smask = MAKEWMASK( CCREG, (ip->cc_i&CCX)?BW:0); ! 221: if (ip->cc_i&FCCR) umask = addmask( umask, MAKERMASK( FPCCREG, BR)); ! 222: if (ip->cc_i&FCC) smask = addmask( smask, MAKEWMASK( FPCCREG, BW)); ! 223: switch (np->op){ ! 224: case OP_CALL: /* writes d0,d1,a0,a1 except with exceptions */ ! 225: o = np->ref[0]; ! 226: if ( o->type_o == T_NORMAL && o->value_o==0 ){ ! 227: struct sym_bkt *s; ! 228: s = o->sym_o; ! 229: if (s->attr_s & S_CRT){ ! 230: /* ! 231: * c- runtime support routine -- some of these may touch ! 232: * the floating point registers, but as of 3.0 they are ! 233: * not called by programs that use them. ! 234: */ ! 235: for (i=0; i<4; i++ ){ ! 236: umask = addmask( umask, MAKERMASK( regnames[i], s->builtin_s[i] )); ! 237: smask = addmask( smask, MAKEWMASK( regnames[i], s->builtin_s[i] )); ! 238: } ! 239: break; ! 240: } ! 241: } ! 242: /* normal routine -- write d0,d1,a0,a1,fp0,fp1 */ ! 243: for (i=0; i<6; i++){ ! 244: smask = addmask(smask,MAKEWMASK( regnames[i], LW )); ! 245: } ! 246: break; ! 247: case OP_EXIT: /* reads some registers, writes all */ ! 248: umask = addmask(exitmask, regmask_nontemp); ! 249: smask = regmask_all; ! 250: break; ! 251: } ! 252: touchop = ip->touchop_i; ! 253: for (i=0; i<np->nref; i++, touchop >>= TOUCHWIDTH ){ ! 254: o = np->ref[i]; ! 255: switch(touchop&TOUCHMASK){ ! 256: case SPEC(0): /* bset, bclr, bcng */ ! 257: if (o->type_o==T_REG){ ! 258: touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR+BW, WR+WW, LR+LW); ! 259: } else{ ! 260: touchop = (touchop&~TOUCHMASK)|(BR+BW); ! 261: } ! 262: np->subop = subopselect( touchop ); ! 263: break; ! 264: case SPEC(1): /* btst */ ! 265: if (o->type_o==T_REG){ ! 266: touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR, WR, LR); ! 267: } else { ! 268: touchop = (touchop&~TOUCHMASK)|(BR); ! 269: } ! 270: np->subop = subopselect( touchop ); ! 271: break; ! 272: case SPEC(2): /* shifts */ ! 273: if (np->nref==1) ! 274: touchop = (touchop&~TOUCHMASK)|(WR+WW); ! 275: else ! 276: touchop = (touchop&~TOUCHMASK)|(WR); ! 277: break; ! 278: case SPEC(3): /* pea, link, unlk */ ! 279: smask = MAKEWMASK( SPREG, LW ); ! 280: /* umask = MAKERMASK( SPREG, LR ); */ ! 281: /* the unlk instruction does not read sp before setting it */ ! 282: umask = (ip->op_i == OP_UNLK) ? regmask0 : smask; ! 283: touchop = LR+LW; /* link and unlk use this */ ! 284: break; ! 285: case SPEC(4): /* bfset bfins */ ! 286: touchop = (touchop&~TOUCHMASK)|(LW); ! 287: break; ! 288: case SPEC(5): /* bfext? bftst */ ! 289: touchop = (touchop&~TOUCHMASK)|(LR); ! 290: break; ! 291: case SPEC(6): /* mulsl, divsll */ ! 292: if (o->type_o != T_REGPAIR){ ! 293: touchop = (touchop&~TOUCHMASK)|(LR+LW); ! 294: break; ! 295: } else { ! 296: /* 1st register of pair written only */ ! 297: smask = addmask( smask, MAKEWMASK( o->value_o, LW )); ! 298: /* 2nd register of pair read+written */ ! 299: umask = addmask( umask, MAKERMASK( o->reg_o, LR )); ! 300: smask = addmask( smask, MAKEWMASK( o->reg_o, LW )); ! 301: continue; ! 302: } ! 303: } ! 304: switch (o->type_o ){ ! 305: case T_REGPAIR: ! 306: umask = addmask( umask, MAKERMASK( o->reg_o, touchop )); ! 307: smask = addmask( smask, MAKEWMASK( o->reg_o, touchop )); ! 308: /* FALL THROUGH */ ! 309: case T_REG: ! 310: if (dareg( o->value_o ) || srreg( o->value_o) || freg( o->value_o)){ ! 311: umask = addmask( umask, MAKERMASK( o->value_o, touchop )); ! 312: smask = addmask( smask, MAKEWMASK( o->value_o, touchop )); ! 313: } ! 314: break; ! 315: case T_POSTINC: ! 316: case T_PREDEC: ! 317: smask = addmask( smask, MAKEWMASK( o->value_o, LW )); ! 318: /* FALL THROUGH */ ! 319: case T_DEFER: ! 320: umask = addmask( umask, MAKERMASK( o->value_o, LR )); ! 321: break; ! 322: case T_DISPL: ! 323: umask = addmask( umask, MAKERMASK( o->reg_o, LR )); ! 324: break; ! 325: case T_INDEX: ! 326: if (! (o->flags_o & O_BSUPRESS)) ! 327: umask = addmask( umask, MAKERMASK( o->reg_o, LR )); ! 328: if ( o->flags_o & (O_PREINDEX|O_POSTINDEX)) ! 329: umask = addmask( umask, MAKERMASK( o->value_o, ! 330: o->flags_o&O_LINDEX ? LR : WR )); ! 331: break; ! 332: } ! 333: if (o->flags_o & O_BFLD){ ! 334: if (o->flags_o & O_BFOREG) ! 335: umask = addmask( umask, MAKERMASK( o->bfoffset_o, BR )); ! 336: if (o->flags_o & O_BFWREG) ! 337: umask = addmask( umask, MAKERMASK( o->bfwidth_o, BR )); ! 338: } ! 339: } ! 340: np->ruse = umask; ! 341: np->rset = smask; ! 342: } ! 343: ! 344: static unsigned ! 345: op_to_bits( op ) ! 346: register struct oper *op; ! 347: { ! 348: /* return the address-mode bits for operand *op */ ! 349: register unsigned s; ! 350: static unsigned bits[] = { ! 351: 0, ! 352: AM_REG, AM_DEFER, AM_POSTINC, AM_PREDEC, AM_DISPL, ! 353: AM_INDEX, AM_ABSS, AM_ABSL, AM_IMMED, AM_NORMAL, ! 354: AM_REGPAIR, -1, -1 ! 355: }; ! 356: switch ( s = bits[(int)op->type_o]){ ! 357: case AM_REG: ! 358: s = reg_access[op->value_o]; break; ! 359: case AM_DISPL: ! 360: if (op->reg_o == PCREG) s = AM_PCDISPL; break; ! 361: case AM_INDEX: ! 362: if (op->reg_o == PCREG) s = AM_PCINDEX; break; ! 363: } ! 364: return s; ! 365: } ! 366: ! 367: int ! 368: operand_ok( ip, op1, op2, op3 ) ! 369: struct ins_bkt *ip; ! 370: struct oper *op1, *op2, *op3; ! 371: { ! 372: /* ! 373: * this routine answers the eternal question: ! 374: * are operands *op1 and *op2 ok to use as the operands of instruction *ip? ! 375: * it does it by looking at the optype_i bit fields in the instruction ! 376: * description. ! 377: */ ! 378: register i; ! 379: register unsigned opbits1, opbits2, opbits3; ! 380: register noperands = ip->noper_i; ! 381: ! 382: opbits1 = op_to_bits( op1 ); ! 383: if (op2) ! 384: opbits2 = op_to_bits( op2 ); ! 385: else ! 386: opbits2 = 0; ! 387: if (op3) ! 388: opbits3 = op_to_bits( op3 ); ! 389: else ! 390: opbits3 = 0; ! 391: switch (ip->touchop_i&TOUCH2(TOUCHMASK)){ ! 392: case TOUCH2(SPEC(0)): ! 393: case TOUCH2(SPEC(1)): ! 394: /* special hackery for bit ops */ ! 395: if (opbits1 == AM_IMMED){ ! 396: i = op1->value_o; ! 397: if (op1->sym_o) { operand_error = E_CONSTANT; return 0;} ! 398: if (opbits2 == AM_DREG){ ! 399: if (i < 0 || i > 31 ) { operand_error = E_CONSTANT; return 0;} ! 400: } else ! 401: if (i < 0 || i > 7 ) { operand_error = E_CONSTANT; return 0;} ! 402: } ! 403: break; ! 404: } ! 405: switch (ip->touchop_i&TOUCH1(TOUCHMASK)){ ! 406: case TOUCH1(SPEC(2)): ! 407: /* special hackery for shifts */ ! 408: if (opbits1 == AM_IMMED && ((i=op1->value_o)<1 || i>8 || op1->sym_o)){ ! 409: operand_error = E_CONSTANT; ! 410: return 0; ! 411: } ! 412: break; ! 413: } ! 414: switch (noperands){ ! 415: case 0: return 1; ! 416: case 1: ! 417: if ((ip == tstw || ip == tstl) && areg_addr(op1) ! 418: && !ext_instruction_set) ! 419: break; ! 420: for (i=0; i<N_OPTYPES; i+=1) ! 421: if ((opbits1&ip->optype_i[i])==opbits1) return 1; ! 422: break; ! 423: case 2: ! 424: for (i=0; i<N_OPTYPES; i+=2) ! 425: if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) ) return 1; ! 426: break; ! 427: case 3: ! 428: for (i=0; i<N_OPTYPES; i+=3) ! 429: if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) && ((opbits3&ip->optype_i[i+2])==opbits3) ) return 1; ! 430: break; ! 431: } ! 432: operand_error = E_OPERAND; ! 433: return 0; ! 434: } ! 435: onceonly() ! 436: { ! 437: /* ! 438: * A collection of context-free, compiler specific hacks ! 439: * we need only do once, as circumstances will not change ! 440: * during the course of our work. These include: ! 441: * - moveml's: deleting those that do nothing, replacing the degenerate ! 442: * cases with movl's. ! 443: * - link a6,#0 ... addl #X,sp: combine if X in range of the link. ! 444: * - pea 0 : becomes clrl sp@- ! 445: * - cmpX #0,Y : becomes tstX Y, for Y not an address register. ! 446: * - movX #0,Y : becomes clrX Y, for Y not a register, or ! 447: * moveq #0,Y, for type long data register, or ! 448: * subl Y,Y for Y an address register. ! 449: */ ! 450: ! 451: register NODE * n; ! 452: register NODE *f; ! 453: register i, v; ! 454: register struct oper *o; ! 455: int regno; ! 456: extern NODE *deletenode(); ! 457: ! 458: for (n=first.forw; n != &first; n=n->forw){ ! 459: switch( n->op){ ! 460: case OP_MOVEM: ! 461: if (n->subop==SUBOP_L || n->subop==SUBOP_X) { ! 462: /* i get the index of the immediate operand */ ! 463: i = (n->ref[1]->type_o==T_IMMED); ! 464: /* o get the pointer to the immediate operand */ ! 465: o = n->ref[i]; ! 466: if (o->sym_o || o->type_o!=T_IMMED) continue; ! 467: /* v gets the register mask -- how many bits set here? */ ! 468: switch( cntbits( v=o->value_o ) ){ ! 469: case 0: ! 470: if (deladdr(n->ref[1-i])){ ! 471: n = deletenode( n ); ! 472: meter.nrmtfr++; ! 473: } ! 474: break; ! 475: case 1: /* replace with a moveml, same "other" operand */ ! 476: v = ffs(v); /* find first bit set -- "1" on littleend */ ! 477: /* if mode of "other" operand is predecrement, bits work backwards */ ! 478: o->type_o=T_REG; ! 479: if (n->subop==SUBOP_L){ ! 480: if (n->ref[1-i]->type_o==T_PREDEC) ! 481: v = 16 - v; ! 482: o->value_o = v-1; ! 483: cannibalize( n, "movl" ); ! 484: }else{ ! 485: o->value_o = FP0REG + 8 - v; ! 486: cannibalize( n, "fmovex" ); ! 487: } ! 488: meter.nmmtmo++; ! 489: break; ! 490: } ! 491: } ! 492: continue; ! 493: case OP_LINK: ! 494: /* make sure we understand this instruction */ ! 495: o = n->ref[1]; ! 496: if (!numeric_immediate(o)) continue; ! 497: v = o->value_o; ! 498: /* see if next instruction is of form: addl #nnn,sp */ ! 499: f = n; ! 500: nexti(f); ! 501: if (f->op!=OP_ADD) continue; ! 502: o = f->ref[0]; ! 503: if (!numeric_immediate(o)) continue; ! 504: v += o->value_o; ! 505: o = f->ref[1]; ! 506: if (!(o->type_o==T_REG && o->value_o==SPREG)) continue; ! 507: /* make sure sum of immediates is in range */ ! 508: if (v <-32768 || v > 32767) continue; ! 509: /* got it! */ ! 510: n->ref[1]->value_o = v; ! 511: n = deletenode( f ); ! 512: meter.namwl++; ! 513: continue; ! 514: case OP_PEA: ! 515: /* if operand is a "normal" 0, change the opcode */ ! 516: o = n->ref[0]; ! 517: if (o->type_o==T_NORMAL && o->sym_o==NULL && o->value_o==0){ ! 518: o->type_o = T_PREDEC; ! 519: o->value_o = SPREG; ! 520: cannibalize( n, "clrl" ); ! 521: meter.nmtoc++; ! 522: } ! 523: continue; ! 524: case OP_CMP: ! 525: /* compares to zero are degenerate */ ! 526: o = n->ref[0]; ! 527: if (immediate_value( o, 0)){ ! 528: if (areg_addr(n->ref[1])){ ! 529: /* "A" register ! 530: * may be able to do something about this later on, ! 531: * after we gain some context. ! 532: */ ! 533: continue; ! 534: } else { ! 535: n->ref[0] = n->ref[1]; ! 536: n->nref--; ! 537: freeoperand( o ); ! 538: cannibalize( n, (n->subop==SUBOP_L)?"tstl" ! 539: :(n->subop==SUBOP_W)?"tstw" ! 540: : "tstb"); ! 541: meter.nctot++; ! 542: } ! 543: } ! 544: continue; ! 545: case OP_MOVE: ! 546: /* moves of zero can often be simplified */ ! 547: o = n->ref[0]; ! 548: if (immediate_value(o, 0)){ ! 549: switch (n->ref[1]->type_o){ ! 550: case T_REG: ! 551: v = n->ref[1]->value_o; ! 552: if (dreg(v) ){ ! 553: if (n->subop != SUBOP_L) goto mkclr; ! 554: /* use moveq */ ! 555: cannibalize( n, "moveq" ); ! 556: meter.nwmov++; ! 557: } else if (areg(v)){ ! 558: /* subtract from self */ ! 559: o->type_o = T_REG; ! 560: o->value_o = v; ! 561: cannibalize( n , "subl" ); ! 562: meter.nmtos++; ! 563: } ! 564: break; ! 565: default: ! 566: mkclr: ! 567: /* use the clear instruction */ ! 568: n->ref[0] = n->ref[1]; ! 569: n->nref--; ! 570: freeoperand( o ); ! 571: cannibalize( n, (n->subop==SUBOP_L)?"clrl" ! 572: :(n->subop==SUBOP_W)?"clrw" ! 573: : "clrb"); ! 574: meter.nmtoc++; ! 575: break; ! 576: } ! 577: } ! 578: continue; ! 579: case OP_AND: ! 580: /* ! 581: * if this looks like a mask of the lower bits, ! 582: * then it kill the rest of the register without ! 583: * reading it: i.e. ! 584: * andl #255,d0 ! 585: * only uses the low-order 8bits anyway, so we can ! 586: * change our usage mask. ! 587: */ ! 588: if (numeric_immediate(o=n->ref[0])){ ! 589: v = o->value_o; ! 590: if ((o=n->ref[1])->type_o==T_REG){ ! 591: regno = o->value_o; ! 592: if ( v>= 0 && v <= 0xffff && dreg(regno) ){ ! 593: n->ruse = submask( n->ruse, MAKERMASK( regno, LR )); ! 594: n->ruse = addmask( n->ruse, MAKERMASK( regno, v<=0xff ? BR : WR )); ! 595: n->rlive = compute_normal( n, n->forw->rlive); ! 596: } ! 597: } ! 598: } ! 599: continue; ! 600: } ! 601: } ! 602: } ! 603: ! 604: int ! 605: addr_delt( old, new ) ! 606: subop_t old, new; ! 607: { ! 608: #define NO_WAY -32768 ! 609: /* ! 610: * if an operand was addressed using subop "old", and will be ! 611: * addressed by "new", what is the address increment? ! 612: */ ! 613: static char deltsize[7][7] = { ! 614: /* new is ... B W L S D X P */ ! 615: /* old is ... */ ! 616: /* B */ { 0, -1, -3, -3, -7, -11, -11 }, ! 617: /* W */ { 1, 0, -2, -2, -6, -10, -10 }, ! 618: /* L */ { 3, 2, 0, 0, -4, -8, -8 }, ! 619: /* S */ { 3, 2, 0, 0, -4, -8, -8 }, ! 620: /* D */ { 7, 6, 4, 4, 0, -4, -4 }, ! 621: /* X */ { 11, 10, 8, 8, 4, 0, 0 }, ! 622: /* P */ { 11, 10, 8, 8, 4, 0, 0 }, ! 623: }; ! 624: ! 625: switch ( old ){ ! 626: case SUBOP_B: ! 627: case SUBOP_W: ! 628: case SUBOP_L: ! 629: break; ! 630: default: return NO_WAY; ! 631: } ! 632: switch ( new ){ ! 633: case SUBOP_B: ! 634: case SUBOP_W: ! 635: case SUBOP_L: ! 636: break; ! 637: default: return NO_WAY; ! 638: } ! 639: return deltsize[(int)old - (int)SUBOP_B][(int)new - (int)SUBOP_B]; ! 640: #undef NO_WAY ! 641: } ! 642: ! 643: int ! 644: long_immediate( opcode ) ! 645: opcode_t opcode; ! 646: { ! 647: /* ! 648: * list some of the opcodes in which immediate operands are long (addl), ! 649: * as opposed to those in which this is not the case (asrl). ! 650: */ ! 651: switch ( opcode ){ ! 652: case OP_ADD: ! 653: case OP_AND: ! 654: case OP_SUB: ! 655: case OP_MOVE: ! 656: case OP_CMP: ! 657: case OP_OR: ! 658: return 1; ! 659: } ! 660: return 0; ! 661: } ! 662: ! 663: static int ! 664: exception( p, pnext ) ! 665: NODE *p, *pnext; ! 666: { ! 667: if (p->instr==moveq && long_immediate(pnext->op )) ! 668: return 1; /* don't elide moveq's */ ! 669: if (pnext->op == OP_BOP){ ! 670: if (!numeric_immediate(pnext->ref[0])) return 1; /* be careful here */ ! 671: if (p->subop!=SUBOP_B) ! 672: if (p->ref[0]->type_o != T_REG && !cancache(p->ref[0])) ! 673: return 1; /* don't mess up memory references */ ! 674: } ! 675: return 0; ! 676: } ! 677: ! 678: /* ! 679: * have the pattern ! 680: * movX Y,d0 ! 681: * opZ d0,... ! 682: * where the second instruction only reads the operand, and we could ! 683: * have done ! 684: * opZ Y',... ! 685: * instead. ! 686: */ ! 687: static NODE * ! 688: elide_move( p, pnext, opset ) ! 689: register NODE *p; ! 690: register NODE *pnext; ! 691: int opset; ! 692: { ! 693: register i; ! 694: ! 695: for ( i=0 ; i<pnext->nref; i++) ! 696: if (opset & (1<<i)) ! 697: *pnext->ref[i] = *p->ref[0]; ! 698: installinstruct( pnext, pnext->instr ); ! 699: pnext->rlive = compute_normal(pnext,pnext->forw->rlive); ! 700: meter.redunm++; ! 701: return( deletenode( p )); ! 702: } ! 703: ! 704: /* ! 705: * look for dbra-equivalent sequence. The compiler ! 706: * already makes some assumptions about 16-bit reachability ! 707: * (word offsets in case-jumps), so we don't worry about that ! 708: * here. We're going to be rather strict about what we recognize, ! 709: * because we don't have the information to determine whether, ! 710: * for instance, an index begins positive, in which case we ! 711: * could recognize the condition " > 0 " as being equivalent ! 712: * to " != -1". Someday, perhaps. ! 713: * We will also be just a little adventuresome and try to ! 714: * handle the "long dbra" case, too. (Long is the data type, ! 715: * not the jump offset!) ! 716: */ ! 717: static NODE * ! 718: make_dbra( p, didchange ) ! 719: register NODE *p; ! 720: int *didchange; ! 721: { ! 722: register NODE *pnext; ! 723: NODE *p3; ! 724: register struct oper *o; ! 725: subop_t length; ! 726: static struct oper immed = { T_IMMED, 0,0,0, NULL, NULL, NULL, 0 }; ! 727: ! 728: /* recognize subqZ #1,dX */ ! 729: length = p->subop; ! 730: if (length == SUBOP_B) return p; ! 731: if ( !immediate_value((o=p->ref[0]), 1)) ! 732: return p; ! 733: o=p->ref[1]; ! 734: if (!dreg_addr(o)) return p; ! 735: pnext = p->forw; ! 736: switch (pnext->op){ ! 737: case OP_CMP: ! 738: /* recognize cmpZ #-1,dX */ ! 739: if (pnext->subop != length || ! 740: !immediate_value( pnext->ref[0], -1) || ! 741: !sameops( o, pnext->ref[1])) ! 742: return p; ! 743: /* recognize jne Y */ ! 744: pnext = pnext->forw; ! 745: if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p; ! 746: if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p; ! 747: /* ! 748: * found the pattern: ! 749: * subqX #1,dY <== p ! 750: * cmpX #-1,dY ! 751: * jne Z <== pnext ! 752: */ ! 753: /* save one copy of the operand register, delete much */ ! 754: p->nref --; ! 755: p = deletenode( p)->forw; ! 756: p = deletenode( p)->forw; ! 757: /* p == pnext */ ! 758: break; ! 759: case OP_TST: ! 760: /* try a different pattern */ ! 761: p3 = p->back; ! 762: if (p3->op != OP_MOVE || p3->subop != length || ! 763: !sameops( p3->ref[0], o) || !dreg_addr( p3->ref[1])) ! 764: return p; ! 765: if (pnext->subop != length || !sameops( p3->ref[1], pnext->ref[0])) ! 766: return p; ! 767: /* recognize jne Y */ ! 768: pnext = pnext->forw; ! 769: if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p; ! 770: if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p; ! 771: if (inmask( p3->ref[1]->value_o, pnext->rlive )) return p; ! 772: /* ! 773: * found the pattern: ! 774: * movX dY,dW <== p3 ! 775: * subqX #1,dY <== p ! 776: * tstX dW ! 777: * jne Y <== pnext ! 778: */ ! 779: /* save one copy of the operand register, delete much */ ! 780: (void) deletenode( p3 ); ! 781: p->nref --; ! 782: p = deletenode( p)->forw; ! 783: p = deletenode( p)->forw; ! 784: /* p == pnext */ ! 785: break; ! 786: default: ! 787: return p; ! 788: } ! 789: /* ! 790: * now: two cases here: simple and long: ! 791: * ! 792: * simple case: move operand o to the jump instruction; ! 793: * cannibalize it as a dbra; ! 794: * ! 795: * long case: as simple case, then add the long-dbra ! 796: * tail: clrw , cmpl, jcc. ! 797: */ ! 798: pnext->ref[0] = o; ! 799: pnext->nref++; ! 800: cannibalize( pnext, "dbra" ); ! 801: pnext->op = OP_DJMP; ! 802: if (length == SUBOP_L){ ! 803: /* add clrw dX instruction after that */ ! 804: pnext = new(); ! 805: pnext->nref = 1; ! 806: pnext->ref[0] = newoperand( o ); ! 807: insert( pnext, p); ! 808: cannibalize( pnext, "clrw" ); ! 809: /* add subql #1 instruction next */ ! 810: p3 = pnext; ! 811: pnext = new(); ! 812: pnext->nref = 2; ! 813: immed.value_o = 1; ! 814: pnext->ref[0] = newoperand( &immed ); ! 815: pnext->ref[1] = newoperand( o ); ! 816: insert( pnext, p3); ! 817: cannibalize( pnext, "subql" ); ! 818: /* finally, add jcc Y instruction */ ! 819: p3 = pnext; ! 820: pnext = new(); ! 821: insert( pnext, p3); ! 822: newreference( p->luse, pnext ); ! 823: cannibalize( pnext, "jcc" ); ! 824: pnext->op = OP_JUMP; ! 825: } ! 826: meter.ndbra++; ! 827: (*didchange)++; ! 828: return p; ! 829: } ! 830: ! 831: /* ! 832: * find out if operand *o uses the register r ! 833: */ ! 834: int ! 835: operand_uses( o, r ) ! 836: struct oper *o; ! 837: int r; ! 838: { ! 839: int t; ! 840: switch (o->type_o){ ! 841: case T_REG: ! 842: case T_DEFER: ! 843: case T_POSTINC: ! 844: case T_PREDEC: ! 845: return (o->value_o == r); ! 846: case T_DISPL: ! 847: return (o->reg_o == r); ! 848: case T_INDEX: ! 849: t = (o->flags_o & O_BSUPRESS)?0 : (o->reg_o == r); ! 850: t |= (o->flags_o & (O_PREINDEX|O_POSTINDEX))? (o->value_o == r) : 0; ! 851: return t; ! 852: case T_REGPAIR: ! 853: return (o->value_o == r || o->reg_o == r); ! 854: } ! 855: return 0; /* others don't use registers */ ! 856: } ! 857: ! 858: /* ! 859: * Look for arithmetic on an A register. Look for nearby uses of ! 860: * the same register using deferred addressing. See if we can combine ! 861: * them into postincrement or predecrement mode addressing. ! 862: */ ! 863: NODE * ! 864: plus_minus( p, didchange ) ! 865: register NODE *p; ! 866: int *didchange; ! 867: { ! 868: int incrval; ! 869: register int reg; ! 870: register NODE *q; ! 871: int found; ! 872: int i; ! 873: operand_t substitute; ! 874: register struct oper *o; ! 875: ! 876: if ( numeric_immediate( p->ref[0] ) && areg_addr( p->ref[1] ) ){ ! 877: incrval = p->ref[0]->value_o; ! 878: reg = p->ref[1]->value_o; ! 879: q = p; ! 880: found = 0; ! 881: if ( p->op == OP_ADD ){ ! 882: /* search backwards */ ! 883: substitute = T_POSTINC; ! 884: while ( (q=q->back)->op != OP_FIRST && q->op != OP_LABEL ! 885: && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){ ! 886: if (inmask( reg, q->ruse)){ ! 887: found = 1; ! 888: break; ! 889: } ! 890: } ! 891: } else { ! 892: /* search forwards */ ! 893: substitute = T_PREDEC; ! 894: while ( (q=q->forw)->op != OP_FIRST && q->op != OP_LABEL ! 895: && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){ ! 896: if (inmask( reg, q->ruse)){ ! 897: found = 1; ! 898: break; ! 899: } ! 900: } ! 901: } ! 902: if (found){ ! 903: /* ! 904: * we've found a nearby node that reads our register. ! 905: * it must now meet these criteria: ! 906: * -- the size of the access must agree with the size of the ! 907: * increment/decrement operation ! 908: * -- must not change the register (already checked) ! 909: * -- must use the register exactly once ! 910: * -- must use the register in a type T_DEFER operand ! 911: * -- must be able to take the substituted operand type ! 912: */ ! 913: switch (q->subop){ ! 914: case SUBOP_B: found = incrval==1; break; ! 915: case SUBOP_W: found = incrval==2; break; ! 916: case SUBOP_L: found = incrval==4; break; ! 917: case SUBOP_S: found = incrval==4; break; ! 918: case SUBOP_D: found = incrval==8; break; ! 919: case SUBOP_X: found = incrval==12; break; ! 920: default: found = 0; break; ! 921: } ! 922: if (found){ ! 923: found = 0; ! 924: for (i=0; i < q->nref; i++) ! 925: if (operand_uses( q->ref[i], reg)){ ! 926: found++; ! 927: o = q->ref[i]; ! 928: } ! 929: if (found == 1 && o->type_o == T_DEFER){ ! 930: o->type_o = substitute; ! 931: if (operand_ok(q->instr, q->ref[0], q->ref[1], q->ref[2] )){ ! 932: /* got it */ ! 933: p = deletenode( p ); ! 934: q->rset = addmask( q->rset, MAKEWMASK( reg, LW ) ); ! 935: *didchange++; ! 936: meter.nplusminus++; ! 937: } else { ! 938: /* blew it */ ! 939: o->type_o = T_DEFER; /* restore operand, go home */ ! 940: } ! 941: } ! 942: } ! 943: } ! 944: } ! 945: return p; ! 946: } ! 947: ! 948: int ! 949: shorten() ! 950: { ! 951: int nchanged = 0; ! 952: register NODE *p, *pnext; ! 953: NODE *pprev, *p3; ! 954: register struct oper *o; ! 955: register regno, t; ! 956: int didchange; ! 957: char *newname; ! 958: int i, newcc, opset; ! 959: int otherreg; ! 960: regmask m; ! 961: struct oper *trialops[OPERANDS_MAX]; ! 962: ! 963: /* ! 964: * delete instructions that do useless things: ! 965: * moves to registers or parts of registers that are dead; ! 966: * extends to parts of registers that are dead; ! 967: * reset the condition codes to its current value. ! 968: * also, anything that depends on context which might ! 969: * be changed by rearranging branchs: ! 970: * resetting condition codes, multiple shifts in a row, ! 971: * changing a "cmpl #0,A0" into a "movl A0,Di", where Di is dead. ! 972: * and the transformation ! 973: * - subqw #1,dX; cmpw #-1,dX; jne Y: becomes dbra dX,Y ! 974: * (most often requested hack). ! 975: */ ! 976: if (moveq==NULL) moveq = sopcode( "moveq" ); ! 977: didchange = 1; ! 978: while(didchange){ ! 979: didchange = 0; ! 980: for (p=first.forw; p != &first; p=p->forw){ ! 981: if (!ISINSTRUC(p->op)) continue; ! 982: if (!emptymask( submask(p->rset , addmask( p->forw->rlive, MAKERMASK( CCREG, LR)))) ){ ! 983: switch (p->op){ ! 984: case OP_CALL: ! 985: case OP_DBRA: ! 986: case OP_DJMP: ! 987: case OP_BRANCH: ! 988: case OP_JUMP: ! 989: break; ! 990: case OP_EXT: ! 991: /* ext's also set condition codes */ ! 992: if (!inmask( CCREG, p->forw->rlive)){ ! 993: /* useless extend -- simply delete it */ ! 994: p = deletenode( p ); ! 995: didchange++; ! 996: meter.nredext++; ! 997: } ! 998: break; ! 999: case OP_MOVE: ! 1000: /* be careful here -- useless set must be to a register */ ! 1001: /* for instance: movl #0,a0@+ sets a0, but we cannot change it */ ! 1002: o = p->ref[1]; /* object of move */ ! 1003: if (o->type_o != T_REG) break; ! 1004: if (!datareg(regno = o->value_o)) break; ! 1005: /* TEST FOR CC USAGE */ ! 1006: if ( dreg(regno) && inmask( CCREG, p->forw->rlive)) break; ! 1007: if ( freg(regno) && inmask( FPCCREG, p->forw->rlive)) break; ! 1008: switch (inmask(regno, p->forw->rlive)) { ! 1009: case 0: ! 1010: if (!deladdr( p->ref[0])) continue; /* side effects? */ ! 1011: /* totally useless -- fugg it */ ! 1012: p = deletenode( p ); ! 1013: didchange++; ! 1014: meter.redunm++; ! 1015: continue; ! 1016: case 1: /* BYTE ONLY */ ! 1017: newname = "movb"; ! 1018: t = (p->subop ==SUBOP_L )?3 : 1; /* could have been movw */ ! 1019: break; ! 1020: case 2: ! 1021: case 3: /* WORD ONLY */ ! 1022: newname = "movw"; ! 1023: t = 2; ! 1024: break; ! 1025: default: continue; ! 1026: } ! 1027: if ( freg(regno) ) break; /* don't rewrite fp moves */ ! 1028: if (incraddr( p->ref[0], t)) break;/* not ok */ ! 1029: if (p->instr == moveq) break; /* already moveq */ ! 1030: cannibalize( p, newname ); ! 1031: p->rlive = compute_normal( p, p->forw->rlive ); ! 1032: didchange++; ! 1033: meter.nwmov++; ! 1034: continue; ! 1035: case OP_AND: ! 1036: /* ! 1037: * if we're doing an AND to a dead register, it must be ! 1038: * for condition-code only (don't even bother to check). ! 1039: * if its only a single bit, change this to a btst. ! 1040: */ ! 1041: if ((o=p->ref[1])->type_o!=T_REG || !dreg(regno=o->value_o)) ! 1042: break; ! 1043: if (inmask(regno, p->forw->rlive)!=0) ! 1044: break; ! 1045: if (!numeric_immediate(o=p->ref[0])) ! 1046: break; ! 1047: if (cntbits( t = o->value_o ) == 1){ ! 1048: o->value_o = ffs(t)-1; ! 1049: cannibalize( p, "btst" ); ! 1050: p->rlive = compute_normal( p, p->forw->rlive ); ! 1051: didchange++; ! 1052: meter.nwop++; ! 1053: } ! 1054: break; ! 1055: } ! 1056: } ! 1057: switch (p->op){ ! 1058: case OP_MOVE: ! 1059: /* ! 1060: * If this is a move to a register which is only read once ! 1061: * by a following instruction, see if we can elide a move. ! 1062: * If this is a move to a register which is changed once ! 1063: * in the next instruction, then written back whence it ! 1064: * came, try doing the modify directly to the source ! 1065: * of it all. ! 1066: * If this is a move of a register to itself, and condition ! 1067: * codes are dead, elide the move. ! 1068: * SPECIAL HACK: the sequence ! 1069: * moveq #n, d0 ! 1070: * movl d0, XXX ! 1071: * is FASTER and shorter than the instruction ! 1072: * movl #n, XXX ! 1073: * DO NOT UNDO THIS OPTIMIZATION! ! 1074: */ ! 1075: if ((o=p->ref[1])->type_o != T_REG) break; ! 1076: regno = o->value_o; ! 1077: if ( p->ref[0]->type_o ==T_REG && p->ref[0]->value_o == regno){ ! 1078: /* either: ! 1079: * its a Dreg or Freg, and the condition code is useless, ! 1080: * or its an Areg, and we're not doing some funny ! 1081: * sign extension. ! 1082: */ ! 1083: if ( ((dreg(regno)||freg(regno)) && !inmask( CCREG, p->forw->rlive)) ! 1084: || (areg(regno) && p->subop == SUBOP_L)){ ! 1085: p = deletenode( p ); ! 1086: didchange++; ! 1087: meter.redunm++; ! 1088: break; ! 1089: } ! 1090: } ! 1091: newcc = 0; ! 1092: p3 = p; ! 1093: nexti(p3); ! 1094: for (pnext=p3; ISINSTRUC(pnext->op)||ISDIRECTIVE(pnext->op); pnext=pnext->forw){ ! 1095: if (ISDIRECTIVE(pnext->op)) continue; ! 1096: newcc = inmask( CCREG, pnext->rset ); ! 1097: if (inmask( regno, pnext->ruse)) break; ! 1098: if ((!newcc && inmask(CCREG, pnext->ruse )) || inmask( regno, pnext->rset)) ! 1099: goto no_cookie; ! 1100: if (!emptymask( andmask( pnext->rset,p->ruse)) || !emptymask( andmask( p->rset,pnext->ruse)) ) ! 1101: goto no_cookie; ! 1102: switch (pnext->op){ ! 1103: case OP_BRANCH: ! 1104: case OP_DBRA: ! 1105: case OP_JUMP: ! 1106: case OP_DJMP: ! 1107: goto no_cookie; ! 1108: } ! 1109: } ! 1110: if (!ISINSTRUC(pnext->op)) break; ! 1111: /* see if operands the same */ ! 1112: /* for each operand #i that is the same, opset gets bit 1<<i set */ ! 1113: opset = 0; ! 1114: for ( i=0 ; i<pnext->nref; i++) ! 1115: if (sameops( o, pnext->ref[i])) opset |= 1<<i; ! 1116: if (!opset) break; ! 1117: /* ! 1118: * We have only two cases we are smart enough to understand. ! 1119: * Either the two instructions are ajacent, in which case ! 1120: * there can have been no side effects in the intervening ! 1121: * (null) instructions, OR we're looking at this pattern: ! 1122: * movX Y,d0; ... ; opX d0,dZ ! 1123: * where dZ is not used between the moves. The reason for ! 1124: * this restriction is that it's too easy to break subtile ! 1125: * C constructs like post-incrementing, and too hard to detect ! 1126: * the general case. ! 1127: */ ! 1128: if (pnext==p3){ ! 1129: /* ! 1130: * see if register used after that instruction ! 1131: * make sure its a read-only access, and same size ! 1132: */ ! 1133: if (!inmask(regno, pnext->forw->rlive) && !inmask( regno, pnext->rset ) ){ ! 1134: t = addr_delt(p->subop, pnext->subop); ! 1135: for ( i=0 ; i<pnext->nref; i++) ! 1136: trialops[i] = (opset & (1<<i) ) ? p->ref[0] : pnext->ref[i]; ! 1137: for ( i ; i<OPERANDS_MAX; i++) ! 1138: trialops[i] = NULL; ! 1139: if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2])){ ! 1140: int ok = 0; ! 1141: if (t==0) { ! 1142: /* both instructions use same size data */ ! 1143: ok = 1; ! 1144: } else if (t>0 && !areg(regno)) { ! 1145: /* ! 1146: * second inst uses smaller data, and ! 1147: * doesn't depend on sign-extension. The ! 1148: * check on regno prevents us from changing ! 1149: * movl a6@(8),a0; cmpw #0,a0 | RIGHT ! 1150: * into ! 1151: * cmpw #0,a6@(10) | WRONG ! 1152: */ ! 1153: ok = !incraddr(p->ref[0],t); ! 1154: } ! 1155: if (ok && !exception( p, pnext)){ ! 1156: p = elide_move(p, pnext, opset); ! 1157: didchange++; ! 1158: break; ! 1159: } ! 1160: } else if (pnext->op == OP_BOP && ! 1161: numeric_immediate( pnext->ref[0] )){ ! 1162: /* ! 1163: * btst #t,d0 ! 1164: * take t modulo 8 ! 1165: */ ! 1166: t = pnext->ref[0]->value_o; ! 1167: pnext->ref[0]->value_o = t%8; ! 1168: if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2]) && ! 1169: !incraddr( p->ref[0], BYTESIZE(p->subop)-1-t/8 )){ ! 1170: /* it worked */ ! 1171: p = elide_move(p, pnext, opset); ! 1172: didchange++; ! 1173: break; ! 1174: } else { ! 1175: /* didn't work; put it back */ ! 1176: pnext->ref[0]->value_o = t; ! 1177: } ! 1178: ! 1179: } ! 1180: } ! 1181: }else{ ! 1182: if (pnext->nref!=2 || !dareg_addr(pnext->ref[1])) break; ! 1183: otherreg = pnext->ref[1]->value_o; ! 1184: for (p3=p->forw; p3!=pnext; p3=p3->forw){ ! 1185: if (inmask( otherreg, addmask(p3->ruse,p3->rset) )) break; ! 1186: } ! 1187: if (p3!=pnext ) break; ! 1188: if (!inmask( regno, pnext->forw->rlive ) && !inmask( CCREG, pnext->forw->rlive) ! 1189: && ! (inmask( regno, pnext->rset) || p->subop != pnext->subop )){ ! 1190: if ( operand_ok(pnext->instr,p->ref[0],pnext->ref[1], 0 )){ ! 1191: freeoperand( p->ref[1] ); ! 1192: p->ref[1] = pnext->ref[1]; ! 1193: installinstruct( p, pnext->instr ); ! 1194: pnext->nref=1; ! 1195: m = pnext->forw->rlive; ! 1196: for (p3=pnext->back; p3!=p; p3=p3->back) ! 1197: p3->rlive = m = compute_normal( p3, m); ! 1198: p->rlive = compute_normal(p, m ); ! 1199: (void) deletenode(pnext); ! 1200: didchange++; ! 1201: meter.redunm++; ! 1202: } ! 1203: } ! 1204: break; ! 1205: } ! 1206: ! 1207: /* see if the operand is written in the next instruction, ! 1208: * then moved back in the following, and dead thereafter ! 1209: */ ! 1210: no_cookie: ! 1211: if (inmask( regno, pnext->rset ) && (p3=pnext->forw)->op==OP_MOVE ! 1212: && sameops( o, p3->ref[0] ) ! 1213: && (pnext->nref== 1 || !sameops( o, pnext->ref[0] ) ) ! 1214: && sameops( p->ref[0], p3->ref[1] ) && !inmask(regno , p3->forw->rlive) ! 1215: && p->subop==pnext->subop && pnext->subop==p3->subop ) ! 1216: { ! 1217: if (pnext->nref==1 && operand_ok( pnext->instr, p->ref[0], NULL, 0 )){ ! 1218: /* looks like a negX d0 or notX d0 */ ! 1219: /* move p's operand to pnext */ ! 1220: freeoperand( pnext->ref[0] ); ! 1221: pnext->ref[0] = p->ref[0]; ! 1222: p->ref[0] = NULL; ! 1223: /* delete p and p3 */ ! 1224: p = deletenode( p ); ! 1225: (void )deletenode( p3 ); ! 1226: /* recompute register info */ ! 1227: installinstruct( pnext, pnext->instr ); ! 1228: pnext->rlive = compute_normal(pnext, pnext->forw->rlive ); ! 1229: didchange++; ! 1230: meter.redunm += 2; ! 1231: break; ! 1232: } else if (pnext->nref==2 && operand_ok( pnext->instr, pnext->ref[0], p->ref[0], 0 )){ ! 1233: /* looks like a addX #Y,d0 */ ! 1234: /* move p's operand to pnext */ ! 1235: freeoperand( pnext->ref[1] ); ! 1236: pnext->ref[1] = p->ref[0]; ! 1237: p->ref[0] = NULL; ! 1238: /* delete p and p3 */ ! 1239: p = deletenode( p ); ! 1240: (void )deletenode( p3 ); ! 1241: /* recompute register info */ ! 1242: installinstruct( pnext, pnext->instr ); ! 1243: pnext->rlive = compute_normal(pnext, pnext->forw->rlive ); ! 1244: didchange++; ! 1245: meter.redunm += 2; ! 1246: break; ! 1247: } else if (pnext->nref==2 && !inmask(regno , p3->forw->rlive) ! 1248: && operand_ok( pnext->instr, o, p->ref[0], 0 )){ ! 1249: /* ! 1250: * change: ! 1251: * movX A,d0 <== p ! 1252: * opX B,d0 <== pnext ! 1253: * movX d0,A <== p3 ! 1254: * into: ! 1255: * movX B,d0 <== p ! 1256: * opX d0,A <== pnext ! 1257: */ ! 1258: p->ref[0] = pnext->ref[0]; ! 1259: installinstruct( p, p->instr ); ! 1260: pnext->ref[0] = pnext->ref[1]; ! 1261: pnext->ref[1] = p3->ref[1]; ! 1262: p3->nref=1; ! 1263: (void)deletenode( p3 ); ! 1264: installinstruct( pnext, pnext->instr ); ! 1265: pnext->rlive = m = compute_normal( pnext, pnext->forw->rlive); ! 1266: p->rlive = compute_normal( p, m ); ! 1267: didchange++; ! 1268: meter.redunm ++; ! 1269: break; ! 1270: } ! 1271: } ! 1272: break; ! 1273: ! 1274: case OP_TST: ! 1275: /* ! 1276: * if a previous instruction touched this as an operand ! 1277: * AND set cc on it in a way we appreciate, then delete this ! 1278: * EXTRA HACKERY: ! 1279: * some instructions (e.g.: lsrl) set the condition codes ! 1280: * in a way that we can use MOST of the time. others ! 1281: * (esp moves) set the cond codes in a way that is ok ! 1282: * all of the time. If the previous instruction is not ! 1283: * a move, we will try to find the instruction checking ! 1284: * the cc, and decide if this is an extraordinary case. ! 1285: */ ! 1286: pprev = p; ! 1287: do{ ! 1288: previ( pprev ); ! 1289: } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) && ! 1290: !inmask(CCREG, p->rset)); ! 1291: if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break; ! 1292: /* integer cc is very funny -- floating cc very regular */ ! 1293: if (pprev->op!=OP_MOVE){ ! 1294: for( p3 = p->forw; p3->op != OP_FIRST; ){ ! 1295: switch (p3->op){ ! 1296: case OP_LABEL: ! 1297: nexti(p3); ! 1298: continue; ! 1299: case OP_JUMP: ! 1300: case OP_BRANCH: ! 1301: case OP_DBRA: ! 1302: case OP_DJMP: ! 1303: break; ! 1304: default: ! 1305: if (inmask( CCREG, p3->ruse)) ! 1306: break; ! 1307: nexti(p3); ! 1308: continue; ! 1309: } ! 1310: break; ! 1311: } ! 1312: if (!inmask( CCREG, p3->ruse)) break;/* cannot find user */ ! 1313: if (p3->op == OP_BRANCH || p3->op == OP_DBRA) ! 1314: break; /* too hard */ ! 1315: if (p3->op == OP_JUMP || p3->op == OP_DJMP){ ! 1316: if (inmask( CCREG, p3->luse->rlive)) break; /* double use */ ! 1317: if (p3->subop != JALL) ! 1318: if (inmask( CCREG, p3->forw->rlive)) break; /* double use */ ! 1319: } ! 1320: if (read_cc_cv[(int)p3->subop - (int)JEQ]) break; /* untrustworthy */ ! 1321: } ! 1322: o = p->ref[0]; ! 1323: if (!deladdr( o )) break; /* not ok to remove this reference */ ! 1324: /* ! 1325: * if we set condition codes on this, AND its not an ! 1326: * Areg (on which condition codes are never set, then ! 1327: * its ok to delete the test ! 1328: */ ! 1329: if (pprev->nref>=1 && sameops( pprev->ref[0], o)){ ! 1330: if (((pprev->instr->cc_i&CCX) == CC1) || ! 1331: ( pprev->op == OP_MOVE && !areg_addr( pprev->ref[1])) ){ ! 1332: p = deletenode( p ); ! 1333: didchange++; ! 1334: meter.nrtst++; ! 1335: } ! 1336: } else if (pprev->nref==2 && sameops( pprev->ref[1], o)){ ! 1337: if (((pprev->instr->cc_i&CCX) == CC2) && !areg_addr(o) ){ ! 1338: p = deletenode( p ); ! 1339: didchange++; ! 1340: meter.nrtst++; ! 1341: } ! 1342: } ! 1343: break; ! 1344: case OP_FTST: ! 1345: /* ! 1346: * Floating-point instructions always set their condition codes ! 1347: * on the result. The exception is that a move from the ! 1348: * coprocessor does not set the condition codes at all. ! 1349: */ ! 1350: /* see if we can find an instruction that sets fpcc */ ! 1351: pprev = p; ! 1352: do{ ! 1353: previ( pprev ); ! 1354: } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) && ! 1355: !inmask(FPCCREG, p->rset)); ! 1356: if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break; ! 1357: o = p->ref[0]; ! 1358: if ((pprev->op ==OP_MOVE && sameops( o, pprev->ref[0] ))|| ! 1359: (pprev->op !=OP_MOVE && sameops( o, pprev->ref[pprev->nref-1] ))){ ! 1360: p = deletenode( p ); ! 1361: didchange++; ! 1362: meter.nrtst++; ! 1363: } ! 1364: break; ! 1365: case OP_OR: ! 1366: /* ! 1367: * if what we're or-ing will fit into a byte or word, then ! 1368: * there's no excuse for using a longer immediate. ! 1369: * unless condition codes are live. ! 1370: */ ! 1371: if ( inmask( CCREG, p->forw->rlive)) break; ! 1372: if (numeric_immediate(o=p->ref[0])){ ! 1373: t = o->value_o; ! 1374: if (t==0 && deladdr(p->ref[1] )){ ! 1375: p = deletenode(p); ! 1376: didchange++; ! 1377: break; ! 1378: } ! 1379: if (t>0 && t<0xffff){ ! 1380: i = (p->subop==SUBOP_L)?2:0; ! 1381: newname = "orw"; ! 1382: if (t<0xff){ ! 1383: i = (p->subop==SUBOP_L)?3:(p->subop==SUBOP_W)?1:0; ! 1384: newname = "orb"; ! 1385: } ! 1386: if (i && !incraddr( p->ref[1], i)){ ! 1387: cannibalize( p, newname); ! 1388: meter.nwop++; ! 1389: didchange++; ! 1390: } ! 1391: } ! 1392: ! 1393: } ! 1394: break; ! 1395: case OP_ASL: ! 1396: /* look for multiple shifts in a row */ ! 1397: if (!numeric_immediate(o=p->ref[0])) continue; ! 1398: t = o->value_o; ! 1399: o = p->ref[1]; ! 1400: while ((pnext=p->forw)->op==OP_ASL){ ! 1401: register struct oper *iop; ! 1402: if (!numeric_immediate(iop=pnext->ref[0]) ! 1403: || !sameops( pnext->ref[1], o)) ! 1404: break; ! 1405: if ( t + iop->value_o > 8){ ! 1406: p->ref[0]->value_o = t; ! 1407: t = iop->value_o; ! 1408: p = pnext; ! 1409: o = p->ref[1]; ! 1410: continue; ! 1411: } ! 1412: t += iop->value_o; ! 1413: (void)deletenode( pnext ); ! 1414: meter.nredshf++; ! 1415: didchange++; ! 1416: } ! 1417: p->ref[0]->value_o = t; ! 1418: break; ! 1419: case OP_CMP: ! 1420: /* compares to zero are degenerate */ ! 1421: o = p->ref[0]; ! 1422: if (immediate_value(o, 0) && areg_addr(p->ref[1])){ ! 1423: /* "A" register */ ! 1424: /* look for a dead D register. Make this a movl */ ! 1425: if ((i=dead_dreg(p)) >= 0){ ! 1426: /* change cmpx #0,ay => movl ay,di */ ! 1427: /* reuse the #0 operand as the di operand */ ! 1428: p->ref[0] = p->ref[1]; ! 1429: o->type_o = T_REG; ! 1430: o->value_o = i; ! 1431: p->ref[1] = o; ! 1432: cannibalize( p, "movl" ); ! 1433: p->rlive = compute_normal( p, p->forw->rlive ); ! 1434: meter.nttomo++; ! 1435: didchange++; ! 1436: } ! 1437: } ! 1438: break; ! 1439: case OP_LEA: ! 1440: /* ! 1441: * this form seems to occur rather often: ! 1442: * lea XXX,a0 ! 1443: * movl a0,aN ! 1444: * with a0 dead beyond this point. Change this into ! 1445: * lea XXX,aN ! 1446: * then, look for the case ! 1447: * lea aN@(0,dM:Z),aN ! 1448: * and simplify it into ! 1449: * addZ dM,aN ! 1450: */ ! 1451: if ((pnext=p->forw)->op == OP_MOVE ! 1452: && pnext->subop == SUBOP_L ! 1453: && sameops( p->ref[1], pnext->ref[0]) ! 1454: && emptymask( andmask(p->rset,pnext->forw->rlive))) { ! 1455: /* if the move is to an A register, we're set */ ! 1456: o=pnext->ref[1]; ! 1457: if (areg_addr(o)){ ! 1458: pnext->ref[1] = p->ref[1]; /* give away our 2nd operand */ ! 1459: p->ref[1] = o; /* gain a new operand */ ! 1460: (void) deletenode( pnext ); /* get rid of next, with operands */ ! 1461: p->rset = MAKEWMASK( o->value_o, LW ); ! 1462: p->rlive = compute_normal( p, p->forw->rlive); ! 1463: didchange++; ! 1464: meter.redunm++; ! 1465: } ! 1466: } ! 1467: if ((o=p->ref[0])->type_o == T_INDEX ! 1468: && o->reg_o == p->ref[1]->value_o ! 1469: && o->scale_o == 1 ! 1470: && !(o->flags_o&(O_BSUPRESS|O_INDIRECT|O_POSTINDEX)) ! 1471: && o->disp_o == 0){ ! 1472: o->type_o = T_REG; ! 1473: newname = (o->flags_o&O_WINDEX) ? "addw" : "addl"; ! 1474: o->flags_o &= ~(O_WINDEX|O_LINDEX); ! 1475: cannibalize( p, newname ); ! 1476: meter.nsaddr++; ! 1477: didchange++; ! 1478: } ! 1479: break; ! 1480: ! 1481: case OP_SUB: ! 1482: p = make_dbra( p, &didchange ); ! 1483: if (p->op != OP_SUB) break; ! 1484: /* FALL THROUGH */ ! 1485: case OP_ADD: ! 1486: p = plus_minus( p, &didchange ); ! 1487: break; ! 1488: } ! 1489: } ! 1490: nchanged += didchange; ! 1491: } ! 1492: return nchanged; ! 1493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.