]> git.sur5r.net Git - cc65/commitdiff
New/changed optimizations
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 Oct 2002 20:32:31 +0000 (20:32 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 Oct 2002 20:32:31 +0000 (20:32 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@1443 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeopt.c
src/cc65/codeseg.c
src/cc65/codeseg.h
src/cc65/coptadd.c
src/cc65/coptind.c
src/cc65/coptind.h
src/cc65/coptstop.c

index f155e4b02748417a23ebad89672fa8b5cdae7d49..5bbc46e6e93393c9454d2b79efa74f410dc6cd8f 100644 (file)
@@ -1013,7 +1013,7 @@ static unsigned OptDecouple (CodeSeg* S)
                break;
 
            case OP65_INY:
-               if (E->RI->In.RegY >= 0) {                   
+               if (E->RI->In.RegY >= 0) {
                    Arg = MakeHexArg ((E->RI->In.RegY + 1) & 0xFF);
                    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
                }
@@ -1097,7 +1097,7 @@ static unsigned OptDecouple (CodeSeg* S)
                break;
 
            case OP65_TXA:
-               if (E->RI->In.RegX >= 0) {                   
+               if (E->RI->In.RegX >= 0) {
                    Arg = MakeHexArg (In->RegX);
                    X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
                }
@@ -1425,6 +1425,7 @@ static OptFunc DOptPtrLoad6       = { OptPtrLoad6,     "OptPtrLoad6",     100, 0,
 static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPush1               = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPushPop      = { OptPushPop,      "OptPushPop",        0, 0, 0, 0, 0, 0 };
 static OptFunc DOptShift1              = { OptShift1,       "OptShift1",       100, 0, 0, 0, 0, 0 };
 static OptFunc DOptShift2              = { OptShift2,       "OptShift2",       100, 0, 0, 0, 0, 0 };
 /*static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };*/
@@ -1477,7 +1478,8 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrLoad6,
     &DOptPtrStore1,
     &DOptPtrStore2,
-    &DOptPush1,
+    &DOptPush1, 
+    &DOptPushPop,
     &DOptRTS,
     &DOptRTSJumps1,
     &DOptRTSJumps2,
@@ -1805,6 +1807,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
                C += RunOptFunc (S, &DOptDupLoads, 1);
                C += RunOptFunc (S, &DOptStoreLoad, 1);
                C += RunOptFunc (S, &DOptTransfers, 1);
+        C += RunOptFunc (S, &DOptPushPop, 1);
 
        Changes += C;
 
index eda3ae502fea9800b4949eef5904e00742407fc8..530ffe205ba2b78e03172965d4d9fbce99fa5c30 100644 (file)
@@ -594,6 +594,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index)
 /* Delete an entry from the code segment. This includes moving any associated
  * labels, removing references to labels and even removing the referenced labels
  * if the reference count drops to zero.
+ * Note: Labels are moved forward if possible, that is, they are moved to the
+ * next insn (not the preceeding one).
  */
 {
     /* Get the code entry for the given index */
index 67de3efbafc4d60236804f780ae4b8229010f20f..c149a2dc771d32be3217af2cc01f4e4555ac40ca 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
+/* (C) 2001-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
@@ -112,6 +112,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index);
 /* Delete an entry from the code segment. This includes moving any associated
  * labels, removing references to labels and even removing the referenced labels
  * if the reference count drops to zero.
+ * Note: Labels are moved forward if possible, that is, they are moved to the
+ * next insn (not the preceeding one).
  */
 
 void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count);
index 93d2a70fc11b577755fc473ded2dffa1010227a7..558dd85ab79bd67eea3bebaa368e9ce7d2186873 100644 (file)
 unsigned OptAdd1 (CodeSeg* S)
 /* Search for the sequence
  *
- *             jsr     pushax
- *      ldy     xxx
- *     ldx     #$00
- *      lda     (sp),y
+ *      ldy     #xx
+ *      jsr     ldaxysp
+ *      jsr     pushax
+ *      ldy     #yy
+ *      jsr     ldaxysp
  *      jsr     tosaddax
  *
  * and replace it by:
- *
- *      ldy     xxx-2
+ *      
+ *      ldy     #xx-1
+ *      lda     (sp),y
  *      clc
+ *      ldy     #yy-3
  *      adc     (sp),y
- *      bcc     L
- *      inx
- * L:
+ *      pha
+ *      ldy     #xx
+ *      lda     (sp),y
+ *      ldy     #yy-2
+ *      adc     (sp),y
+ *      tax
+ *      pla
  */
 {
     unsigned Changes = 0;
@@ -71,58 +78,78 @@ unsigned OptAdd1 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[5];
+       CodeEntry* L[6];
 
        /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+               L[0] = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (CE_IsCall (E, "pushax")          &&
-                   CS_GetEntries (S, L, I+1, 5)     &&
-                   L[0]->OPC == OP65_LDY            &&
+               if (L[0]->OPC == OP65_LDY            &&
            CE_KnownImm (L[0])               &&
-           !CE_HasLabel (L[0])              &&
-           L[1]->OPC == OP65_LDX            &&
-           CE_KnownImm (L[1])               &&
-           L[1]->Num == 0                   &&
-           !CE_HasLabel (L[1])              &&
-           L[2]->OPC == OP65_LDA            &&
-           !CE_HasLabel (L[2])              &&
-           CE_IsCall (L[3], "tosaddax")     &&
-           !CE_HasLabel (L[3])) {
+           !CS_RangeHasLabel (S, I+1, 5)    &&
+                   CS_GetEntries (S, L+1, I+1, 5)   &&
+                   CE_IsCall (L[1], "ldaxysp")      &&
+                   CE_IsCall (L[2], "pushax")       &&
+                   L[3]->OPC == OP65_LDY            &&
+           CE_KnownImm (L[3])               &&
+                   CE_IsCall (L[4], "ldaxysp")      &&
+                   CE_IsCall (L[5], "tosaddax")) {
 
            CodeEntry* X;
-           CodeLabel* Label;
+            const char* Arg;
 
-           /* Remove the call to pushax */
-           CS_DelEntry (S, I);
+                   /* Correct the stack of the first Y register load */
+           CE_SetNumArg (L[0], L[0]->Num - 1);
 
-           /* Correct the stack offset (needed since pushax was removed) */
-           CE_SetNumArg (L[0], L[0]->Num - 2);
+            /* lda (sp),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+1);
 
-           /* Add the clc . */
-           X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+1);
-
-           /* Remove the load */
-           CS_DelEntry (S, I+3);      /* lda */
-           CS_DelEntry (S, I+2);      /* ldx */
-
-           /* Add the adc */
-           X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
+                   /* clc */
+           X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI);
            CS_InsertEntry (S, X, I+2);
 
-           /* Generate the branch label and the branch */
-           Label = CS_GenLabel (S, L[4]);
-           X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI);
+            /* ldy #yy-3 */
+           Arg = MakeHexArg (L[3]->Num - 3);
+            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
            CS_InsertEntry (S, X, I+3);
 
-           /* Generate the increment of the high byte */
-           X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI);
+           /* adc (sp),y */
+           X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
            CS_InsertEntry (S, X, I+4);
 
-           /* Delete the call to tosaddax */
-           CS_DelEntry (S, I+5);
+            /* pha */
+            X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[5]->LI);
+            CS_InsertEntry (S, X, I+5);
+
+            /* ldy #xx (beware: L[0] has changed) */
+           Arg = MakeHexArg (L[0]->Num + 1);
+            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
+           CS_InsertEntry (S, X, I+6);
+
+            /* lda (sp),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+7);
+
+            /* ldy #yy-2 */
+           Arg = MakeHexArg (L[3]->Num - 2);
+            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
+           CS_InsertEntry (S, X, I+8);
+
+           /* adc (sp),y */
+           X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
+           CS_InsertEntry (S, X, I+9);
+
+            /* tax */
+            X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[5]->LI);
+            CS_InsertEntry (S, X, I+10);
+
+            /* pla */
+            X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[5]->LI);
+            CS_InsertEntry (S, X, I+11);
+
+           /* Delete the old code */
+           CS_DelEntries (S, I+12, 5);
 
            /* Remember, we had changes */
            ++Changes;
