|
|
1.1 ! root 1: /* @(#) w1opt.c: 1.4 3/27/84 */ ! 2: /* w1opt.c ! 3: ** ! 4: ** 3B20S optimizer: for one-instruction window ! 5: ** ! 6: ** ! 7: */ ! 8: ! 9: /* #include "defs" -- optim.h takes care of this */ ! 10: #include "optim.h" ! 11: #include "optutil.h" ! 12: ! 13: ! 14: /* D A N G E R ! 15: ** ! 16: ** This definition selects the highest numbered register that we ! 17: ** can arbitrarily choose as a temporary in the multiply strength ! 18: ** reduction that is performed below. It should equal the highest ! 19: ** numbered temporary register used by the compiler (1 less than ! 20: ** lowest numbered register used for register variables. ! 21: */ ! 22: ! 23: #define TEMPREG 3 /* highest temp. reg. to use */ ! 24: /* w1opt -- one-instruction optimizer ! 25: ** ! 26: ** This routine handles the single-instruction optimization window. ! 27: ** See individual comments below about what's going on. ! 28: ** In some cases (which are noted), the optimizations are ordered. ! 29: */ ! 30: ! 31: boolean /* true if we make any changes */ ! 32: w1opt(pf,pl) ! 33: register NODE * pf; /* pointer to first instruction in ! 34: ** window (and last) ! 35: */ ! 36: NODE * pl; /* pointer to last instruction in ! 37: ** window (= pf) ! 38: */ ! 39: { ! 40: ! 41: register int cop = pf->op; /* single instruction's op code # */ ! 42: int opn; /* temporary op code number */ ! 43: char * opst; /* temporary op code string */ ! 44: boolean retval = false; /* return value: in some cases ! 45: ** we fall through after completing ! 46: ** an optimization because it could ! 47: ** lead into others. This variable ! 48: ** contains the return state for the ! 49: ** end. ! 50: */ ! 51: char * dest; /* destination string, used below */ ! 52: long mult; /* multiplier, used below */ ! 53: boolean f; /* random boolean flag, used below */ ! 54: long templ; /* general long temporary */ ! 55: /* eliminate dead code: ! 56: ** ! 57: ** op2 O1,R or op3 O1,O2,R ! 58: ** where R is dead ! 59: */ ! 60: ! 61: if ( ! 62: isdead(dst(pf),pf) /* we don't really care what the op ! 63: ** is ! 64: */ ! 65: && ! isbr(pf) /* but some branches set variables ! 66: ** and jump: keep them ! 67: */ ! 68: && isdeadcc( pf ) /* this inst. may have side effects ! 69: ** relied upon by cond. branch ! 70: */ ! 71: && isiros( pf->op1 ) ! 72: && isiros( pf->op2 ) /* are operands safe for mmio */ ! 73: ) ! 74: { ! 75: wchange(); /* Note we're changing the window */ ! 76: ldelin2(pf); /* preserve line number info */ ! 77: mvlivecc(pf); /* preserve condition codes line info */ ! 78: DELNODE(pf); /* discard instruction */ ! 79: return(true); /* announce success */ ! 80: } ! 81: ! 82: /* ! 83: ** cmpw R,&0 -> movw R,R ! 84: ** ! 85: ** This wins on the 3B20S, but might not on other 3B processors. ! 86: */ ! 87: ! 88: /* Although this improvement is a small win, it messes up other ! 89: ** transformations and generally confuses things. It's probably ! 90: ** better to leave it turned off. ! 91: */ ! 92: ! 93: #ifdef CMPWTOMOVW ! 94: ! 95: if ( ! 96: cop == CMPW ! 97: && isreg(pf->op1) ! 98: && strcmp(pf->op2,"&0") == 0 ! 99: ) ! 100: ! 101: { ! 102: wchange(); /* note change */ ! 103: chgop(pf,MOVW,"movw"); /* change the op code */ ! 104: pf->op2 = pf->op1; /* both operands point at R */ ! 105: makelive(pf->op2,pf); /* make register appear to be live ! 106: ** hereafter so "compare" isn't thrown ! 107: ** away. (Otherwise R might be dead ! 108: ** and we would eliminate the inst.) ! 109: */ ! 110: return(true); /* made a change */ ! 111: } ! 112: ! 113: #endif /* def CMPWTOMOV */ ! 114: /* get rid of useless arithmetic ! 115: ** ! 116: ** addw2 &0,O -> deleted or cmpw O,&0 ! 117: ** subw2 &0,O -> deleted or cmpw O,&0 ! 118: ** orw2 &0,O -> deleted or cmpw O,&0 ! 119: ** xorw2 &0,O -> deleted or cmpw O,&0 ! 120: ** alsw2 &0,O -> deleted or cmpw O,&0 ! 121: ** arsw2 &0,O -> deleted or cmpw O,&0 ! 122: ** llsw2 &0,O -> deleted or cmpw O,&0 ! 123: ** lrsw2 &0,O -> deleted or cmpw O,&0 ! 124: ** mulw2 &1,O -> deleted or cmpw O,&0 ! 125: ** umulw2 &1,O -> deleted or cmpw O,&0 ! 126: ** divw2 &1,O -> deleted or cmpw O,&0 ! 127: ** udivw2 &1,O -> deleted or cmpw O,&0 ! 128: ** andw2 &-1,O -> deleted or cmpw O,&0 ! 129: ! 130: ** addw3 &0,O1,O2 -> movw O1,O2 ! 131: ** subw3 &0,O1,O2 -> movw O1,O2 ! 132: ** orw3 &0,O1,O2 -> movw O1,O2 ! 133: ** xorw3 &0,O1,O2 -> movw O1,O2 ! 134: ** alsw3 &0,O1,O2 -> movw O1,O2 ! 135: ** arsw3 &0,O1,O2 -> movw O1,O2 ! 136: ** llsw3 &0,O1,O2 -> movw O1,O2 ! 137: ** lrsw3 &0,O1,O2 -> movw O1,O2 ! 138: ** mulw3 &1,O1,O2 -> movw O1,O2 ! 139: ** umulw3 &1,O1,O2 -> movw O1,O2 ! 140: ** divw3 &1,O1,O2 -> movw O1,O2 ! 141: ** udivw3 &1,O1,O2 -> movw O1,O2 ! 142: ** andw3 &-1,O1,O2 -> movw O1,O2 ! 143: ** ! 144: ** mulw2 &0,O -> movw &0,O ! 145: ** umulw2 &0,O -> movw &0,O ! 146: ** andw2 &0,O -> movw &0,O ! 147: ** mulw3 &0,O1,O2 -> movw &0,O2 ! 148: ** umulw3 &0,O1,O2 -> movw &0,O2 ! 149: ** andw3 &0,O1,O2 -> movw &0,O2 ! 150: ** ! 151: ** xorw2 &-1,O -> mcomw O,O ! 152: ** xorw3 &-1,O1,O2 -> mcomw O1,O2 ! 153: ** ! 154: ** mulw2 &-1,O -> mnegw O,O ! 155: ** divw2 &-1,O -> mnegw O,O ! 156: ** mulw3 &-1,O1,O2 -> mnegw O1,O2 ! 157: ** divw3 &-1,O1,O2 -> mnegw O1,O2 ! 158: ** ! 159: ** Note that since we've already gotten rid of dead code, we won't ! 160: ** check whether O (O2) is live. However, we must be careful to ! 161: ** preserve the sense of result indicators if a conditional branch ! 162: ** follows some of these changes. ! 163: */ ! 164: ! 165: /* Define types of changes we will make.... */ ! 166: ! 167: #define UA_NOP 1 /* no change */ ! 168: #define UA_DEL 2 /* delete instruction */ ! 169: #define UA_MOV 3 /* change to move */ ! 170: #define UA_MOVZ 4 /* change to move zero to ... */ ! 171: #define UA_MCOM 5 /* change to move complemented */ ! 172: #define UA_MNEG 6 /* change to move negated */ ! 173: /* We must have a literal as the first operand, and its value must fit ! 174: ** in an integer. We check the latter condition by comparing the converted ! 175: ** value from atol to the same value cast as an int: they must agree. ! 176: ** (This is a particular problem for DMERT when they run the optimizer ! 177: ** on a PDP-11/70 to optimize 3B20 code.) ! 178: */ ! 179: if ( isnumlit(pf->op1) ! 180: && (templ = atol(pf->op1+1)) == (long)((int) templ) ! 181: ) ! 182: { ! 183: int ultype = UA_NOP; /* initial type of change = none */ ! 184: ! 185: switch((int) templ) /* branch on literal */ ! 186: { ! 187: case 0: /* handle all instructions with &0 ! 188: ** as first operand ! 189: */ ! 190: switch (cop) ! 191: { ! 192: case ADDW2: ! 193: case SUBW2: ! 194: case ORW2: ! 195: case XORW2: ! 196: case ALSW2: ! 197: case ARSW2: ! 198: case LLSW2: ! 199: case LRSW2: ! 200: if( !isiros( pf->op2 ) ) break; ! 201: ultype = UA_DEL; ! 202: break; ! 203: /* if safe from mmio, ! 204: ** delete all of these */ ! 205: ! 206: case ADDW3: ! 207: case SUBW3: ! 208: case ORW3: ! 209: case XORW3: ! 210: case ALSW3: ! 211: case ARSW3: ! 212: case LLSW3: ! 213: case LRSW3: ! 214: ultype = UA_MOV; /* convert to simple moves */ ! 215: break; ! 216: ! 217: case MULW2: ! 218: case UMULW2: ! 219: case ANDW2: ! 220: ultype = UA_MOVZ; /* convert to move zero */ ! 221: break; ! 222: ! 223: case MULW3: ! 224: case UMULW3: ! 225: case ANDW3: ! 226: if( !isiros( pf->op2 ) ) break; ! 227: ultype = UA_MOVZ; ! 228: break; ! 229: /* if safe from mmio, ! 230: ** convert to move zero */ ! 231: } ! 232: break; /* done &0 case */ ! 233: ! 234: case 1: /* &1 case */ ! 235: switch( cop ) /* branch on op code */ ! 236: { ! 237: case DIVW2: ! 238: case UDIVW2: ! 239: case MULW2: ! 240: case UMULW2: ! 241: if( !isiros( pf->op2 ) ) break; ! 242: ultype = UA_DEL; ! 243: break; ! 244: /* if safe from mmio, ! 245: ** delete these */ ! 246: ! 247: case DIVW3: ! 248: case UDIVW3: ! 249: case MULW3: ! 250: case UMULW3: ! 251: ultype = UA_MOV; /* convert these to moves */ ! 252: break; ! 253: } ! 254: break; /* done &1 case */ ! 255: ! 256: case -1: /* &-1 case */ ! 257: switch ( cop ) /* branch on op code */ ! 258: { ! 259: case ANDW2: ! 260: if( !isiros( pf->op2 ) ) break; ! 261: ultype = UA_DEL; ! 262: break; ! 263: /* if safe from mmio, ! 264: ** delete this */ ! 265: ! 266: case ANDW3: ! 267: ultype = UA_MOV; /* change to move */ ! 268: break; ! 269: ! 270: case XORW2: ! 271: if( !isiros( pf->op2 ) ) break; ! 272: ultype = UA_MCOM; ! 273: break; ! 274: /* if safe from mmio, ! 275: ** change to move complemented */ ! 276: ! 277: case XORW3: ! 278: ultype = UA_MCOM; /* change to move complemented */ ! 279: break; ! 280: ! 281: case MULW2: ! 282: case DIVW2: ! 283: if( !isiros( pf->op2 ) ) break; ! 284: ultype = UA_MNEG; ! 285: break; ! 286: /* if safe from mmio, ! 287: ** change to move complemented */ ! 288: case MULW3: ! 289: case DIVW3: ! 290: ultype = UA_MNEG; /* change to move negated */ ! 291: break; ! 292: } ! 293: break; /* end &-1 case */ ! 294: } /* end switch on immediate value */ ! 295: /* Now do something, based on selections made above */ ! 296: ! 297: switch ( ultype ) ! 298: { ! 299: case UA_MOV: /* change instruction to move */ ! 300: wchange(); /* changing window */ ! 301: pf->op1 = pf->op2; /* shift operands */ ! 302: pf->op2 = dst(pf); ! 303: pf->op3 = NULL; /* in case we removed it */ ! 304: chgop(pf,MOVW,"movw"); /* change op code */ ! 305: retval = true; /* made a change */ ! 306: break; ! 307: ! 308: case UA_MOVZ: /* change to move zero to operand */ ! 309: wchange(); ! 310: pf->op1 = "&0"; /* first operand is zero */ ! 311: pf->op2 = dst(pf); /* second is ultimate destination */ ! 312: pf->op3 = NULL; /* clean out if there was one */ ! 313: chgop(pf,MOVW,"movw"); /* change op code */ ! 314: retval = true; /* made a change */ ! 315: break; ! 316: ! 317: case UA_MCOM: /* change to move complemented */ ! 318: wchange(); ! 319: pf->op1 = pf->op2; /* shift operands */ ! 320: pf->op2 = dst(pf); ! 321: pf->op3 = NULL; ! 322: chgop(pf,MCOMW,"mcomw"); /* change op code */ ! 323: retval = true; /* made a change */ ! 324: break; ! 325: ! 326: case UA_MNEG: /* change to move negated */ ! 327: wchange(); ! 328: pf->op1 = pf->op2; /* shift operands */ ! 329: pf->op2 = dst(pf); ! 330: pf->op3 = NULL; ! 331: chgop(pf,MNEGW,"mnegw"); /* change op code */ ! 332: retval = true; /* made a change */ ! 333: break; ! 334: /* For this case we must be careful: if a following instruction is a ! 335: ** conditional branch, it is clearly depending on the result of the ! 336: ** arithmetic, so we must put in a compare against zero instead of deleting ! 337: ** the instruction. ! 338: */ ! 339: ! 340: case UA_DEL: /* delete instruction */ ! 341: ! 342: wchange(); /* we will make a change */ ! 343: ! 344: if ( ! isdeadcc(pf) ) ! 345: { ! 346: chgop(pf,CMPW,"cmpw"); ! 347: pf->op1 = pf->op2; /* always test second operand */ ! 348: pf->op2 = "&0"; /* compare to zero */ ! 349: pf->op3 = NULL; /* for completeness */ ! 350: retval = true; /* made a change */ ! 351: } ! 352: else ! 353: { ! 354: ldelin2(pf); /* preserve line number info */ ! 355: mvlivecc(pf); /* preserve condition codes line info */ ! 356: DELNODE(pf); /* not conditional; delete node */ ! 357: return(true); /* say we changed something */ ! 358: } ! 359: break; ! 360: } /* end case that decides what to do */ ! 361: ! 362: cop = pf->op; /* reset current op for changed inst. */ ! 363: ! 364: } /* end useless arithmetic removal */ ! 365: /* discard useless movw's ! 366: ** ! 367: ** movw O,O -> deleted ! 368: ** ! 369: ** The movw must not be followed by a conditional jump, since we ! 370: ** must leave the condition codes set. Note that this improvement ! 371: ** picks up some strange code generated above, like ! 372: ** ! 373: ** mulw3 &1,%r0,%r0 -> movw %r0,%r0 ! 374: ** ! 375: */ ! 376: ! 377: if ( pf->op == MOVW ! 378: && strcmp(pf->op1,pf->op2) == 0 ! 379: && isdeadcc(pf) ! 380: && isiros(pf->op1) /* safe from mmio */ ! 381: ) ! 382: { ! 383: wchange(); /* changing the window */ ! 384: ldelin2(pf); /* preserve line number info */ ! 385: mvlivecc(pf); /* preserve condition codes line info */ ! 386: DELNODE(pf); /* delete the movw */ ! 387: return(true); ! 388: } ! 389: /* change triadics to dyadics if possible ! 390: ** ! 391: ** op3 O1,O2,O2 -> op2 O1,O2 ! 392: ** ! 393: */ ! 394: ! 395: if (istriadic(pf,&opn,&opst) ! 396: && strcmp(pf->op2,pf->op3) == 0 ! 397: && isiros(pf->op2) /* safe from mmio */ ! 398: ) ! 399: ! 400: /* triadic and last two operands match */ ! 401: ! 402: { ! 403: wchange(); /* we're making a change */ ! 404: chgop(pf,opn,opst); /* change the op code */ ! 405: pf->op3 = NULL; /* so we don't keep looking at 3rd ! 406: ** operand ! 407: */ ! 408: retval = true; /* remember that we made a change, ! 409: ** but don't exit, as the next ! 410: ** optimization may also apply. ! 411: */ ! 412: cop = opn; /* changed op code */ ! 413: } ! 414: /* falling through either way !! */ ! 415: /* change multiplies and divides to shifts if power of 2 */ ! 416: ! 417: /* ! 418: ** udivw2 &2^n,O -> lrsw2 &n,O ! 419: ** udivw3 &2^n,O1,O2 -> lrsw3 &n,O1,O2 ! 420: ** mulw2 &2^n,O -> arsw2 &n,O ! 421: ** mulw3 &2^n,O1,O2 -> arsw3 &n,O1,O2 ! 422: ** umulw2 &2^n,O -> llsw2 &n,O ! 423: ** umulw3 &2^n,O1,O2 -> llsw3 &n,O1,O2 ! 424: ** ! 425: ** Note that signed divide cannot safely be altered with these ! 426: ** transformations! ! 427: */ ! 428: ! 429: switch (cop) /* dispatch on type */ ! 430: { ! 431: int bit; /* temporary bit number if 2^n */ ! 432: ! 433: case UDIVW2: ! 434: case UDIVW3: ! 435: case MULW2: ! 436: case MULW3: ! 437: case UMULW2: ! 438: case UMULW3: ! 439: ! 440: if ( (bit = getbit(pf->op1)) < 0) /* if not power of 2, done this */ ! 441: break; ! 442: ! 443: wchange(); /* about to change window */ ! 444: pf->op1 = getspace(1+2+1); /* room for &dd\0 */ ! 445: (void) sprintf(pf->op1,"&%d",bit); /* write shift amount */ ! 446: switch (cop) /* now change op code as needed */ ! 447: { ! 448: case UDIVW2: ! 449: chgop(pf,LRSW2,"lrsw2"); break; ! 450: case UDIVW3: ! 451: chgop(pf,LRSW3,"lrsw3"); break; ! 452: case MULW2: ! 453: chgop(pf,ALSW2,"alsw2"); break; ! 454: case MULW3: ! 455: chgop(pf,ALSW3,"alsw3"); break; ! 456: case UMULW2: ! 457: chgop(pf,LLSW2,"llsw2"); break; ! 458: case UMULW3: ! 459: chgop(pf,LLSW3,"llsw3"); break; ! 460: } ! 461: retval = true; /* we changed something */ ! 462: cop = pf->op; /* changed op code, too */ ! 463: } ! 464: ! 465: #ifndef M32 /* applies only to 3B20S */ ! 466: ! 467: /* The 3B20 can do shifts and adds faster than multiplies for small ! 468: ** integer multipliers where the result ends up in a register. Here ! 469: ** we pick such multiplies apart, arbitrarily stopping at 10 as an ! 470: ** upper bound. ! 471: */ ! 472: ! 473: if ( ! 474: ( ! 475: cop == MULW2 ! 476: || cop == MULW3 ! 477: ) ! 478: && *pf->op1 == '&' /* multiplier is small literal */ ! 479: && isreg(dest = (cop == MULW2 ? pf->op2 : pf->op3)) ! 480: /* remember dest.; must be reg. */ ! 481: && (mult = atol(pf->op1+1)) > 2/* positive multiplier (exclude ! 482: ** 0, 1, 2 ! 483: */ ! 484: && mult <= 10 /* arbitrary upper limit */ ! 485: ) ! 486: { ! 487: static char regstring[] = "%rx";/* boiler-plate register name */ ! 488: char * temp = NULL; /* string representing temp. used ! 489: ** during "multiply" ! 490: */ ! 491: NODE * new; /* pointer to new instruction node */ ! 492: ! 493: /* The approach works like this: ! 494: ** ! 495: ** 1. Identify destination register and temporary register that ! 496: ** we will need to use. ! 497: ** 2. Determine live/dead data for new instructions. ! 498: ** 3. Add new instructions after the MULW_, but holding on to the ! 499: ** MULW_ as an anchor (since pf points at it). ! 500: ** 4. Delete MULW_ when done. ! 501: ** ! 502: ** Note that the instruction sequences we create always set the ! 503: ** result indicators the same as if a multiply had been done. ! 504: */ ! 505: ! 506: /* Macro to add new instruction: ! 507: ** ptr points to instruction to add after ! 508: ** opn op code number of new instruction ! 509: ** opst op code string of instruction ! 510: ** opn1 operand 1 for new instruction ! 511: ** opn2 operand 2 for new instruction ! 512: ** ld live/dead data for new instruction ! 513: */ ! 514: ! 515: #define addinst(ptr,opn,opst,opn1,opn2,ld) \ ! 516: { \ ! 517: last = insert(ptr); /* get new node */ \ ! 518: chgop(last,opn,opst); /* put in op code number, string */ \ ! 519: last->op1 = opn1; /* put in operands */ \ ! 520: last->op2 = opn2; \ ! 521: last->nlive = ld; /* put in live/dead info. */ \ ! 522: } ! 523: /* Identify temporary and destination registers. ! 524: ** ! 525: ** Destination is already in 'dest': the destination of the MULW_. ! 526: ** 'temp' must be chosen for MULW2 or for MULW3 where the second ! 527: ** operand is not already in a register. ! 528: */ ! 529: ! 530: /* f will remember whether we needed to "create" a temporary. ! 531: ** We must do so for MULW2 or for MULW3 when 2nd operand not a reg. ! 532: */ ! 533: ! 534: if ( f = ( ! 535: cop == MULW2 /* inst. is MULW2 */ ! 536: || ! isreg(pf->op2) /* MULW3 2nd operand not reg. */ ! 537: ) ! 538: ) ! 539: ! 540: { ! 541: int j; /* register number */ ! 542: ! 543: /* We're going to loop, trying to find a register to steal. ! 544: ** Then we save a copy of the appropriate register string for ! 545: ** the instructions we'll build. ! 546: */ ! 547: ! 548: for ( j = '0' + TEMPREG; j >= '0'; j--) /* go down from highest */ ! 549: { ! 550: regstring[2] = (char) j; /* stick char in string */ ! 551: if (isdead(regstring,pf)) /* if dead, we can use it */ ! 552: { ! 553: temp = strcpy(getspace(sizeof regstring),regstring); ! 554: break; ! 555: } ! 556: } ! 557: } /* end if that builds a temp. string */ ! 558: else /* MULW3 had reg. as 2nd operand */ ! 559: temp = pf->op2; /* point at it as suitable temporary */ ! 560: ! 561: /* 'dest' and 'temp' now point at suitable strings representing registers. ! 562: ** Although we're not sure about the multiplier value, we know powers of ! 563: ** 2 have already been handled. Therefore there is no danger of allocating ! 564: ** a string above without actually using it. ! 565: */ ! 566: /* Build correct instruction sequence. */ ! 567: ! 568: if (temp != NULL) /* make sure we got a temporary */ ! 569: { ! 570: NODE * last = pf; /* remember last node in sequence */ ! 571: int ld; /* current live/dead bits */ ! 572: ! 573: wchange(); /* tell the world we're changing */ ! 574: ! 575: /* Set up live/dead data. We want to replicate the information in ! 576: ** the current multiply node, plus we want to set 'temp' and 'dest' ! 577: ** registers live. ! 578: */ ! 579: ! 580: makelive(dest,pf); /* set destination live */ ! 581: ld = pf->nlive; /* remember data */ ! 582: ! 583: if (cop == MULW3) /* On MULW3 we must load the dest. */ ! 584: addinst(last,MOVW,"movw",pf->op2,dest,ld); ! 585: ! 586: /* Now we change the live/dead information so 'temp' will appear live */ ! 587: ! 588: makelive(temp,pf); ! 589: ld = pf->nlive; ! 590: ! 591: /* If we created a temp, move the current destination (multiplicand) ! 592: ** there now. ! 593: */ ! 594: ! 595: if (f) ! 596: addinst(last,MOVW,"movw",dest,temp,ld); ! 597: ! 598: /* Now generate instruction sequences based on multiplier. */ ! 599: ! 600: switch ((int) mult) /* value known to be between 2, 10 */ ! 601: { ! 602: case 3: ! 603: addinst(last,LLSW2,"llsw2","&1",dest,ld); /* *2 */ ! 604: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *3 */ ! 605: break; ! 606: case 5: ! 607: addinst(last,LLSW2,"llsw2","&2",dest,ld); /* *4 */ ! 608: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *5 */ ! 609: break; ! 610: case 6: ! 611: addinst(last,LLSW2,"llsw2","&2",dest,ld); /* *4 */ ! 612: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *5 */ ! 613: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *6 */ ! 614: break; ! 615: case 7: ! 616: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */ ! 617: addinst(last,SUBW2,"subw2",temp,dest,ld); /* *7 */ ! 618: break; ! 619: case 9: ! 620: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */ ! 621: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *9 */ ! 622: break; ! 623: case 10: ! 624: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */ ! 625: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *9 */ ! 626: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *10 */ ! 627: break; ! 628: } ! 629: /* Done generating instructions. Now clean up. ! 630: ** First, fix up live/dead data so temp is dead after last ! 631: ** instruction. Then kill old node. ! 632: */ ! 633: ! 634: makedead(temp,last); ! 635: ldelin(pf); /* preserve line number info */ ! 636: DELNODE(pf); /* delete the multiply */ ! 637: return(true); /* we-ve changed something */ ! 638: } /* end if, testing for NULL temp */ ! 639: } /* end if, testing for multiply */ ! 640: ! 641: #endif /* ndef M32 */ ! 642: ! 643: #ifndef M32 /* 3B20 only */ ! 644: ! 645: /* The 3B20 has special instructions to move a positive nibble to a ! 646: ** register. It does less well with negative ones, since it puts ! 647: ** them in a large immediate value. The following transformation ! 648: ** runs faster for small negative constants. ! 649: ** ! 650: ** movw &-n,R -> movw &n,R ! 651: ** -> mnegw R,R ! 652: ** ! 653: ** when 1 <= n <= 15 ! 654: */ ! 655: ! 656: if ( ! 657: cop == MOVW ! 658: && isreg(pf->op2) ! 659: && isnegnib(pf->op1) ! 660: ) ! 661: { ! 662: NODE * new = insert(pf); /* make new node after pf */ ! 663: ! 664: wchange(); /* we're making changes */ ! 665: *(pf->op1 = copyopn(pf->op1,-1,1)) = '&'; ! 666: /* copy operand, offset by 1, ! 667: ** overwrite - with & ! 668: */ ! 669: chgop(new,MNEGW,"mnegw"); /* fill in new node */ ! 670: new->op1 = new->op2 = pf->op2; ! 671: new->nlive = pf->nlive; /* replicate live/dead data for new ! 672: ** node so it won't go away ! 673: */ ! 674: return(true); ! 675: } ! 676: ! 677: #endif /* ndef M32 */ ! 678: ! 679: #ifndef M32 /* 3B20 only */ ! 680: ! 681: /* From empirical studies it appears that triadic instructions should ! 682: ** not be used on the 3B20S when the destination is a register, because ! 683: ** an equivalent two-instruction sequence is faster. The same applies ! 684: ** in another specialized triadic case below. ! 685: ** ! 686: ** op3 O1,O2,R -> movw O2,R ! 687: ** -> op2 O1,R ! 688: ** ! 689: ** if R not used in O1 ! 690: ** ! 691: ** ! 692: ** op3 &n,R,O -> op2 &n,R ! 693: ** -> movw R,O ! 694: ** ! 695: ** if R is dead ! 696: */ ! 697: ! 698: if (istriadic(pf,&opn,&opst)) /* check triadic, save equiv. op code ! 699: ** number and string ! 700: */ ! 701: { ! 702: ! 703: /* first case: op3 O1,O2,R */ ! 704: ! 705: if ( isreg(pf->op3) && ! usesreg(pf->op1,pf->op3) ) ! 706: /* check R not used in O1 */ ! 707: { ! 708: NODE * new = insert(pf); /* add new node after pf */ ! 709: ! 710: wchange(); /* changing something */ ! 711: ! 712: chgop(new,opn,opst); /* set up new node with dyadic */ ! 713: new->op1 = pf->op1; /* set O1 */ ! 714: new->op2 = pf->op3; /* set R */ ! 715: new->nlive = pf->nlive; /* propagate live/dead stuff */ ! 716: ! 717: chgop(pf,MOVW,"movw"); /* modify original node */ ! 718: pf->op1 = pf->op2; /* make first operand O2 */ ! 719: pf->op2 = pf->op3; /* second is R */ ! 720: pf->op3 = NULL; /* clean up third one */ ! 721: makelive(pf->op2,pf); /* force R live; R may be dead ! 722: ** after pl if pl is followed by a ! 723: ** conditional branch. We must make ! 724: ** it live here. ! 725: */ ! 726: return(true); ! 727: } ! 728: else if (isnib(pf->op1) && isdead(pf->op2,pf)) ! 729: /* (test for register implicit in "isdead") */ ! 730: ! 731: /* second case: op3 &n,R,O */ ! 732: ! 733: { ! 734: NODE * new = insert(pf); /* add new following node */ ! 735: ! 736: wchange(); /* changing something */ ! 737: ! 738: chgop(pf,opn,opst); /* put dyadic in first node */ ! 739: ! 740: chgop(new,MOVW,"movw"); /* second node is MOVW */ ! 741: new->op1 = pf->op2; /* set R */ ! 742: new->op2 = pf->op3; /* set O */ ! 743: new->nlive = pf->nlive; /* propagate live/dead in movw */ ! 744: makelive(pf->op2,pf); /* make R live after op2 */ ! 745: ! 746: pf->op3 = NULL; /* clean out 3rd operand of original */ ! 747: return(true); ! 748: } ! 749: } ! 750: ! 751: #endif /* ndef M32 */ ! 752: ! 753: #ifdef IMPLLSW ! 754: ! 755: /* For BELLMAC-32, a shift by one bit is more efficiently ! 756: ** done as an add. ! 757: ** ! 758: ** llsw2 &1,O1 -> addw2 O1,O1 ! 759: ** ! 760: ** llsw3 &1,O1,O2 -> addw3 O1,O1,O2 ! 761: ** ! 762: */ ! 763: ! 764: { ! 765: if( strcmp( pf->op1, "&1" ) == 0 ! 766: && isiros(pf->op2) /* safe from mmio */ ! 767: ) { ! 768: if( pf->op == LLSW2 ) { ! 769: chgop( pf, ADDW2, "addw2" ); ! 770: pf->op1 = pf->op2; ! 771: return( true ); ! 772: } ! 773: if( pf->op == LLSW3 ) { ! 774: chgop( pf, ADDW3, "addw3" ); ! 775: pf->op1 = pf->op2; ! 776: return( true ); ! 777: } ! 778: } ! 779: } ! 780: #endif /* IMPLLSW */ ! 781: ! 782: return(retval); /* indicate whether anything changed */ ! 783: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.