]> git.sur5r.net Git - cc65/commitdiff
Handle intermediate access to local variables in the stack op optimizations.
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 2 Oct 2001 10:55:04 +0000 (10:55 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 2 Oct 2001 10:55:04 +0000 (10:55 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@994 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeopt.c
src/cc65/coptstop.c

index 3461af698f6cd0b0d12922b262e3772e51a5dfa0..9ba4be02fffad13c4eac9e37787cde74f4cdd643 100644 (file)
@@ -1630,6 +1630,7 @@ static void RunOptGroup3 (CodeSeg* S)
                Changes += RunOptFunc (S, &DOptSub1, 1);
                Changes += RunOptFunc (S, &DOptSub2, 1);
                Changes += RunOptFunc (S, &DOptAdd3, 1);
+       Changes += RunOptFunc (S, &DOptStackOps, 1);
                Changes += RunOptFunc (S, &DOptJumpCascades, 1);
                Changes += RunOptFunc (S, &DOptDeadJumps, 1);
                Changes += RunOptFunc (S, &DOptRTS, 1);
@@ -1651,7 +1652,6 @@ static void RunOptGroup3 (CodeSeg* S)
        Changes += RunOptFunc (S, &DOptDupLoads, 1);
        Changes += RunOptFunc (S, &DOptStoreLoad, 1);
        Changes += RunOptFunc (S, &DOptTransfers, 1);
-       Changes += RunOptFunc (S, &DOptStackOps, 1);
 
     } while (Changes);
 }
index 6123b945abb19c4c9af7eadceba8df0b92062f4b..231552d2e564c70696a1512564af9648ddba6c05 100644 (file)
 
 
 
+static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
+                                  unsigned Offs)
+/* Adjust the offset for all stack accesses in the range Start to Stop, both
+ * inclusive. The function returns the number of instructions that have been
+ * inserted.
+ */
+{
+    /* Number of inserted instructions */
+    unsigned Inserted = 0;
+
+    /* Walk over all entries */
+    unsigned I = Start;
+    while (I <= Stop) {
+
+       CodeEntry* E = CS_GetEntry (S, I);
+
+       if (E->Use & REG_SP) {
+
+           CodeEntry* P;
+
+           /* Check for some things that should not happen */
+           CHECK (E->AM == AM65_ZP_INDY || E->RI->In.RegY >= (short) Offs);
+           CHECK (strcmp (E->Arg, "sp") == 0);
+
+           /* Get the code entry before this one. If it's a LDY, adjust the
+            * value.
+            */
+           P = CS_GetPrevEntry (S, I);
+           if (P && P->OPC == OP65_LDY && CE_KnownImm (P)) {
+
+               /* The Y load is just before the stack access, adjust it */
+               CE_SetNumArg (P, P->Num - Offs);
+
+           } else {
+
+               /* Insert a new load instruction before the stack access */
+               char Buf [16];
+               CodeEntry* X;
+               xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegY - Offs);
+               X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
+               CS_InsertEntry (S, X, I);
+
+               /* One more inserted entries */
+               ++Inserted;
+               ++Stop;
+
+               /* Be sure to skip the stack access for the next round */
+               ++I;
+
+           }
+
+       }
+
+       /* Next entry */
+       ++I;
+    }
+
+    /* Return the number of inserted entries */
+    return Inserted;
+}
+
+
+
+/*****************************************************************************/
+/*                      Actual optimization functions                       */
+/*****************************************************************************/
+
+
+
 static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store,
-                             const char* ZPLo, const char* ZPHi)
+                             const char* ZPLo, const char* ZPHi)
 /* Optimize the staspidx sequence if possible */
 {
     CodeEntry* X;
     CodeEntry* PushEntry;
     CodeEntry* StoreEntry;
 
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
     /* Get the push entry */
     PushEntry = CS_GetEntry (S, Push);
 
@@ -85,9 +151,6 @@ static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store,
     CS_DelEntry (S, Store);
     CS_DelEntry (S, Push);
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
     /* We changed the sequence */
     return 1;
 }