index d0b9809c9d6f4ecd5874e634ff5fb32bdbf876b7..f517088e2d1fe35843fc9f381c9be3841dd34653 100644 (file)
@@ -1054,9 +1054,9 @@ unsigned OptTransfers (CodeSeg* S)
                    (N->Info & OF_XFR) != 0) {
 
            /* Check if it's a transfer and back */
-                   if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) ||
-                       (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) ||
-                       (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) ||
+                   if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+1)) ||
+                       (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+1)) ||
+                       (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+1)) ||
                        (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+1))) {
 
                /* If the next insn is a conditional branch, check if the insn
@@ -1074,16 +1074,16 @@ unsigned OptTransfers (CodeSeg* S)
                    P = CS_GetEntry (S, I-1);
                    if ((P->Info & OF_SETF) == 0) {
                        /* Does not set the flags */
-                       goto NextEntry;
-                   }
-               }
+                       goto NextEntry;
+                   }
+               }
 
-               /* Remove both transfers */
-               CS_DelEntry (S, I+1);
-               CS_DelEntry (S, I);
+               /* Remove both transfers */
+               CS_DelEntry (S, I+1);
+               CS_DelEntry (S, I);
 
-               /* Remember, we had changes */
-               ++Changes;
+               /* Remember, we had changes */
+               ++Changes;
            }
        }
 
