]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptstop.c
Minor improvement of optimizations
[cc65] / src / cc65 / coptstop.c
index 231552d2e564c70696a1512564af9648ddba6c05..39691a3ce39112670641c46f489e1e579955406d 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                                                 */
@@ -35,9 +35,6 @@
 
 #include <stdlib.h>
 
-/* common */
-#include "xsprintf.h"
-
 /* cc65 */
 #include "codeent.h"
 #include "codeinfo.h"
 
 
 /*****************************************************************************/
-/*                                 Helpers                                  */
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+/* Flags returned by DirectOp */
+#define OP_DIRECT       0x01            /* Direct op may be used */
+#define OP_ONSTACK      0x02            /* Operand is on stack */
+
+
+
+/*****************************************************************************/
+/*                                 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.
@@ -89,10 +98,8 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
            } 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);
+               const char* Arg = MakeHexArg (E->RI->In.RegY - Offs);
+               CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
                CS_InsertEntry (S, X, I);
 
                /* One more inserted entries */
@@ -116,6 +123,30 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
 
 
 
+static unsigned DirectOp (CodeEntry* E)
+/* 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;
+    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;
+        } else if (E->AM == AM65_ZP_INDY &&
+                   E->RI->In.RegY >= 0   &&
+                   strcmp (E->Arg, "sp") == 0) {
+            /* Load from stack with known offset is also ok */
+            Flags |= (OP_DIRECT | OP_ONSTACK);
+        }
+    }
+    return Flags;
+}
+
+
+
 /*****************************************************************************/
 /*                      Actual optimization functions                       */
 /*****************************************************************************/
@@ -157,51 +188,127 @@ 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)
+/* 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);
+
+    /* 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) {
+       /* Value of X is known */
+       const char* Arg = MakeHexArg (StoreEntry->RI->In.RegX);
+               X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, StoreEntry->LI);
+    } else {
+       /* Value unknown */
+       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, StoreEntry->LI);
+    }
+    CS_InsertEntry (S, X, Store+3);
+    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
+    CS_InsertEntry (S, X, Store+4);
+
+    /* Remove the push and the call to the staspidx function */
+    CS_DelEntry (S, Store);
+    CS_DelEntry (S, Push);
+
+    /* We changed the sequence */
+    return 1;
+}
+
+
+
 static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
                              const char* ZPLo, const char* ZPHi)
 /* Optimize the tosaddax sequence if possible */
 {
-    CodeEntry* N;
-    CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* AddEntry;
+    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 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);
+
     /* 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);
+    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 */
+    }
 
-    /* Correct the index of the add and get a pointer to the entry */
-    Add += 2;
+    /* Get a pointer to the add entry */
     AddEntry = CS_GetEntry (S, Add);
 
     /* Inline the add */
     X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI);
     CS_InsertEntry (S, X, Add+1);
-    X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
+    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) {
-       /* 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);
+       /* 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);
+       /* 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 */
+           const char* Arg = MakeHexArg (PushEntry->RI->In.RegX);
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, AddEntry->LI);
        } else {
            /* Value of first op high byte is unknown */
            X = NewCodeEntry (OP65_LDX, AM65_ZP, ZPHi, 0, AddEntry->LI);
@@ -237,28 +344,56 @@ 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)
+                             const char* ZPLo, const char* ZPHi)
 /* Optimize the tosandax sequence if possible */
 {
-    CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* AndEntry;
+    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);
+
     /* 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);
+    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 */
+    }
 
-    /* Correct the index of the add and get a pointer to the entry */
-    And += 2;
+    /* Get a pointer to the and entry */
     AndEntry = CS_GetEntry (S, And);
 
     /* Inline the and */
-    X = NewCodeEntry (OP65_AND, AM65_ZP, ZPLo, 0, AndEntry->LI);
+    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) {
        /* The high byte is zero */
@@ -289,35 +424,61 @@ 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)
+                            const char* ZPLo, const char* ZPHi)
 /* Optimize the tosorax sequence if possible */
 {
-    CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* OrEntry;
+    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);
+
     /* 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);
+    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 */
+    }
 