@@ -104,13 +167,7 @@ static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
     CodeEntry* AddEntry;
 
     /* We need the entry behind the add */
-    if ((N = CS_GetNextEntry (S, Add)) == 0) {
-       /* Unavailable */
-       return 0;
-    }
-
-    /* Generate register info */
-    CS_GenRegInfo (S);
+    CHECK ((N = CS_GetNextEntry (S, Add)) != 0);
 
     /* Get the push entry */
     PushEntry = CS_GetEntry (S, Push);
@@ -130,13 +187,31 @@ static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
     CS_InsertEntry (S, X, Add+1);
     X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
     CS_InsertEntry (S, X, Add+2);
-    if (PushEntry->RI->In.RegX == 0 && AddEntry->RI->In.RegX == 0) {
-       /* The high byte is zero on entry */
+    if (PushEntry->RI->In.RegX == 0) {
+       /* The high byte is the value in X plus the carry */
        CodeLabel* L = CS_GenLabel (S, N);
        X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI);
        CS_InsertEntry (S, X, Add+3);
        X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI);
        CS_InsertEntry (S, X, Add+4);
+    } else if (AddEntry->RI->In.RegX == 0) {
+       /* The high byte is that of the first operand plus carry */
+       CodeLabel* L;
+       if (PushEntry->RI->In.RegX >= 0) {
+           /* Value of first op high byte is known */
+           char Buf [16];
+           xsprintf (Buf, sizeof (Buf), "$%02X", PushEntry->RI->In.RegX);
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, AddEntry->LI);
+       } else {
+           /* Value of first op high byte is unknown */
+           X = NewCodeEntry (OP65_LDX, AM65_ZP, ZPHi, 0, AddEntry->LI);
+       }
+       CS_InsertEntry (S, X, Add+3);
+       L = CS_GenLabel (S, N);
+       X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+4);
+       X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+5);
     } else {
        /* High byte is unknown */
        X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AddEntry->LI);
@@ -155,9 +230,6 @@ static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
     CS_DelEntry (S, Add);
     CS_DelEntry (S, Push);
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
     /* We changed the sequence */
     return 1;
 }
@@ -172,9 +244,6 @@ static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And,
     CodeEntry* PushEntry;
     CodeEntry* AndEntry;
 
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
     /* Get the push entry */
     PushEntry = CS_GetEntry (S, Push);
 
@@ -213,9 +282,6 @@ static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And,
     CS_DelEntry (S, And);
     CS_DelEntry (S, Push);
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
     /* We changed the sequence */
     return 1;
 }
@@ -230,9 +296,6 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
     CodeEntry* PushEntry;
     CodeEntry* OrEntry;
 
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
     /* Get the push entry */
     PushEntry = CS_GetEntry (S, Push);
 
@@ -249,10 +312,11 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
     /* Inline the or */
     X = NewCodeEntry (OP65_ORA, AM65_ZP, ZPLo, 0, OrEntry->LI);
     CS_InsertEntry (S, X, Or+1);