@@ -1099,6 +1099,71 @@ NextEntry:
 
 
 
+unsigned OptPushPop (CodeSeg* S)
+/* Remove a PHA/PLA sequence were A is not used later */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       CodeEntry* N;
+
+       /* Get next entry */
+               CodeEntry* E = CS_GetEntry (S, I);
+
+       /* Check if it is a PLA instruction that does not have a label and
+         * where the register value is not used later and that is not followed
+         * by a conditional branch.
+        */
+        if (E->OPC == OP65_PLA                  &&
+                   !CE_HasLabel (E)                    &&
+                   (N = CS_GetNextEntry (S, I)) != 0   &&
+                   (N->Info & OF_CBRA) == 0            &&
+            !RegAUsed (S, I+1)) {
+
+            /* Search back until we find the matching PHA instruction. If we
+             * find a label or another PLA somewhere in between, bail out
+             * since this may have side effects.
+             */
+            unsigned J = I;
+            while (J-- > 0) {
+
+                /* Get the previous entry */
+                CodeEntry* P = CS_GetEntry (S, J);
+
+                /* Check this entry */
+                if (P->OPC == OP65_PHA) {
+
+                    /* Found the matching push, remove both */
+                    CS_DelEntry (S, I);
+                    CS_DelEntry (S, J);
+
+                    /* Remember that we had changes and bail out */
+                    ++Changes;
+                    break;
+
+                } else if (CE_HasLabel (P) || P->OPC == OP65_PLA) {
+
+                    /* OOPS - too dangerous! */
+                    break;
+
+                }
+            }
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
 /*****************************************************************************/
 /*                          Optimize branch types                           */
 /*****************************************************************************/
index 44fe8f1ceeab8675c1838179d16f085c5534d394..0eb4cf33c6a02a1d9241cb96571ca81edfe04c64 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
+/* (C) 2001-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
@@ -105,6 +105,9 @@ unsigned OptStoreLoad (CodeSeg* S);
 unsigned OptTransfers (CodeSeg* S);
 /* Remove transfers from one register to another and back */
 
+unsigned OptPushPop (CodeSeg* S);
+/* Remove a PHA/PLA sequence were A is not used later */
+
 unsigned OptBranchDist (CodeSeg* S);
 /* Change branches for the distance needed. */
 
index 39691a3ce39112670641c46f489e1e579955406d..cca49c871eb0db701d70351214f5385160362ff5 100644 (file)
 
 
 
+/* Structure that holds the needed data */
+typedef struct StackOpData StackOpData;
+struct StackOpData {
+    CodeSeg*    Code;                   /* Pointer to code segment */
+    unsigned    Flags;                  /* Flags to remember things */
+    unsigned    PushIndex;              /* Index of call to pushax in codeseg */
+    unsigned    OpIndex;                /* Index of actual operation */
+    CodeEntry*  PrevEntry;              /* Entry before the call to pushax */
+    CodeEntry*  PushEntry;              /* Pointer to entry with call to pushax */
+    CodeEntry*  OpEntry;                /* Pointer to entry with op */
+    CodeEntry*  NextEntry;              /* Entry after the op */
+    const char* ZPLo;                   /* Lo byte of zero page loc to use */
+    const char* ZPHi;                   /* Hi byte of zero page loc to use */
+    unsigned    IP;                     /* Insertion point used by some routines */
+};
+
 /* Flags returned by DirectOp */
 #define OP_DIRECT       0x01            /* Direct op may be used */
 #define OP_ONSTACK      0x02            /* Operand is on stack */
 
 
 /*****************************************************************************/
-/*                                 Helpers                                  */
+/*                                         Helpers                                  */
 /*****************************************************************************/
 
 
 
 static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
-                                  unsigned Offs)
+                                  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.
@@ -123,64 +139,173 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
 
 
 
