]> git.sur5r.net Git - cc65/commitdiff
Replace "lda (zp),y" by "lda (zp,x)" where possible and where it saves us
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 3 Sep 2009 12:13:08 +0000 (12:13 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 3 Sep 2009 12:13:08 +0000 (12:13 +0000)
cycles and code bytes.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4113 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeopt.c
src/cc65/coptind.c
src/cc65/coptind.h

index 422496792c6ae4d355c4700452a96ea32a7b945d..dfb5ab1154ae3fb2d40b397209c4a47cbd4b982d 100644 (file)
@@ -1105,6 +1105,8 @@ static OptFunc DOptDeadCode       = { OptDeadCode,     "OptDeadCode",     100, 0,
 static OptFunc DOptDeadJumps           = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
+static OptFunc DOptIndLoads1    = { OptIndLoads1,    "OptIndLoads1",      0, 0, 0, 0, 0, 0 };
+static OptFunc DOptIndLoads2    = { OptIndLoads2,    "OptIndLoads2",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpCascades        = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget1  = { OptJumpTarget1,  "OptJumpTarget1",  100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget2  = { OptJumpTarget2,  "OptJumpTarget2",  100, 0, 0, 0, 0, 0 };
@@ -1191,6 +1193,8 @@ static OptFunc* OptFuncs[] = {
     &DOptDeadJumps,
     &DOptDecouple,
     &DOptDupLoads,
+    &DOptIndLoads1,
+    &DOptIndLoads2,
     &DOptJumpCascades,
     &DOptJumpTarget1,
     &DOptJumpTarget2,
@@ -1644,6 +1648,32 @@ static unsigned RunOptGroup5 (CodeSeg* S)
 
 
 static unsigned RunOptGroup6 (CodeSeg* S)
+/* This one is quite special. It tries to replace "lda (sp),y" by "lda (sp,x)".
+ * The latter is ony cycle slower, but if we're able to remove the necessary
+ * load of the Y register, because X is zero anyway, we gain 1 cycle and
+ * shorten the code by one (transfer) or two bytes (load). So what we do is
+ * to replace the insns, remove unused loads, and then change back all insns
+ * where Y is still zero (meaning that the load has not been removed).
+ */
+{
+    unsigned Changes = 0;
+
+    /* This group will only run for a standard 6502, because the 65C02 has a
+     * better addressing mode that covers this case.
+     */
+    if ((CPUIsets[CPU] & CPU_ISET_65SC02) == 0) {
+        Changes += RunOptFunc (S, &DOptIndLoads1, 1);
+        Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+        Changes += RunOptFunc (S, &DOptIndLoads2, 1);
+    }
+
+    /* Return the number of changes */
+    return Changes;
+}
+
+
+
+static unsigned RunOptGroup7 (CodeSeg* S)
 /* The last group of optimization steps. Adjust branches, do size optimizations.
  */
 {
@@ -1726,6 +1756,7 @@ void RunOpt (CodeSeg* S)
     RunOptGroup4 (S);
     RunOptGroup5 (S);
     RunOptGroup6 (S);
+    RunOptGroup7 (S);
 
     /* Write statistics */
     if (StatFileName) {
index b80610b56b83858fd1ff04b9937014bdc336b566..63351677a44d24add188ecf4ade44c475dfad685 100644 (file)
@@ -883,17 +883,17 @@ unsigned OptUnusedLoads (CodeSeg* S)
            /* Check which sort of load or transfer it is */
            unsigned R;
            switch (E->OPC) {
-               case OP65_DEA:
-               case OP65_INA:
-               case OP65_LDA:
+               case OP65_DEA:
+               case OP65_INA:
+               case OP65_LDA:
                case OP65_TXA:
                case OP65_TYA:  R = REG_A;      break;
-               case OP65_DEX:
-               case OP65_INX:
-               case OP65_LDX:
+               case OP65_DEX:
+               case OP65_INX:
+               case OP65_LDX:
                case OP65_TAX:  R = REG_X;      break;
-               case OP65_DEY:
-               case OP65_INY:
+               case OP65_DEY:
+               case OP65_INY:
                        case OP65_LDY:
                case OP65_TAY:  R = REG_Y;      break;
                default:        goto NextEntry;         /* OOPS */
@@ -903,11 +903,11 @@ unsigned OptUnusedLoads (CodeSeg* S)
            if ((GetRegInfo (S, I+1, R) & R) == 0) {
 
                /* Register value is not used, remove the load */
-               CS_DelEntry (S, I);
+               CS_DelEntry (S, I);
 
-               /* Remember, we had changes. Account the deleted entry in I. */
-               ++Changes;
-               --I;
+               /* Remember, we had changes. Account the deleted entry in I. */
+               ++Changes;
+               --I;
 
            }
        }
@@ -2036,3 +2036,117 @@ unsigned OptBranchDist (CodeSeg* S)
 
 
 
+/*****************************************************************************/
+/*                          Optimize indirect loads                          */
+/*****************************************************************************/
+
+
+
+unsigned OptIndLoads1 (CodeSeg* S)
+/* Change
+ *
+ *     lda      (zp),y
+ *
+ * into
+ *
+ *     lda      (zp,x)
+ *
+ * provided that x and y are both zero.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Generate register info for this step */
+    CS_GenRegInfo (S);
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       /* Get next entry */
+               CodeEntry* E = CS_GetEntry (S, I);
+
+       /* Check if it's what we're looking for */
+               if (E->OPC == OP65_LDA          &&
+            E->AM == AM65_ZP_INDY       &&
+            E->RI->In.RegY == 0         &&
+            E->RI->In.RegX == 0) {
+
+           /* Replace by the same insn with other addressing mode */
+            CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZPX_IND, E->Arg, 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            /* Remove the old insn */
+            CS_DelEntry (S, I);
+            ++Changes;
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Free register info */
+    CS_FreeRegInfo (S);
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+unsigned OptIndLoads2 (CodeSeg* S)
+/* Change
+ *
+ *     lda      (zp,x)
+ *
+ * into
+ *
+ *     lda      (zp),y
+ *
+ * provided that x and y are both zero.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Generate register info for this step */
+    CS_GenRegInfo (S);
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       /* Get next entry */
+               CodeEntry* E = CS_GetEntry (S, I);
+
+       /* Check if it's what we're looking for */
+               if (E->OPC == OP65_LDA          &&
+            E->AM == AM65_ZPX_IND       &&
+            E->RI->In.RegY == 0         &&
+            E->RI->In.RegX == 0) {
+
+           /* Replace by the same insn with other addressing mode */
+            CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_INDY, E->Arg, 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            /* Remove the old insn */
+            CS_DelEntry (S, I);
+            ++Changes;
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Free register info */
+    CS_FreeRegInfo (S);
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
index eb22301e10d12de8952a95720d732a93043c6fdc..98d205489a91113e7bb84c4fe98c3050b9240c78 100644 (file)
@@ -141,6 +141,30 @@ unsigned OptPrecalc (CodeSeg* S);
 unsigned OptBranchDist (CodeSeg* S);
 /* Change branches for the distance needed. */
 
+unsigned OptIndLoads1 (CodeSeg* S);
+/* Change
+ *
+ *     lda      (zp),y
+ *
+ * into
+ *
+ *     lda      (zp,x)
+ *
+ * provided that x and y are both zero.
+ */
+
+unsigned OptIndLoads2 (CodeSeg* S);
+/* Change
+ *
+ *     lda      (zp,x)
+ *
+ * into
+ *
+ *     lda      (zp),y
+ *
+ * provided that x and y are both zero.
+ */
+
 
 
 /* End of coptind.h */