-    if (PushEntry->RI->In.RegX >= 0 && OrEntry->RI->In.RegX == 0) {
-       /* Value of X will be that of the first operand */
+    if (PushEntry->RI->In.RegX >= 0 && OrEntry->RI->In.RegX >= 0) {
+       /* Both values known, precalculate the result */
        char Buf [16];
-       xsprintf (Buf, sizeof (Buf), "$%02X", PushEntry->RI->In.RegX);
+       int Val = (PushEntry->RI->In.RegX | OrEntry->RI->In.RegX);
+       xsprintf (Buf, sizeof (Buf), "$%02X", Val);
                X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, OrEntry->LI);
        CS_InsertEntry (S, X, Or+2);
     } else if (PushEntry->RI->In.RegX != 0) {
@@ -273,8 +337,60 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
     CS_DelEntry (S, Or);
     CS_DelEntry (S, Push);
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
+    /* We changed the sequence */
+    return 1;
+}
+
+
+
+static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor,
+                             const char* ZPLo, const char* ZPHi)
+/* Optimize the tosorax sequence if possible */
+{
+    CodeEntry* X;
+    CodeEntry* PushEntry;
+    CodeEntry* XorEntry;
+
+    /* Get the push entry */
+    PushEntry = CS_GetEntry (S, Push);
+
+    /* Store the value into the zeropage instead of pushing it */
+    X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+1);
+    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+2);
+
+    /* Correct the index of the add and get a pointer to the entry */
+    Xor += 2;
+    XorEntry = CS_GetEntry (S, Xor);
+
+    /* Inline the or */
+    X = NewCodeEntry (OP65_EOR, AM65_ZP, ZPLo, 0, XorEntry->LI);
+    CS_InsertEntry (S, X, Xor+1);
+    if (PushEntry->RI->In.RegX >= 0 && XorEntry->RI->In.RegX >= 0) {
+       /* Both values known, precalculate the result */
+       char Buf [16];
+       int Val = (PushEntry->RI->In.RegX ^ XorEntry->RI->In.RegX);
+       xsprintf (Buf, sizeof (Buf), "$%02X", Val);
+               X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+2);
+    } else if (PushEntry->RI->In.RegX != 0) {
+       /* High byte is unknown */
+               X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+2);
+       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+3);
+               X = NewCodeEntry (OP65_EOR, AM65_ZP, ZPHi, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+4);
+       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+5);
+       X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, XorEntry->LI);
+       CS_InsertEntry (S, X, Xor+6);
+    }
+
+    /* Remove the push and the call to the tosandax function */
+    CS_DelEntry (S, Xor);
+    CS_DelEntry (S, Push);
 
     /* We changed the sequence */
     return 1;
@@ -301,6 +417,7 @@ static const OptFuncDesc FuncTable[] = {
     { "tosaddax",       Opt_tosaddax    },
     { "tosandax",       Opt_tosandax    },
     { "tosorax",        Opt_tosorax     },
+    { "tosxorax",       Opt_tosxorax    },
 };
 #define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
 
@@ -337,7 +454,10 @@ unsigned OptStackOps (CodeSeg* S)
     int      InSeq = 0;       /* Inside a sequence */
     unsigned Push = 0;               /* Index of pushax */
     unsigned UsedRegs = 0;    /* Zeropage registers used in sequence */
+    unsigned I;
 
+    /* Generate register info */
+    CS_GenRegInfo (S);
 
     /* Look for a call to pushax followed by a call to some other function
      * that takes it's first argument on the stack, and the second argument
@@ -347,15 +467,15 @@ unsigned OptStackOps (CodeSeg* S)
      *
      *  - there must not be a jump or conditional branch (this may
      *    get relaxed later).
-     *  - there may not be accesses to local variables (may also be
-     *    relaxed later)
+     *  - there may not be accesses to local variables with unknown
+     *    offsets (because we have to adjust these offsets).
      *  - no subroutine calls
      *  - no jump labels
      *
      * Since we need a zero page register later, do also check the
      * intermediate code for zero page use.
      */