-static unsigned DirectOp (CodeEntry* E)
+static void InsertEntry (StackOpData* D, CodeEntry* E, unsigned Index)
+/* Insert a new entry. Depending on Index, D->PushIndex and D->OpIndex will
+ * be adjusted by this function.
+ */
+{
+    /* Insert the entry into the code segment */
+    CS_InsertEntry (D->Code, E, Index);
+
+    /* Adjust the indices if necessary */
+    if (D->PushEntry && Index <= D->PushIndex) {
+        ++D->PushIndex;
+    }
+    if (D->OpEntry && Index <= D->OpIndex) {
+        ++D->OpIndex;
+    }
+}
+
+
+
+static void DelEntry (StackOpData* D, unsigned Index)
+/* Delete an entry. Depending on Index, D->PushIndex and D->OpIndex will be
+ * adjusted by this function, and PushEntry/OpEntry may get invalidated.
+ */
+{
+    /* Delete the entry from the code segment */
+    CS_DelEntry (D->Code, Index);
+
+    /* Adjust the indices if necessary */
+    if (Index < D->PushIndex) {
+        --D->PushIndex;
+    } else if (Index == D->PushIndex) {
+        D->PushEntry = 0;
+    }
+    if (Index < D->OpIndex) {
+        --D->OpIndex;
+    } else if (Index == D->OpIndex) {
+        D->OpEntry = 0;
+    }
+}
+
+
+
+static void CheckDirectOp (StackOpData* D)
 /* Check if the given entry is a lda instruction with an addressing mode
  * that allows us to replace it by another operation (like ora). If so, we may
  * use this location for the or and must not save the value in the zero
  * page location.
  */
 {
-    unsigned Flags = 0;
+    /* We need the entry before the push */
+    CodeEntry* E;
+    CHECK ((E = D->PrevEntry) != 0);
+
     if (E->OPC == OP65_LDA) {
         if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) {
             /* These insns are all ok and replaceable */
-            Flags |= OP_DIRECT;
+            D->Flags |= OP_DIRECT;
         } else if (E->AM == AM65_ZP_INDY &&
                    E->RI->In.RegY >= 0   &&
-                   strcmp (E->Arg, "sp") == 0) {
+                          (E->Use & REG_SP) != 0) {
             /* Load from stack with known offset is also ok */
-            Flags |= (OP_DIRECT | OP_ONSTACK);
+            D->Flags |= (OP_DIRECT | OP_ONSTACK);
+        }
+    }
+}
+
+
+
+static void ReplacePushByStore (StackOpData* D)
+/* Replace the call to the push subroutine by a store into the zero page
+ * location (actually, the push is not replaced, because we need it for
+ * later, but the name is still ok since the push will get removed at the
+ * end of each routine.
+ */
+{
+    CodeEntry* X;
+
+    /* Store the value into the zeropage instead of pushing it */
+    X = NewCodeEntry (OP65_STX, AM65_ZP, D->ZPHi, 0, D->PushEntry->LI);
+    InsertEntry (D, X, D->PushIndex+1);
+    if ((D->Flags & OP_DIRECT) == 0) {
+       X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPLo, 0, D->PushEntry->LI);
+               InsertEntry (D, X, D->PushIndex+1);
+    }
+}
+
+
+
+static void AddOpLow (StackOpData* D, opc_t OPC)
+/* Add an op for the low byte of an operator. This function honours the
+ * OP_DIRECT and OP_ONSTACK flags and generates the necessary instructions.
+ * All code is inserted at the current insertion point.
+ */
+{
+    CodeEntry* X;
+
+    if ((D->Flags & OP_DIRECT) != 0) {
+               /* Op with a variable location. If the location is on the stack, we
+         * need to reload the Y register.
+         */
+        if ((D->Flags & OP_ONSTACK) != 0) {
+            const char* Arg = MakeHexArg (D->PrevEntry->RI->In.RegY);
+            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+            InsertEntry (D, X, D->IP++);
         }
+       X = NewCodeEntry (OPC, D->PrevEntry->AM, D->PrevEntry->Arg, 0, D->OpEntry->LI);
+    } else {
+       /* Op with temp storage */
+       X = NewCodeEntry (OPC, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
     }
-    return Flags;
+    InsertEntry (D, X, D->IP++);
+}
+
+
+
+static void AddOpHigh (StackOpData* D, opc_t OPC)
+/* Add an op for the high byte of an operator. Special cases (constant values
+ * or similar have to be checked separately, the function covers only the
+ * generic case. Code is inserted at the insertion point.
+ */
+{
+    CodeEntry* X;
+
+    /* High byte is unknown */
+    X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+    X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+    X = NewCodeEntry (OPC, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+    X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+    X = NewCodeEntry (OP65_LDA, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+}
+
+
+
+static void RemovePushAndOp (StackOpData* D)
+/* Remove the call to pushax and the call to the operator subroutine */
+{
+    DelEntry (D, D->OpIndex);
+    DelEntry (D, D->PushIndex);
 }
 
 
 
 /*****************************************************************************/
-/*                      Actual optimization functions                       */
+/*                      Actual optimization functions                       */
 /*****************************************************************************/
 
 
 
-static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store,
-                             const char* ZPLo, const char* ZPHi)
+static unsigned Opt_staspidx (StackOpData* D)
 /* Optimize the staspidx sequence if possible */
 {
     CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* StoreEntry;
-
-    /* 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 store and get a pointer to the entry */
-    Store += 2;
-    StoreEntry = CS_GetEntry (S, Store);
+    ReplacePushByStore (D);
 
-    /* Inline the store */
-    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
-    CS_InsertEntry (S, X, Store+1);
+    /* Replace the store subroutine call by a direct op */
+    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->OpIndex+1);
 
     /* Remove the push and the call to the staspidx function */
-    CS_DelEntry (S, Store);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -188,47 +313,33 @@ static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store,
 
 
 
-static unsigned Opt_staxspidx (CodeSeg* S, unsigned Push, unsigned Store,
-                              const char* ZPLo, const char* ZPHi)
+static unsigned Opt_staxspidx (StackOpData* D)
 /* Optimize the staxspidx sequence if possible */
 {
     CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* StoreEntry;
-
-    /* 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 store and get a pointer to the entry */
-    Store += 2;
-    StoreEntry = CS_GetEntry (S, Store);
+    ReplacePushByStore (D);
 
     /* Inline the store */
-    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
-    CS_InsertEntry (S, X, Store+1);
-    X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, StoreEntry->LI);
-    CS_InsertEntry (S, X, Store+2);
-    if (StoreEntry->RI->In.RegX >= 0) {
+    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->OpIndex+1);
+    X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->OpIndex+2);
+    if (D->OpEntry->RI->In.RegX >= 0) {
        /* Value of X is known */
-       const char* Arg = MakeHexArg (StoreEntry->RI->In.RegX);
-               X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, StoreEntry->LI);
+       const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX);
+               X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
     } else {
        /* Value unknown */
-       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, StoreEntry->LI);
+       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
     }