-    /* Correct the index of the add and get a pointer to the entry */
-    Or += 2;
+    /* Get a pointer to the or entry */
     OrEntry = CS_GetEntry (S, Or);
 
     /* Inline the or */
-    X = NewCodeEntry (OP65_ORA, AM65_ZP, ZPLo, 0, OrEntry->LI);
+    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) {
        /* Both values known, precalculate the result */
-       char Buf [16];
-       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);
+       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) {
        /* High byte is unknown */
@@ -333,7 +494,7 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
        CS_InsertEntry (S, X, Or+6);
     }
 
-    /* Remove the push and the call to the tosandax function */
+    /* Remove the push and the call to the tosorax function */
     CS_DelEntry (S, Or);
     CS_DelEntry (S, Push);
 
@@ -345,35 +506,61 @@ 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)
-/* Optimize the tosorax sequence if possible */
+/* Optimize the tosxorax sequence if possible */
 {
-    CodeEntry* X;
-    CodeEntry* PushEntry;
-    CodeEntry* XorEntry;
+    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);
+
     /* 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);
+    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 */
+    }
 
-    /* Correct the index of the add and get a pointer to the entry */
-    Xor += 2;
+    /* Get a pointer to the entry */
     XorEntry = CS_GetEntry (S, Xor);
 
-    /* Inline the or */
-    X = NewCodeEntry (OP65_EOR, AM65_ZP, ZPLo, 0, XorEntry->LI);
+    /* 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) {
        /* 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);
+       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) {
        /* High byte is unknown */
                X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, XorEntry->LI);
@@ -399,25 +586,34 @@ static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor,
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                  Code                                    */
 /*****************************************************************************/
 
 
 
+/* Flags for the functions */
+typedef enum {
+    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);
+                            const char* ZPLo, const char* ZPHi);
 typedef struct OptFuncDesc OptFuncDesc;
 struct OptFuncDesc {
-    const char*         Name;   /* Name of the replaced runtime function */
-    OptFunc             Func;   /* Function pointer */
+    const char*     Name;   /* Name of the replaced runtime function */
+    OptFunc         Func;   /* Function pointer */
+    STOP_FLAGS      Flags;  /* Flags */
 };
 
 static const OptFuncDesc FuncTable[] = {
-    { "staspidx",       Opt_staspidx    },
-    { "tosaddax",       Opt_tosaddax    },
-    { "tosandax",       Opt_tosandax    },
-    { "tosorax",        Opt_tosorax     },
-    { "tosxorax",       Opt_tosxorax    },
+    { "staspidx",   Opt_staspidx,  STOP_NONE },
+    { "staxspidx",  Opt_staxspidx, STOP_A_UNUSED },
+    { "tosaddax",   Opt_tosaddax,  STOP_NONE },
+    { "tosandax",   Opt_tosandax,  STOP_NONE },
+    { "tosorax",    Opt_tosorax,   STOP_NONE },
+    { "tosxorax",   Opt_tosxorax,  STOP_NONE },
 };
 #define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
 
@@ -498,28 +694,40 @@ unsigned OptStackOps (CodeSeg* S)
                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) {
+                   const char* ZPLo = 0;
+                   const char* ZPHi = 0;
+                   int PreCondOk    = 1;
+
+                   /* Check the flags */
+                   if (F->Flags & STOP_A_UNUSED) {
+                       /* a must be unused later */
+                       if (RegAUsed (S, I+1)) {
+                           /* Cannot optimize */
+                           PreCondOk = 0;
+                       }
+                   }
+
+                   /* Determine the zero page locations to use */
+                   if (PreCondOk) {
+                       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 */
+                           PreCondOk = 0;
+                       }
+                   }
+
+                   /* If preconditions are ok, call the optimizer function */
+                   if (PreCondOk) {
 
                        /* Adjust stack offsets */
                        unsigned Op = I + AdjustStackOffset (S, Push, I, 2);