-    unsigned I = 0;
+    I = 0;
     while (I < CS_GetEntryCount (S)) {
 
        /* Get the next entry */
@@ -364,61 +484,69 @@ unsigned OptStackOps (CodeSeg* S)
        /* Handling depends if we're inside a sequence or not */
        if (InSeq) {
 
-           /* Subroutine call? */
-           if (E->OPC == OP65_JSR) {
+           if ((E->Info & OF_BRA) != 0                              ||
+               ((E->Use & REG_SP) != 0                         &&
+                (E->AM != AM65_ZP_INDY || E->RI->In.RegY < 0))      ||
+               CE_HasLabel (E)) {
 
-               /* Check if this is one of our functions */
-               const OptFuncDesc* F = FindFunc (E->Arg);
-               if (F) {
+               /* All this stuff is not allowed in a sequence */
+               InSeq = 0;
 
-                   /* Determine the register to use */
-                   const char* ZPLo;
-                   const char* ZPHi;
+           } else if (E->OPC == OP65_JSR) {
+
+                       /* Subroutine call: Check if this is one of our functions */
+               const OptFuncDesc* F = FindFunc (E->Arg);
+               if (F) {
+
+                   /* Determine the register to use */
+                   const char* ZPLo;
+                   const char* ZPHi;
                            UsedRegs |= GetRegInfo (S, I+1, REG_SREG | REG_PTR1 | REG_PTR2);
-                   if ((UsedRegs & REG_SREG) == REG_NONE) {
-                       /* SREG is available */
-                       ZPLo = "sreg";
-                       ZPHi = "sreg+1";
-                   } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
-                       ZPLo = "ptr1";
-                       ZPHi = "ptr1+1";
-                   } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
-                       ZPLo = "ptr2";
-                       ZPHi = "ptr2+1";
-                   } else {
-                       /* No registers available */
-                       ZPLo = 0;
-                       ZPHi = 0;
-                   }
-
-                   /* If we have a register, call the optimizer function */
-                   if (ZPLo && ZPHi) {
-                       Changes += F->Func (S, Push, I, ZPLo, ZPHi);
-                   }
-
-                   /* End of sequence */
-                   InSeq = 0;
-
-               } else if (strcmp (E->Arg, "pushax") == 0) {
-                   /* Restart the sequence */
-                   Push     = I;
-                   UsedRegs = REG_NONE;
-               } else {
-                   /* A call to an unkown subroutine ends the sequence */
-                   InSeq = 0;
-               }
-
-           } else if ((E->Info & OF_BRA) != 0 ||
-                      (E->Use & REG_SP) != 0  ||
-                      CE_HasLabel (E)) {
-
-               /* All this stuff is not allowed in a sequence */
-               InSeq = 0;
+                   if ((UsedRegs & REG_SREG) == REG_NONE) {
+                       /* SREG is available */
+                       ZPLo = "sreg";
+                       ZPHi = "sreg+1";
+                   } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
+                       ZPLo = "ptr1";
+                       ZPHi = "ptr1+1";
+                   } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
+                       ZPLo = "ptr2";
+                       ZPHi = "ptr2+1";
+                   } else {
+                       /* No registers available */
+                       ZPLo = 0;
+                       ZPHi = 0;
+                   }
+
+                   /* If we have a register, call the optimizer function */
+                   if (ZPLo && ZPHi) {
+
+                       /* Adjust stack offsets */
+                       unsigned Op = I + AdjustStackOffset (S, Push, I, 2);
+
+                       /* Call the optimizer function */
+                       Changes += F->Func (S, Push, Op, ZPLo, ZPHi);
+
+                       /* Regenerate register info */
+                       CS_GenRegInfo (S);
+                   }
+
+                   /* End of sequence */
+                   InSeq = 0;
+
+               } else if (strcmp (E->Arg, "pushax") == 0) {
+                   /* Restart the sequence */
+                   Push     = I;
+                   UsedRegs = REG_NONE;
+               } else {
+                   /* A call to an unkown subroutine ends the sequence */
+                   InSeq = 0;
+               }
 
            } else {
 
-               /* Other stuff: Track zeropage register usage */
-               UsedRegs |= (E->Use | E->Chg);
+               /* Other stuff: Track zeropage register usage */
+               UsedRegs |= (E->Use | E->Chg);
 
            }
 
@@ -436,6 +564,9 @@ unsigned OptStackOps (CodeSeg* S)
 
     }
 
+    /* Free the register info */
+    CS_FreeRegInfo (S);
+
     /* Return the number of changes made */
     return Changes;
 }