-    CS_InsertEntry (S, X, Store+3);
-    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
-    CS_InsertEntry (S, X, Store+4);
+    InsertEntry (D, X, D->OpIndex+3);
+    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->OpIndex+4);
 
     /* Remove the push and the call to the staspidx function */
-    CS_DelEntry (S, Store);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -236,106 +347,65 @@ static unsigned Opt_staxspidx (CodeSeg* S, unsigned Push, unsigned Store,
 
 
 
-static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
-                             const char* ZPLo, const char* ZPHi)
+static unsigned Opt_tosaddax (StackOpData* D)
 /* Optimize the tosaddax sequence if possible */
 {
-    CodeEntry*  P;
-    CodeEntry*  N;
     CodeEntry*  X;
-    CodeEntry*  PushEntry;
-    CodeEntry*  AddEntry;
-    unsigned    Flags;
 
 
     /* We need the entry behind the add */
-    CHECK ((N = CS_GetNextEntry (S, Add)) != 0);
-
-    /* And the entry before the push */
-    CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
-
-    /* Get the push entry */
-    PushEntry = CS_GetEntry (S, Push);
+    CHECK (D->NextEntry != 0);
 
     /* Check the entry before the push. If it's a lda instruction with an
      * addressing mode that allows us to replace it, we may use this
      * location for the op and must not save the value in the zero page
      * location.
      */
-    Flags = DirectOp (P);
+    CheckDirectOp (D);
 
     /* Store the value into the zeropage instead of pushing it */
-    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
-    CS_InsertEntry (S, X, Push+1);
-    ++Add;      /* Correct the index */
-    if ((Flags & OP_DIRECT) == 0) {
-       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
-       CS_InsertEntry (S, X, Push+1);
-       ++Add;  /* Correct the index */
-    }
-
-    /* Get a pointer to the add entry */
-    AddEntry = CS_GetEntry (S, Add);
+    ReplacePushByStore (D);
 
     /* Inline the add */
-    X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI);
-    CS_InsertEntry (S, X, Add+1);
-    if ((Flags & OP_DIRECT) != 0) {
-               /* Add a variable location. If the location is on the stack, we
-         * need to reload the Y register.
-         */
-        if ((Flags & OP_ONSTACK) != 0) {
-            X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, AddEntry->LI);
-            CS_InsertEntry (S, X, Add);
-            ++Add;
-        }
-       X = NewCodeEntry (OP65_ADC, P->AM, P->Arg, 0, AddEntry->LI);
-    } else {
-       /* Add from temp storage */
-       X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
-    }
-    CS_InsertEntry (S, X, Add+2);
-    if (PushEntry->RI->In.RegX == 0) {
+    D->IP = D->OpIndex+1;
+    X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, D->OpEntry->LI);
+    InsertEntry (D, X, D->IP++);
+
+    /* Low byte */
+    AddOpLow (D, OP65_ADC);
+
+    /* High byte */
+    if (D->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 = CS_GenLabel (D->Code, D->NextEntry);
+       X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
+       X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
+    } else if (D->OpEntry->RI->In.RegX == 0) {
+               /* The high byte is that of the first operand plus carry */
        CodeLabel* L;
-       if (PushEntry->RI->In.RegX >= 0) {
+       if (D->PushEntry->RI->In.RegX >= 0) {
            /* Value of first op high byte is known */
-           const char* Arg = MakeHexArg (PushEntry->RI->In.RegX);
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, AddEntry->LI);
+           const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX);
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
        } else {
            /* Value of first op high byte is unknown */
-           X = NewCodeEntry (OP65_LDX, AM65_ZP, ZPHi, 0, AddEntry->LI);
+           X = NewCodeEntry (OP65_LDX, AM65_ZP, D->ZPHi, 0, D->OpEntry->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);
+       InsertEntry (D, X, D->IP++);
+       L = CS_GenLabel (D->Code, D->NextEntry);
+       X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
+       X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
     } else {
        /* High byte is unknown */
-       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AddEntry->LI);
-       CS_InsertEntry (S, X, Add+3);
-       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, AddEntry->LI);
-       CS_InsertEntry (S, X, Add+4);
-       X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPHi, 0, AddEntry->LI);
-       CS_InsertEntry (S, X, Add+5);
-       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, AddEntry->LI);
-       CS_InsertEntry (S, X, Add+6);
-       X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, AddEntry->LI);
-       CS_InsertEntry (S, X, Add+7);
+        AddOpHigh (D, OP65_ADC);
     }
 
     /* Remove the push and the call to the tosaddax function */
-    CS_DelEntry (S, Add);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -343,79 +413,37 @@ static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
 
 
 
-static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And,
-                             const char* ZPLo, const char* ZPHi)
+static unsigned Opt_tosandax (StackOpData* D)
 /* Optimize the tosandax sequence if possible */
 {
-    CodeEntry*  P;
     CodeEntry*  X;
-    CodeEntry*  PushEntry;
-    CodeEntry*  AndEntry;
-    unsigned    Flags;
-
-    /* Get the entry before the push */
-    CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
-
-    /* Get the push entry */
-    PushEntry = CS_GetEntry (S, Push);
 
     /* Check the entry before the push. If it's a lda instruction with an
      * addressing mode that allows us to replace it, we may use this
      * location for the op and must not save the value in the zero page
      * location.
      */
-    Flags = DirectOp (P);
+    CheckDirectOp (D);
 
     /* Store the value into the zeropage instead of pushing it */
-    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
-    CS_InsertEntry (S, X, Push+1);
-    ++And;      /* Correct the index */
-    if ((Flags & OP_DIRECT) == 0) {
-       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
-       CS_InsertEntry (S, X, Push+1);
-       ++And;  /* Correct the index */
-    }
+    ReplacePushByStore (D);
 
-    /* Get a pointer to the and entry */
-    AndEntry = CS_GetEntry (S, And);
+    /* Inline the and, low byte */
+    D->IP = D->OpIndex + 1;
+    AddOpLow (D, OP65_AND);
 
-    /* Inline the and */
-    if ((Flags & OP_DIRECT) != 0) {
-       /* And with variable location. If the location is on the stack, we
-         * need to reload the Y register.
-         */
-        if ((Flags & OP_ONSTACK) != 0) {
-            X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, AndEntry->LI);
-            CS_InsertEntry (S, X, And);
-            ++And;
-        }
-       X = NewCodeEntry (OP65_AND, P->AM, P->Arg, 0, AndEntry->LI);
-    } else {
-       /* And with temp storage */
-       X = NewCodeEntry (OP65_AND, AM65_ZP, ZPLo, 0, AndEntry->LI);
-    }
-    CS_InsertEntry (S, X, And+1);
-    if (PushEntry->RI->In.RegX == 0 || AndEntry->RI->In.RegX == 0) {
+    /* High byte */
+    if (D->PushEntry->RI->In.RegX == 0 || D->OpEntry->RI->In.RegX == 0) {
        /* The high byte is zero */
-               X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+2);
+               X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
     } else {
        /* High byte is unknown */
-               X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+2);
-       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+3);
-       X = NewCodeEntry (OP65_AND, AM65_ZP, ZPHi, 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+4);
-       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+5);
-       X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, AndEntry->LI);
-       CS_InsertEntry (S, X, And+6);
+        AddOpHigh (D, OP65_AND);
     }
 
     /* Remove the push and the call to the tosandax function */
-    CS_DelEntry (S, And);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -423,80 +451,38 @@ static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And,
 
 
 
-static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
-                            const char* ZPLo, const char* ZPHi)
+static unsigned Opt_tosorax (StackOpData* D)
 /* Optimize the tosorax sequence if possible */
 {
-    CodeEntry*  P;
     CodeEntry*  X;
-    CodeEntry*  PushEntry;
-    CodeEntry*  OrEntry;
-    unsigned    Flags;
-
-    /* Get the entry before the push */
-    CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
-
-    /* Get the push entry */
-    PushEntry = CS_GetEntry (S, Push);
 
     /* Check the entry before the push. If it's a lda instruction with an
      * addressing mode that allows us to replace it, we may use this
      * location for the op and must not save the value in the zero page
      * location.
      */
-    Flags = DirectOp (P);
+    CheckDirectOp (D);
 
     /* Store the value into the zeropage instead of pushing it */
-    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
-    CS_InsertEntry (S, X, Push+1);
-    ++Or;  /* Correct the index */
-    if ((Flags & OP_DIRECT) == 0) {
-       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
-       CS_InsertEntry (S, X, Push+1);
-       ++Or;  /* Correct the index */
-    }
+    ReplacePushByStore (D);
 
-    /* Get a pointer to the or entry */
-    OrEntry = CS_GetEntry (S, Or);
+    /* Inline the or, low byte */
+    D->IP = D->OpIndex + 1;
+    AddOpLow (D, OP65_ORA);
 
-    /* Inline the or */
-    if ((Flags & OP_DIRECT) != 0) {
-       /* Or with variable location. If the location is on the stack, we
-         * need to reload the Y register.
-         */
-        if ((Flags & OP_ONSTACK) != 0) {
-            X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, OrEntry->LI);
-            CS_InsertEntry (S, X, Or);
-            ++Or;
-        }
-       X = NewCodeEntry (OP65_ORA, P->AM, P->Arg, 0, OrEntry->LI);
-    } else {
-        /* Or with temp storage */
-       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) {
+    /* High byte */
+    if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) {
        /* Both values known, precalculate the result */
-       const char* Arg = MakeHexArg (PushEntry->RI->In.RegX | OrEntry->RI->In.RegX);
-               X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+2);
-    } else if (PushEntry->RI->In.RegX != 0) {
+       const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX | D->OpEntry->RI->In.RegX);
+               X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
+    } else if (D->PushEntry->RI->In.RegX != 0) {
        /* High byte is unknown */
-               X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+2);
-       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+3);
-               X = NewCodeEntry (OP65_ORA, AM65_ZP, ZPHi, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+4);
-       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+5);
-       X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, OrEntry->LI);
-       CS_InsertEntry (S, X, Or+6);
+        AddOpHigh (D, OP65_ORA);
     }
 
     /* Remove the push and the call to the tosorax function */
-    CS_DelEntry (S, Or);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -504,80 +490,38 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
 
 
 
-static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor,
-                             const char* ZPLo, const char* ZPHi)
+static unsigned Opt_tosxorax (StackOpData* D)
 /* Optimize the tosxorax sequence if possible */
 {
-    CodeEntry*  P;
     CodeEntry*  X;
-    CodeEntry*  PushEntry;
-    CodeEntry*  XorEntry;
-    unsigned    Flags;
-
-    /* Get the entry before the push */
-    CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
-
-    /* Get the push entry */
-    PushEntry = CS_GetEntry (S, Push);
 
     /* Check the entry before the push. If it's a lda instruction with an
      * addressing mode that allows us to replace it, we may use this
      * location for the op and must not save the value in the zero page
      * location.
      */
-    Flags = DirectOp (P);
+    CheckDirectOp (D);
 
     /* Store the value into the zeropage instead of pushing it */
-    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
-    CS_InsertEntry (S, X, Push+1);
-    ++Xor;  /* Correct the index */
-    if ((Flags & OP_DIRECT) != 0) {
-       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
-       CS_InsertEntry (S, X, Push+1);
-       ++Xor;  /* Correct the index */
-    }
+    ReplacePushByStore (D);
 
-    /* Get a pointer to the entry */
-    XorEntry = CS_GetEntry (S, Xor);
+    /* Inline the xor, low byte */
+    D->IP = D->OpIndex + 1;
+    AddOpLow (D, OP65_EOR);
 
-    /* Inline the xor */
-    if ((Flags & OP_DIRECT) != 0) {
-               /* Xor with a variable location. If the location is on the stack, we
-         * need to reload the Y register.
-         */
-        if ((Flags & OP_ONSTACK) != 0) {
-            X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, XorEntry->LI);
-            CS_InsertEntry (S, X, Xor);
-            ++Xor;
-        }
-       X = NewCodeEntry (OP65_EOR, P->AM, P->Arg, 0, XorEntry->LI);
-    } else {
-       /* Xor with temp storage */
-       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) {
+    /* High byte */
+    if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) {
        /* Both values known, precalculate the result */
-       const char* Arg = MakeHexArg (PushEntry->RI->In.RegX ^ XorEntry->RI->In.RegX);
-               X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, XorEntry->LI);
-       CS_InsertEntry (S, X, Xor+2);
-    } else if (PushEntry->RI->In.RegX != 0) {
+       const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX ^ D->OpEntry->RI->In.RegX);
+               X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
+       InsertEntry (D, X, D->IP++);
+    } else if (D->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);
+        AddOpHigh (D, OP65_EOR);
     }
 
     /* Remove the push and the call to the tosandax function */
-    CS_DelEntry (S, Xor);
-    CS_DelEntry (S, Push);
+    RemovePushAndOp (D);
 
     /* We changed the sequence */
     return 1;
@@ -593,13 +537,12 @@ static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor,
 
 /* Flags for the functions */
 typedef enum {
-    STOP_NONE,             /* Nothing special */
+    STOP_NONE,             /* Nothing special */
     STOP_A_UNUSED           /* Call only if a unused later */
 } STOP_FLAGS;
 
 
-typedef unsigned (*OptFunc) (CodeSeg* S, unsigned Push, unsigned Store,
-                            const char* ZPLo, const char* ZPHi);
+typedef unsigned (*OptFunc) (StackOpData* D);
 typedef struct OptFuncDesc OptFuncDesc;
 struct OptFuncDesc {
     const char*     Name;   /* Name of the replaced runtime function */
@@ -637,6 +580,33 @@ static const OptFuncDesc* FindFunc (const char* Name)
 
 
 
+static int CmpHarmless (const void* Key, const void* Entry)
+/* Compare function for bsearch */
+{
+    return strcmp (Key, *(const char**)Entry);
+}
+
+
+
+static int HarmlessCall (const char* Name)
+/* Check if this is a call to a harmless subroutine that will not interrupt
+ * the pushax/op sequence when encountered.
+ */
+{
+    static const char* Tab[] = {
+        "ldaxysp",
+    };
+
+    void* R = bsearch (Name,
+                       Tab,
+                       sizeof (Tab) / sizeof (Tab[0]),
+                       sizeof (Tab[0]),
+                       CmpHarmless);
+    return (R != 0);
+}
+
+
+
 /*****************************************************************************/
 /*                                  Code                                    */
 /*****************************************************************************/
@@ -646,11 +616,12 @@ static const OptFuncDesc* FindFunc (const char* Name)
 unsigned OptStackOps (CodeSeg* S)
 /* Optimize operations that take operands via the stack */
 {
-    unsigned Changes = 0;     /* Number of changes in one run */
-    int      InSeq = 0;       /* Inside a sequence */
-    unsigned Push = 0;               /* Index of pushax */
-    unsigned UsedRegs = 0;    /* Zeropage registers used in sequence */
-    unsigned I;
+    unsigned    Changes = 0;    /* Number of changes in one run */
+    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);
@@ -694,9 +665,8 @@ unsigned OptStackOps (CodeSeg* S)
                const OptFuncDesc* F = FindFunc (E->Arg);
                if (F) {
 
-                   const char* ZPLo = 0;
-                   const char* ZPHi = 0;
-                   int PreCondOk    = 1;
+                    StackOpData Data;
+                   int PreCondOk = 1;
 
                    /* Check the flags */
                    if (F->Flags & STOP_A_UNUSED) {
@@ -712,14 +682,14 @@ unsigned OptStackOps (CodeSeg* S)
                        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";
+                           Data.ZPLo = "sreg";
+                           Data.ZPHi = "sreg+1";
                        } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
-                           ZPLo = "ptr1";
-                           ZPHi = "ptr1+1";
+                           Data.ZPLo = "ptr1";
+                           Data.ZPHi = "ptr1+1";
                        } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
-                           ZPLo = "ptr2";
-                           ZPHi = "ptr2+1";
+                           Data.ZPLo = "ptr2";
+                           Data.ZPHi = "ptr2+1";
                        } else {
                            /* No registers available */
                            PreCondOk = 0;
@@ -730,13 +700,22 @@ unsigned OptStackOps (CodeSeg* S)
                    if (PreCondOk) {
 
                        /* 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);
+                       Data.OpIndex = I + AdjustStackOffset (S, Push, I, 2);
+
+                        /* Prepare the remainder of the data structure */
+                        Data.Code      = S;
+                        Data.Flags     = 0;
+                        Data.PushIndex = Push;
+                        Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex);
+                        Data.PushEntry = CS_GetEntry (S, Data.PushIndex);
+                        Data.OpEntry   = E;
+                        Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex);
+
+                               /* Call the optimizer function */
+                       Changes += F->Func (&Data);
+
+                       /* Regenerate register info */
+                       CS_GenRegInfo (S);
                    }
 
                    /* End of sequence */
@@ -746,7 +725,7 @@ unsigned OptStackOps (CodeSeg* S)
                    /* Restart the sequence */
                    Push     = I;
                    UsedRegs = REG_NONE;
-               } else {
+               } else if (!HarmlessCall (E->Arg)) {
                    /* A call to an unkown subroutine ends the sequence */
                    InSeq = 0;
                }