]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
Added HuC6280 cpu (will be treated as a 65C02)
[cc65] / src / cc65 / codeopt.c
index 4797e8b518668079942a3e13b94182a977a8a7de..e26e747f42c2d8451d847e85015fbed322fac581 100644 (file)
@@ -6,9 +6,9 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
+/* (C) 2001-2003 Ullrich von Bassewitz                                       */
+/*               Römerstraße 52                                              */
+/*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
@@ -39,9 +39,9 @@
 /* common */
 #include "abend.h"
 #include "chartype.h"
+#include "cpu.h"
 #include "print.h"
 #include "xmalloc.h"
-#include "xsprintf.h"
 
 /* cc65 */
 #include "asmlabel.h"
 #include "coptcmp.h"
 #include "coptind.h"
 #include "coptneg.h"
+#include "coptpush.h"
+#include "coptsize.h"
 #include "coptstop.h"
+#include "coptstore.h"
 #include "coptsub.h"
 #include "copttest.h"
-#include "cpu.h"
 #include "error.h"
 #include "global.h"
 #include "codeopt.h"
 
 
 
+/*****************************************************************************/
+/*                                     Data                                  */
+/*****************************************************************************/
+
+
+
+/* Shift types */
+enum {
+    SHIFT_NONE,
+    SHIFT_ASR_1,
+    SHIFT_ASL_1,
+    SHIFT_LSR_1,
+    SHIFT_LSL_1
+};
+
+
+
 /*****************************************************************************/
 /*                             Optimize shifts                              */
 /*****************************************************************************/
@@ -118,13 +137,17 @@ static unsigned OptShift1 (CodeSeg* S)
 
 static unsigned OptShift2 (CodeSeg* S)
 /* A call to the shraxN routine may get replaced by one or more lsr insns
- * if the value of X is not used later.
+ * if the value of X is zero.
  */
 {
     unsigned Changes = 0;
+    unsigned I;
+
+    /* Generate register info */
+    CS_GenRegInfo (S);
 
     /* Walk over the entries */
-    unsigned I = 0;
+    I = 0;
     while (I < CS_GetEntryCount (S)) {
 
        /* Get next entry */
@@ -135,13 +158,13 @@ static unsigned OptShift2 (CodeSeg* S)
                    strncmp (E->Arg, "shrax", 5) == 0        &&
            strlen (E->Arg) == 6                     &&
            IsDigit (E->Arg[5])                      &&
-           !RegXUsed (S, I+1)) {
+                   E->RI->In.RegX == 0) {
 
            /* Insert shift insns */
            unsigned Count = E->Arg[5] - '0';
            while (Count--) {
                CodeEntry* X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI);
-               CS_InsertEntry (S, X, I+1);
+               CS_InsertEntry (S, X, I+1);
            }
 
            /* Delete the call to shlax */
@@ -157,6 +180,215 @@ static unsigned OptShift2 (CodeSeg* S)
 
     }
 
+    /* Free the register info */
+    CS_FreeRegInfo (S);
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned GetShiftType (const char* Sub)
+/* Helper function for OptShift3 */
+{
+    if (*Sub == 'a') {
+        if (strcmp (Sub+1, "slax1") == 0) {
+            return SHIFT_ASL_1;
+        } else if (strcmp (Sub+1, "srax1") == 0) {
+            return SHIFT_ASR_1;
+        }
+    } else if (*Sub == 's') {
+        if (strcmp (Sub+1, "hlax1") == 0) {
+            return SHIFT_LSL_1;
+        } else if (strcmp (Sub+1, "hrax1") == 0) {
+            return SHIFT_LSR_1;
+        }
+    }
+    return SHIFT_NONE;
+}
+
+
+
+static unsigned OptShift3 (CodeSeg* S)
+/* Search for the sequence
+ *
+ *      lda     xxx
+ *      ldx     yyy
+ *      jsr     aslax1/asrax1/shlax1/shrax1
+ *      sta     aaa
+ *      stx     bbb
+ *
+ * and replace it by
+ *
+ *      lda     xxx
+ *      asl     a
+ *      sta     aaa
+ *      lda     yyy
+ *      rol     a
+ *      sta     bbb
+ *
+ * or similar, provided that a/x is not used later
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        unsigned ShiftType;
+       CodeEntry* L[5];
+
+       /* Get next entry */
+               L[0] = CS_GetEntry (S, I);
+
+       /* Check for the sequence */
+               if (L[0]->OPC == OP65_LDA                               &&
+            (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP)       &&
+                   CS_GetEntries (S, L+1, I+1, 4)                      &&
+            !CS_RangeHasLabel (S, I+1, 4)                       &&
+            L[1]->OPC == OP65_LDX                               &&
+            (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP)       &&
+            L[2]->OPC == OP65_JSR                               &&
+            (ShiftType = GetShiftType (L[2]->Arg)) != SHIFT_NONE&&
+                   L[3]->OPC == OP65_STA                               &&
+            (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)       &&
+            L[4]->OPC == OP65_STX                               &&
+            (L[4]->AM == AM65_ABS || L[4]->AM == AM65_ZP)       &&
+            !RegAXUsed (S, I+5)) {
+
+            CodeEntry* X;
+
+            /* Handle the four shift types differently */
+            switch (ShiftType) {
+
+                case SHIFT_ASR_1:
+                    X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
+                    CS_InsertEntry (S, X, I+5);
+                    X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+6);
+                    X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+7);
+                    X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
+                    CS_InsertEntry (S, X, I+8);
+                    X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
+                    CS_InsertEntry (S, X, I+9);
+                    X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+10);
+                    X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
+                    CS_InsertEntry (S, X, I+11);
+                    CS_DelEntries (S, I, 5);
+                    break;
+
+                case SHIFT_LSR_1:
+                    X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
+                    CS_InsertEntry (S, X, I+5);
+                    X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+6);
+                    X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
+                    CS_InsertEntry (S, X, I+7);
+                    X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
+                    CS_InsertEntry (S, X, I+8);
+                    X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+9);
+                    X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
+                    CS_InsertEntry (S, X, I+10);
+                    CS_DelEntries (S, I, 5);
+                    break;
+
+                case SHIFT_LSL_1:
+                case SHIFT_ASL_1:
+                    /* These two are identical */
+                    X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+1);
+                    X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
+                    CS_InsertEntry (S, X, I+2);
+                    X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
+                    CS_InsertEntry (S, X, I+3);
+                    X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, I+4);
+                    X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
+                    CS_InsertEntry (S, X, I+5);
+                    CS_DelEntries (S, I+6, 4);
+                    break;
+
+            }
+
+           /* Remember, we had changes */
+            ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                              Optimize loads                               */
+/*****************************************************************************/
+
+
+
+static unsigned OptLoad1 (CodeSeg* S)
+/* Search for a call to ldaxysp where X is not used later and replace it by
+ * a load of just the A register.
+ */
+{
+    unsigned I;
+    unsigned Changes = 0;
+
+    /* Generate register info */
+    CS_GenRegInfo (S);
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       CodeEntry* E;
+
+       /* Get next entry */
+               E = CS_GetEntry (S, I);
+
+       /* Check for the sequence */
+               if (CE_IsCallTo (E, "ldaxysp")          &&
+            RegValIsKnown (E->RI->In.RegY)      &&
+            !RegXUsed (S, I+1)) {
+
+            CodeEntry* X;
+
+            /* Reload the Y register */
+            const char* Arg = MakeHexArg (E->RI->In.RegY - 1);
+            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            /* Load from stack */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI);
+            CS_InsertEntry (S, X, I+2);
+
+            /* Now remove the call to the subroutine */
+           CS_DelEntry (S, I);
+
+           /* Remember, we had changes */
+            ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Free the register info */
+    CS_FreeRegInfo (S);
+
     /* Return the number of changes made */
     return Changes;
 }
@@ -196,7 +428,7 @@ static unsigned OptPtrStore1Sub (CodeSeg* S, unsigned I, CodeEntry** const L)
               (L[1] = CS_GetNextEntry (S, I)) != 0       &&
               L[1]->OPC == OP65_SBC                      &&
               !CE_HasLabel (L[1])) {
-       return 2;
+       return 2;
     }
 
 
@@ -227,6 +459,20 @@ static unsigned OptPtrStore1 (CodeSeg* S)
  *     subop
  *      ldy     yyy
  *      sta     (ptr1),y
+ *
+ * In case a/x is loaded from the register bank before the pushax, we can even
+ * use the register bank instead of ptr1.
+ */
+/*
+ *     jsr     pushax
+ *      ldy     xxx
+ *      jsr     ldauidx
+ *      ldx     #$00
+ *      lda     (zp),y
+ *      subop
+ *      ldy     yyy
+ *      sta     (zp),y
+ *     jsr     staspidx
  */
 {
     unsigned Changes = 0;
@@ -242,56 +488,90 @@ static unsigned OptPtrStore1 (CodeSeg* S)
                L[0] = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (CE_IsCall (L[0], "pushax")              &&
+               if (CE_IsCallTo (L[0], "pushax")            &&
                    CS_GetEntries (S, L+1, I+1, 3)          &&
                    L[1]->OPC == OP65_LDY                   &&
            CE_KnownImm (L[1])                      &&
            !CE_HasLabel (L[1])                     &&
-                   CE_IsCall (L[2], "ldauidx")             &&
+                   CE_IsCallTo (L[2], "ldauidx")           &&
            !CE_HasLabel (L[2])                     &&
                    (K = OptPtrStore1Sub (S, I+3, L+3)) > 0 &&
            CS_GetEntries (S, L+3+K, I+3+K, 2)      &&
                    L[3+K]->OPC == OP65_LDY                 &&
            CE_KnownImm (L[3+K])                    &&
            !CE_HasLabel (L[3+K])                   &&
-           CE_IsCall (L[4+K], "staspidx")          &&
+           CE_IsCallTo (L[4+K], "staspidx")        &&
            !CE_HasLabel (L[4+K])) {
 
-           CodeEntry* X;
 
-           /* Create and insert the stores */
-                   X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+1);
-
-           X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+2);
-
-           /* Delete the call to pushax */
-           CS_DelEntry (S, I);
+            const char* RegBank = 0;
+            const char* ZPLoc   = "ptr1";
+           CodeEntry* X;
 
-           /* Delete the call to ldauidx */
-           CS_DelEntry (S, I+3);
 
-           /* Insert the load from ptr1 */
+            /* Get the preceeding two instructions and check them. We check
+             * for:
+             *          lda     regbank+n
+             *          ldx     regbank+n+1
+             */
+            if (I > 1) {
+                CodeEntry* P[2];
+                P[0] = CS_GetEntry (S, I-2);
+                P[1] = CS_GetEntry (S, I-1);
+                if (P[0]->OPC == OP65_LDA &&
+                    P[0]->AM  == AM65_ZP  &&
+                    P[1]->OPC == OP65_LDX &&
+                    P[1]->AM  == AM65_ZP  &&
+                    !CE_HasLabel (P[1])   &&
+                    strncmp (P[0]->Arg, "regbank+", 8) == 0) {
+
+                    unsigned Len = strlen (P[0]->Arg);
+
+                    if (strncmp (P[0]->Arg, P[1]->Arg, Len) == 0 &&
+                        P[1]->Arg[Len+0] == '+'                  &&
+                        P[1]->Arg[Len+1] == '1'                  &&
+                        P[1]->Arg[Len+2] == '\0') {
+
+                        /* Ok, found. Use the name of the register bank */
+                        RegBank = ZPLoc = P[0]->Arg;
+                    }
+                }
+            }
+
+           /* Insert the load via the zp pointer */
            X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
            CS_InsertEntry (S, X, I+3);
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[2]->LI);
-           CS_InsertEntry (S, X, I+4);
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, ZPLoc, 0, L[2]->LI);
+           CS_InsertEntry (S, X, I+4);
 
-           /* Insert the store through ptr1 */
-           X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+6+K);
+           /* Insert the store through the zp pointer */
+           X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLoc, 0, L[3]->LI);
+           CS_InsertEntry (S, X, I+6+K);
 
-           /* Delete the call to staspidx */
-           CS_DelEntry (S, I+7+K);
+           /* Delete the old code */
+           CS_DelEntry (S, I+7+K);     /* jsr spaspidx */
+            CS_DelEntry (S, I+2);       /* jsr ldauidx */
 
-           /* Remember, we had changes */
-           ++Changes;
+           /* Create and insert the stores into the zp pointer if needed */
+            if (RegBank == 0) {
+                X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+1);
+                X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+2);
+            }
 
-       }
+            /* Delete more old code. Do it here to keep a label attached to
+             * entry I in place.
+             */
+            CS_DelEntry (S, I);         /* jsr pushax */
 
-       /* Next entry */
-       ++I;
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
 
     }
 
@@ -304,18 +584,24 @@ static unsigned OptPtrStore1 (CodeSeg* S)
 static unsigned OptPtrStore2 (CodeSeg* S)
 /* Search for the sequence:
  *
- *     jsr     pushax
- *      lda     xxx
- *      ldy     yyy
- *     jsr     staspidx
+ *      lda     #<(label+0)
+ *      ldx     #>(label+0)
+ *      clc
+ *      adc     xxx
+ *      bcc     L
+ *      inx
+ * L:   jsr    pushax
+ *     ldx     #$00
+ *     lda     yyy
+ *     ldy     #$00
+ *      jsr     staspidx
  *
  * and replace it by:
  *
- *      sta     ptr1
- *      stx     ptr1+1
- *      lda     xxx
- *      ldy     yyy
- *      sta     (ptr1),y
+ *      ldy     xxx
+ *     ldx     #$00
+ *     lda     yyy
+ *      sta    label,y
  */
 {
     unsigned Changes = 0;
@@ -324,39 +610,65 @@ static unsigned OptPtrStore2 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[4];
+       CodeEntry* L[11];
+       unsigned Len;
 
        /* Get next entry */
                L[0] = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (CE_IsCall (L[0], "pushax")          &&
-                   CS_GetEntries (S, L+1, I+1, 3)      &&
-                   L[1]->OPC == OP65_LDA               &&
-           !CE_HasLabel (L[1])                 &&
-           L[2]->OPC == OP65_LDY               &&
-           !CE_HasLabel (L[2])                 &&
-           CE_IsCall (L[3], "staspidx")        &&
-           !CE_HasLabel (L[3])) {
+               if (L[0]->OPC == OP65_LDA                            &&
+           L[0]->AM == AM65_IMM                             &&
+                   CS_GetEntries (S, L+1, I+1, 10)                  &&
+                   L[1]->OPC == OP65_LDX                            &&
+           L[1]->AM == AM65_IMM                             &&
+           L[2]->OPC == OP65_CLC                            &&
+           L[3]->OPC == OP65_ADC                            &&
+           (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
+                   (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
+                   L[4]->JumpTo != 0                                &&
+                   L[4]->JumpTo->Owner == L[6]                      &&
+           L[5]->OPC == OP65_INX                            &&
+            CE_IsCallTo (L[6], "pushax")                     &&
+            L[7]->OPC == OP65_LDX                            &&
+            L[8]->OPC == OP65_LDA                            &&
+                   L[9]->OPC == OP65_LDY                            &&
+                   CE_KnownImm (L[9])                               &&
+            L[9]->Num == 0                                   &&
+                   CE_IsCallTo (L[10], "staspidx")                  &&
+                   !CS_RangeHasLabel (S, I+1, 5)                    &&
+            !CS_RangeHasLabel (S, I+7, 4)                    &&
+           /* Check the label last because this is quite costly */
+           (Len = strlen (L[0]->Arg)) > 3                   &&
+           L[0]->Arg[0] == '<'                              &&
+           L[0]->Arg[1] == '('                              &&
+           strlen (L[1]->Arg) == Len                        &&
+           L[1]->Arg[0] == '>'                              &&
+                   memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
 
            CodeEntry* X;
+           char* Label;
 
-           /* Create and insert the stores */
-                   X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+1);
+           /* We will create all the new stuff behind the current one so
+            * we keep the line references.
+            */
+           X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+11);
 
-           X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+2);
+                   X = NewCodeEntry (OP65_LDX, L[7]->AM, L[7]->Arg, 0, L[7]->LI);
+           CS_InsertEntry (S, X, I+12);
 
-           /* Delete the call to pushax */
-           CS_DelEntry (S, I);
+            X = NewCodeEntry (OP65_LDA, L[8]->AM, L[8]->Arg, 0, L[8]->LI);
+            CS_InsertEntry (S, X, I+13);
 
-           /* Insert the store through ptr1 */
-           X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+4);
+           Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
+           Label[Len-3] = '\0';
+                   X = NewCodeEntry (OP65_STA, AM65_ABSY, Label, 0, L[10]->LI);
+           CS_InsertEntry (S, X, I+14);
+           xfree (Label);
 
-           /* Delete the call to staspidx */
-           CS_DelEntry (S, I+5);
+           /* Remove the old code */
+           CS_DelEntries (S, I, 11);
 
            /* Remember, we had changes */
            ++Changes;
@@ -381,85 +693,6 @@ static unsigned OptPtrStore2 (CodeSeg* S)
 
 
 static unsigned OptPtrLoad1 (CodeSeg* S)
-/* Search for the sequence:
- *
- *      tax
- *      dey
- *      lda     (sp),y             # May be any destination
- *      ldy     ...
- *     jsr     ldauidx
- *
- * and replace it by:
- *
- *      sta     ptr1+1
- *      dey
- *      lda     (sp),y
- *      sta     ptr1
- *      ldy     ...
- *      ldx     #$00
- *      lda     (ptr1),y
- */
-{
-    unsigned Changes = 0;
-
-    /* Walk over the entries */
-    unsigned I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-       CodeEntry* L[5];
-
-       /* Get next entry */
-               L[0] = CS_GetEntry (S, I);
-
-       /* Check for the sequence */
-               if (L[0]->OPC == OP65_TAX               &&
-                   CS_GetEntries (S, L+1, I+1, 4)      &&
-                   L[1]->OPC == OP65_DEY               &&
-           !CE_HasLabel (L[1])                 &&
-           L[2]->OPC == OP65_LDA               &&
-           !CE_HasLabel (L[2])                 &&
-           L[3]->OPC == OP65_LDY               &&
-           !CE_HasLabel (L[3])                 &&
-           CE_IsCall (L[4], "ldauidx")         &&
-           !CE_HasLabel (L[4])) {
-
-           CodeEntry* X;
-
-                   /* Store the high byte and remove the TAX instead */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+1);
-           CS_DelEntry (S, I);
-
-           /* Store the low byte */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI);
-           CS_InsertEntry (S, X, I+3);
-
-           /* Delete the call to ldauidx */
-           CS_DelEntry (S, I+5);
-
-           /* Load high and low byte */
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+5);
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+6);
-
-           /* Remember, we had changes */
-           ++Changes;
-
-       }
-
-       /* Next entry */
-       ++I;
-
-    }
-
-    /* Return the number of changes made */
-    return Changes;
-}
-
-
-
-static unsigned OptPtrLoad2 (CodeSeg* S)
 /* Search for the sequence:
  *
  *      clc
@@ -500,58 +733,60 @@ static unsigned OptPtrLoad2 (CodeSeg* S)
                if (L[0]->OPC == OP65_CLC               &&
                    CS_GetEntries (S, L+1, I+1, 8)      &&
            L[1]->OPC == OP65_ADC               &&
-           !CE_HasLabel (L[1])                 &&
                    L[2]->OPC == OP65_TAY               &&
-           !CE_HasLabel (L[2])                 &&
            L[3]->OPC == OP65_TXA               &&
-           !CE_HasLabel (L[3])                 &&
            L[4]->OPC == OP65_ADC               &&
-           !CE_HasLabel (L[4])                 &&
            L[5]->OPC == OP65_TAX               &&
-           !CE_HasLabel (L[5])                 &&
            L[6]->OPC == OP65_TYA               &&
-           !CE_HasLabel (L[6])                 &&
            L[7]->OPC == OP65_LDY               &&
-           !CE_HasLabel (L[7])                 &&
-                   CE_IsCall (L[8], "ldauidx")         &&
-           !CE_HasLabel (L[8])) {
+                   CE_IsCallTo (L[8], "ldauidx")       &&
+            !CS_RangeHasLabel (S, I+1, 8)) {
 
            CodeEntry* X;
            CodeEntry* P;
 
-                   /* Store the low byte and remove the TAY instead */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[1]->LI);
-           CS_InsertEntry (S, X, I+2);
-           CS_DelEntry (S, I+3);
+            /* Track the insertion point */
+            unsigned IP = I+2;
 
-           /* Store the high byte */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
-           CS_InsertEntry (S, X, I+5);
+            /* sta ptr1 */
+            X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI);
+            CS_InsertEntry (S, X, IP++);
 
-           /* If the instruction before the adc is a ldx, replace the
-            * txa by and lda with the same location of the ldx.
+           /* If the instruction before the clc is a ldx, replace the
+            * txa by an lda with the same location of the ldx. Otherwise
+             * transfer the value in X to A.
             */
            if ((P = CS_GetPrevEntry (S, I)) != 0 &&
-               P->OPC == OP65_LDX                &&
+               P->OPC == OP65_LDX                &&
                !CE_HasLabel (P)) {
-
                X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI);
-               CS_InsertEntry (S, X, I+4);
-               CS_DelEntry (S, I+3);
-           }
+           } else {
+                X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
+            }
+            CS_InsertEntry (S, X, IP++);
 
-           /* Delete more transfer insns */
-           CS_DelEntry (S, I+7);
-           CS_DelEntry (S, I+6);
+            /* adc yyy */
+            X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
+            CS_InsertEntry (S, X, IP++);
 
-           /* Delete the call to ldauidx */
-           CS_DelEntry (S, I+7);
+            /* sta ptr1+1 */
+            X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI);
+            CS_InsertEntry (S, X, IP++);
 
-           /* Load high and low byte */
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[7]->LI);
-           CS_InsertEntry (S, X, I+7);
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[7]->LI);
-           CS_InsertEntry (S, X, I+8);
+            /* ldy ... */
+            X = NewCodeEntry (OP65_LDY, L[7]->AM, L[7]->Arg, 0, L[7]->LI);
+            CS_InsertEntry (S, X, IP++);
+
+            /* ldx #$00 */
+            X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI);
+            CS_InsertEntry (S, X, IP++);
+
+            /* lda (ptr1),y */
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI);
+           CS_InsertEntry (S, X, IP++);
+
+            /* Remove the old instructions */
+            CS_DelEntries (S, IP, 7);
 
            /* Remember, we had changes */
            ++Changes;
@@ -569,7 +804,7 @@ static unsigned OptPtrLoad2 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad3 (CodeSeg* S)
+static unsigned OptPtrLoad2 (CodeSeg* S)
 /* Search for the sequence:
  *
  *      adc            xxx
@@ -601,7 +836,7 @@ static unsigned OptPtrLoad3 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[9];
+       CodeEntry* L[9];
 
        /* Get next entry */
                L[0] = CS_GetEntry (S, I);
@@ -610,53 +845,44 @@ static unsigned OptPtrLoad3 (CodeSeg* S)
                if (L[0]->OPC == OP65_ADC               &&
                    CS_GetEntries (S, L+1, I+1, 8)      &&
                    L[1]->OPC == OP65_PHA               &&
-           !CE_HasLabel (L[1])                 &&
-           L[2]->OPC == OP65_TXA               &&
-           !CE_HasLabel (L[2])                 &&
-           L[3]->OPC == OP65_INY               &&
-           !CE_HasLabel (L[3])                 &&
+           L[2]->OPC == OP65_TXA               &&
+           L[3]->OPC == OP65_INY               &&
                    L[4]->OPC == OP65_ADC               &&
-           !CE_HasLabel (L[4])                 &&
-           L[5]->OPC == OP65_TAX               &&
-           !CE_HasLabel (L[5])                 &&
-           L[6]->OPC == OP65_PLA               &&
-           !CE_HasLabel (L[6])                 &&
-           L[7]->OPC == OP65_LDY               &&
-           !CE_HasLabel (L[7])                 &&
-                   CE_IsCall (L[8], "ldauidx")         &&
-           !CE_HasLabel (L[8])) {
+           L[5]->OPC == OP65_TAX               &&
+           L[6]->OPC == OP65_PLA               &&
+           L[7]->OPC == OP65_LDY               &&
+                   CE_IsCallTo (L[8], "ldauidx")       &&
+                   !CS_RangeHasLabel (S, I+1, 8)) {
 
-           CodeEntry* X;
+           CodeEntry* X;
 
                    /* Store the low byte and remove the PHA instead */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+1);
-           CS_DelEntry (S, I+2);
-
-           /* Store the high byte */
-           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
-           CS_InsertEntry (S, X, I+5);
+           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+1);
 
-           /* Delete more transfer and PLA insns */
-           CS_DelEntry (S, I+7);
-           CS_DelEntry (S, I+6);
+           /* Store the high byte */
+           X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
+           CS_InsertEntry (S, X, I+6);
 
-           /* Delete the call to ldauidx */
-           CS_DelEntry (S, I+7);
+           /* Load high and low byte */
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
+           CS_InsertEntry (S, X, I+10);
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
+           CS_InsertEntry (S, X, I+11);
 
-           /* Load high and low byte */
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
-           CS_InsertEntry (S, X, I+7);
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
-           CS_InsertEntry (S, X, I+8);
+           /* Delete the old code */
+           CS_DelEntry (S, I+12);      /* jsr ldauidx */
+           CS_DelEntry (S, I+8);       /* pla */
+           CS_DelEntry (S, I+7);       /* tax */
+           CS_DelEntry (S, I+2);       /* pha */
 
-           /* Remember, we had changes */
-           ++Changes;
+           /* Remember, we had changes */
+           ++Changes;
 
-       }
+       }
 
-       /* Next entry */
-       ++I;
+       /* Next entry */
+       ++I;
 
     }
 
@@ -666,7 +892,7 @@ static unsigned OptPtrLoad3 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad4 (CodeSeg* S)
+static unsigned OptPtrLoad3 (CodeSeg* S)
 /* Search for the sequence:
  *
  *      lda     #<(label+0)
@@ -703,23 +929,124 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
                    CS_GetEntries (S, L+1, I+1, 7)                   &&
                    L[1]->OPC == OP65_LDX                            &&
            L[1]->AM == AM65_IMM                             &&
-           !CE_HasLabel (L[1])                              &&
            L[2]->OPC == OP65_CLC                            &&
-           !CE_HasLabel (L[2])                              &&
            L[3]->OPC == OP65_ADC                            &&
            (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
-           !CE_HasLabel (L[3])                              &&
                    (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
                    L[4]->JumpTo != 0                                &&
                    L[4]->JumpTo->Owner == L[6]                      &&
-           !CE_HasLabel (L[4])                              &&
            L[5]->OPC == OP65_INX                            &&
-           !CE_HasLabel (L[5])                              &&
            L[6]->OPC == OP65_LDY                            &&
            CE_KnownImm (L[6])                               &&
            L[6]->Num == 0                                   &&
-                   CE_IsCall (L[7], "ldauidx")                      &&
-           !CE_HasLabel (L[7])                              &&
+                   CE_IsCallTo (L[7], "ldauidx")                    &&
+                   !CS_RangeHasLabel (S, I+1, 5)                    &&
+            !CE_HasLabel (L[7])                              &&
+           /* Check the label last because this is quite costly */
+           (Len = strlen (L[0]->Arg)) > 3                   &&
+           L[0]->Arg[0] == '<'                              &&
+           L[0]->Arg[1] == '('                              &&
+           strlen (L[1]->Arg) == Len                        &&
+           L[1]->Arg[0] == '>'                              &&
+                   memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
+
+           CodeEntry* X;
+           char* Label;
+
+           /* We will create all the new stuff behind the current one so
+            * we keep the line references.
+            */
+           X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+8);
+
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+9);
+
+           Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
+           Label[Len-3] = '\0';
+           X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+10);
+           xfree (Label);
+
+           /* Remove the old code */
+           CS_DelEntries (S, I, 8);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned OptPtrLoad4 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ *      lda     #<(label+0)
+ *      ldx     #>(label+0)
+ *      ldy     #$xx
+ *      clc
+ *      adc     (sp),y
+ *      bcc     L
+ *      inx
+ * L:   ldy     #$00
+ *      jsr     ldauidx
+ *
+ * and replace it by:
+ *
+ *      ldy     #$xx
+ *      lda     (sp),y
+ *      tay
+ *      ldx     #$00
+ *      lda     label,y
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       CodeEntry* L[9];
+       unsigned Len;
+
+       /* Get next entry */
+               L[0] = CS_GetEntry (S, I);
+
+       /* Check for the sequence */
+               if (L[0]->OPC == OP65_LDA                            &&
+           L[0]->AM == AM65_IMM                             &&
+                   CS_GetEntries (S, L+1, I+1, 8)                   &&
+                   L[1]->OPC == OP65_LDX                            &&
+           L[1]->AM == AM65_IMM                             &&
+           !CE_HasLabel (L[1])                              &&
+           L[2]->OPC == OP65_LDY                            &&
+           CE_KnownImm (L[2])                               &&
+           !CE_HasLabel (L[2])                              &&
+           L[3]->OPC == OP65_CLC                            &&
+           !CE_HasLabel (L[3])                              &&
+           L[4]->OPC == OP65_ADC                            &&
+           L[4]->AM == AM65_ZP_INDY                         &&
+           !CE_HasLabel (L[4])                              &&
+                   (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
+                   L[5]->JumpTo != 0                                &&
+                   L[5]->JumpTo->Owner == L[7]                      &&
+           !CE_HasLabel (L[5])                              &&
+           L[6]->OPC == OP65_INX                            &&
+           !CE_HasLabel (L[6])                              &&
+           L[7]->OPC == OP65_LDY                            &&
+           CE_KnownImm (L[7])                               &&
+           L[7]->Num == 0                                   &&
+                   CE_IsCallTo (L[8], "ldauidx")                    &&
+           !CE_HasLabel (L[8])                              &&
            /* Check the label last because this is quite costly */
            (Len = strlen (L[0]->Arg)) > 3                   &&
            L[0]->Arg[0] == '<'                              &&
@@ -728,26 +1055,245 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
            L[1]->Arg[0] == '>'                              &&
                    memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
 
-           CodeEntry* X;
-           char* Label;
+           CodeEntry* X;
+           char* Label;
+
+           /* Add the lda */
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+3);
+
+           /* Add the tay */
+           X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+4);
+
+           /* Add the ldx */
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+5);
+
+           /* Add the lda */
+           Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
+           Label[Len-3] = '\0';
+           X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I+6);
+           xfree (Label);
+
+           /* Remove the old code */
+           CS_DelEntries (S, I, 2);
+           CS_DelEntries (S, I+5, 6);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned OptPtrLoad5 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ *      lda     regbank+n
+ *      ldx     regbank+n+1
+ *      sta     regsave
+ *      stx     regsave+1
+ *      clc
+ *      adc     #$01
+ *      bcc     L0005
+ *      inx
+ * L:   sta     regbank+n
+ *      stx     regbank+n+1
+ *      lda     regsave
+ *      ldx     regsave+1
+ *      ldy     #$00
+ *      jsr     ldauidx
+ *
+ * and replace it by:
+ *
+ *      ldy     #$00
+ *      ldx     #$00
+ *      lda     (regbank+n),y
+ *      inc     regbank+n
+ *      bne     L1
+ *      inc     regbank+n+1
+ * L1:  tay                     <- only if flags are used
+ *
+ * This function must execute before OptPtrLoad5!
+ *
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+               CodeEntry* L[15];
+       unsigned Len;
+
+       /* Get next entry */
+               L[0] = CS_GetEntry (S, I);
+
+       /* Check for the sequence */
+               if (L[0]->OPC == OP65_LDA                               &&
+            L[0]->AM == AM65_ZP                                 &&
+            strncmp (L[0]->Arg, "regbank+", 8) == 0             &&
+            (Len = strlen (L[0]->Arg)) > 0                      &&
+                   CS_GetEntries (S, L+1, I+1, 14)                     &&
+            !CS_RangeHasLabel (S, I+1, 7)                       &&
+            !CS_RangeHasLabel (S, I+9, 5)                       &&
+            L[1]->OPC == OP65_LDX                               &&
+            L[1]->AM == AM65_ZP                                 &&
+            strncmp (L[1]->Arg, L[0]->Arg, Len) == 0            &&
+            strcmp (L[1]->Arg+Len, "+1") == 0                   &&
+            L[2]->OPC == OP65_STA                               &&
+            L[2]->AM == AM65_ZP                                 &&
+            strcmp (L[2]->Arg, "regsave") == 0                  &&
+            L[3]->OPC == OP65_STX                               &&
+            L[3]->AM == AM65_ZP                                 &&
+            strcmp (L[3]->Arg, "regsave+1") == 0                &&
+            L[4]->OPC == OP65_CLC                               &&
+            L[5]->OPC == OP65_ADC                               &&
+            CE_KnownImm (L[5])                                  &&
+            L[5]->Num == 1                                      &&
+            L[6]->OPC == OP65_BCC                               &&
+            L[6]->JumpTo != 0                                   &&
+            L[6]->JumpTo->Owner == L[8]                         &&
+            L[7]->OPC == OP65_INX                               &&
+            L[8]->OPC == OP65_STA                               &&
+            L[8]->AM == AM65_ZP                                 &&
+            strcmp (L[8]->Arg, L[0]->Arg) == 0                  &&
+            L[9]->OPC == OP65_STX                               &&
+            L[9]->AM == AM65_ZP                                 &&
+            strcmp (L[9]->Arg, L[1]->Arg) == 0                  &&
+            L[10]->OPC == OP65_LDA                              &&
+            L[10]->AM == AM65_ZP                                &&
+            strcmp (L[10]->Arg, "regsave") == 0                 &&
+            L[11]->OPC == OP65_LDX                              &&
+            L[11]->AM == AM65_ZP                                &&
+            strcmp (L[11]->Arg, "regsave+1") == 0               &&
+            L[12]->OPC == OP65_LDY                              &&
+            CE_KnownImm (L[12])                                 &&
+            CE_IsCallTo (L[13], "ldauidx")) {
+
+           CodeEntry* X;
+            CodeLabel* Label;
+
+            /* Check if the instruction following the sequence uses the flags
+             * set by the load. If so, insert a test of the value in the
+             * accumulator.
+             */
+            if (CE_UseLoadFlags (L[14])) {
+                X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI);
+                CS_InsertEntry (S, X, I+14);
+            }
+
+            /* Attach a label to L[14]. This may be either the just inserted
+             * instruction, or the one following the sequence.
+             */
+            Label = CS_GenLabel (S, L[14]);
+
+           /* ldy #$xx */
+           X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI);
+           CS_InsertEntry (S, X, I+14);
+
+           /* ldx #$xx */
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI);
+           CS_InsertEntry (S, X, I+15);
+
+            /* lda (regbank+n),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI);
+            CS_InsertEntry (S, X, I+16);
+
+            /* inc regbank+n */
+            X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI);
+            CS_InsertEntry (S, X, I+17);
+
+            /* bne ... */
+            X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI);
+            CS_InsertEntry (S, X, I+18);
+
+            /* inc regbank+n+1 */
+            X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI);
+            CS_InsertEntry (S, X, I+19);
+
+            /* Delete the old code */
+           CS_DelEntries (S, I, 14);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned OptPtrLoad6 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ *      lda     zp
+ *      ldx     zp+1
+ *      ldy     xx
+ *      jsr     ldauidx
+ *
+ * and replace it by:
+ *
+ *      ldy     xx
+ *      ldx     #$00
+ *      lda     (zp),y
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       CodeEntry* L[4];
+       unsigned Len;
 
-           /* We will create all the new stuff behind the current one so
-            * we keep the line references.
-            */
-           X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+8);
+       /* Get next entry */
+               L[0] = CS_GetEntry (S, I);
 
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+9);
+       /* Check for the sequence */
+               if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
+                   CS_GetEntries (S, L+1, I+1, 3)                      &&
+            !CS_RangeHasLabel (S, I+1, 3)                       &&
+                   L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
+            (Len = strlen (L[0]->Arg)) > 0                      &&
+            strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
+            strcmp (L[1]->Arg + Len, "+1") == 0                 &&
+           L[2]->OPC == OP65_LDY                               &&
+                   CE_IsCallTo (L[3], "ldauidx")) {
 
-           Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
-           Label[Len-3] = '\0';
-           X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+10);
-           xfree (Label);
+           CodeEntry* X;
+
+           /* ldx #$00 */
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
+           CS_InsertEntry (S, X, I+3);
+
+           /* lda (zp),y */
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
+           CS_InsertEntry (S, X, I+4);
 
            /* Remove the old code */
-           CS_DelEntries (S, I, 8);
+           CS_DelEntry (S, I+5);
+           CS_DelEntries (S, I, 2);
 
            /* Remember, we had changes */
            ++Changes;
@@ -765,26 +1311,21 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad5 (CodeSeg* S)
+static unsigned OptPtrLoad7 (CodeSeg* S)
 /* Search for the sequence:
  *
- *      lda     #<(label+0)
- *      ldx     #>(label+0)
- *      ldy     #$xx
- *      clc
- *      adc     (sp),y
- *      bcc     L
- *      inx
- * L:   ldy     #$00
- *      jsr     ldauidx
+ *      lda     zp
+ *      ldx     zp+1
+ *      ldy     xx
+ *      jsr     ldaxidx
  *
  * and replace it by:
  *
- *      ldy     #$xx
- *      lda     (sp),y
- *      tay
- *      ldx     #$00
- *      lda     label,y
+ *      ldy     xx
+ *      lda     (zp),y
+ *      tax
+ *      dey
+ *      lda     (zp),y
  */
 {
     unsigned Changes = 0;
@@ -793,71 +1334,44 @@ static unsigned OptPtrLoad5 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[9];
+       CodeEntry* L[4];
        unsigned Len;
 
        /* Get next entry */
                L[0] = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (L[0]->OPC == OP65_LDA                            &&
-           L[0]->AM == AM65_IMM                             &&
-                   CS_GetEntries (S, L+1, I+1, 8)                   &&
-                   L[1]->OPC == OP65_LDX                            &&
-           L[1]->AM == AM65_IMM                             &&
-           !CE_HasLabel (L[1])                              &&
-           L[2]->OPC == OP65_LDY                            &&
-           CE_KnownImm (L[2])                               &&
-           !CE_HasLabel (L[2])                              &&
-           L[3]->OPC == OP65_CLC                            &&
-           !CE_HasLabel (L[3])                              &&
-           L[4]->OPC == OP65_ADC                            &&
-           L[4]->AM == AM65_ZP_INDY                         &&
-           !CE_HasLabel (L[4])                              &&
-                   (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
-                   L[5]->JumpTo != 0                                &&
-                   L[5]->JumpTo->Owner == L[7]                      &&
-           !CE_HasLabel (L[5])                              &&
-           L[6]->OPC == OP65_INX                            &&
-           !CE_HasLabel (L[6])                              &&
-           L[7]->OPC == OP65_LDY                            &&
-           CE_KnownImm (L[7])                               &&
-           L[7]->Num == 0                                   &&
-                   CE_IsCall (L[8], "ldauidx")                      &&
-           !CE_HasLabel (L[8])                              &&
-           /* Check the label last because this is quite costly */
-           (Len = strlen (L[0]->Arg)) > 3                   &&
-           L[0]->Arg[0] == '<'                              &&
-           L[0]->Arg[1] == '('                              &&
-           strlen (L[1]->Arg) == Len                        &&
-           L[1]->Arg[0] == '>'                              &&
-                   memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
+               if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
+                   CS_GetEntries (S, L+1, I+1, 3)                      &&
+            !CS_RangeHasLabel (S, I+1, 3)                       &&
+                   L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
+            (Len = strlen (L[0]->Arg)) > 0                      &&
+            strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
+            strcmp (L[1]->Arg + Len, "+1") == 0                 &&
+           L[2]->OPC == OP65_LDY                               &&
+                   CE_IsCallTo (L[3], "ldaxidx")) {
 
            CodeEntry* X;
-           char* Label;
 
-           /* Add the lda */
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+3);
-
-           /* Add the tay */
-           X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
+                   /* lda (zp),y */
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
            CS_InsertEntry (S, X, I+4);
 
-           /* Add the ldx */
-           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+5);
+           /* tax */
+            X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
+            CS_InsertEntry (S, X, I+5);
 
-           /* Add the lda */
-           Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
-           Label[Len-3] = '\0';
-           X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+6);
-           xfree (Label);
+           /* dey */
+            X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI);
+            CS_InsertEntry (S, X, I+6);
+
+                   /* lda (zp),y */
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
+           CS_InsertEntry (S, X, I+7);
 
            /* Remove the old code */
+           CS_DelEntry (S, I+3);
            CS_DelEntries (S, I, 2);
-           CS_DelEntries (S, I+5, 6);
 
            /* Remember, we had changes */
            ++Changes;
@@ -875,7 +1389,7 @@ static unsigned OptPtrLoad5 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad6 (CodeSeg* S)
+static unsigned OptPtrLoad8 (CodeSeg* S)
 /* Search for the sequence
  *
  *      ldy     ...
@@ -889,7 +1403,7 @@ static unsigned OptPtrLoad6 (CodeSeg* S)
  *      ldx     #$00
  *      lda     (ptr1),y
  *
- * This step must be execute *after* OptPtrLoad1!
+ * This step must be executed *after* OptPtrLoad1!
  */
 {
     unsigned Changes = 0;
@@ -906,7 +1420,7 @@ static unsigned OptPtrLoad6 (CodeSeg* S)
        /* Check for the sequence */
                if (L[0]->OPC == OP65_LDY               &&
                    CS_GetEntries (S, L+1, I+1, 1)      &&
-                   CE_IsCall (L[1], "ldauidx")         &&
+                   CE_IsCallTo (L[1], "ldauidx")       &&
            !CE_HasLabel (L[1])) {
 
            CodeEntry* X;
@@ -961,9 +1475,9 @@ static unsigned OptDecouple (CodeSeg* S)
  *   txa        -> lda #imm
  *   tay        -> ldy #imm
  *   tya        -> lda #imm
- *   lda sreg   -> lda #imm
- *   ldx sreg   -> ldx #imm
- *   ldy sreg   -> ldy #imm
+ *   lda zp     -> lda #imm
+ *   ldx zp     -> ldx #imm
+ *   ldy zp    -> ldy #imm
  *
  * Provided that the register values are known of course.
  */
@@ -978,10 +1492,11 @@ static unsigned OptDecouple (CodeSeg* S)
     I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       char Buf [16];
+       const char* Arg;
 
-       /* Get next entry */
+       /* Get next entry and it's input register values */
                CodeEntry* E = CS_GetEntry (S, I);
+       const RegContents* In = &E->RI->In;
 
        /* Assume we have no replacement */
        CodeEntry* X = 0;
@@ -989,95 +1504,166 @@ static unsigned OptDecouple (CodeSeg* S)
        /* Check the instruction */
        switch (E->OPC) {
 
+           case OP65_DEA:
+               if (RegValIsKnown (In->RegA)) {
+                   Arg = MakeHexArg ((In->RegA - 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+               }
+               break;
+
            case OP65_DEX:
-               if (E->RI->In.RegX >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegX - 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI);
+               if (RegValIsKnown (In->RegX)) {
+                   Arg = MakeHexArg ((In->RegX - 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_DEY:
-               if (E->RI->In.RegY >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegY - 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
+               if (RegValIsKnown (In->RegY)) {
+                   Arg = MakeHexArg ((In->RegY - 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+               }
+               break;
+
+           case OP65_INA:
+               if (RegValIsKnown (In->RegA)) {
+                   Arg = MakeHexArg ((In->RegA + 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_INX:
-               if (E->RI->In.RegX >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegX + 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI);
+               if (RegValIsKnown (In->RegX)) {
+                   Arg = MakeHexArg ((In->RegX + 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_INY:
-               if (E->RI->In.RegY >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegY + 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
+               if (RegValIsKnown (In->RegY)) {
+                   Arg = MakeHexArg ((In->RegY + 1) & 0xFF);
+                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_LDA:
                if (E->AM == AM65_ZP) {
-                   if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo);
-                       X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI);
-                   } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi);
-                       X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI);
+                   switch (GetKnownReg (E->Use & REG_ZP, In)) {
+                       case REG_TMP1:
+                           Arg = MakeHexArg (In->Tmp1);
+                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_LO:
+                           Arg = MakeHexArg (In->Ptr1Lo);
+                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_HI:
+                           Arg = MakeHexArg (In->Ptr1Hi);
+                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_LO:
+                           Arg = MakeHexArg (In->SRegLo);
+                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_HI:
+                           Arg = MakeHexArg (In->SRegHi);
+                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                           break;
                    }
                }
                break;
 
            case OP65_LDX:
                if (E->AM == AM65_ZP) {
-                   if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo);
-                       X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI);
-                   } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi);
-                       X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI);
+                   switch (GetKnownReg (E->Use & REG_ZP, In)) {
+                       case REG_TMP1:
+                           Arg = MakeHexArg (In->Tmp1);
+                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_LO:
+                           Arg = MakeHexArg (In->Ptr1Lo);
+                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_HI:
+                           Arg = MakeHexArg (In->Ptr1Hi);
+                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_LO:
+                           Arg = MakeHexArg (In->SRegLo);
+                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_HI:
+                           Arg = MakeHexArg (In->SRegHi);
+                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                           break;
                    }
                }
                break;
 
            case OP65_LDY:
                if (E->AM == AM65_ZP) {
-                   if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo);
-                       X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
-                   } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) {
-                       xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi);
-                       X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
+                   switch (GetKnownReg (E->Use, In)) {
+                       case REG_TMP1:
+                           Arg = MakeHexArg (In->Tmp1);
+                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_LO:
+                           Arg = MakeHexArg (In->Ptr1Lo);
+                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_PTR1_HI:
+                           Arg = MakeHexArg (In->Ptr1Hi);
+                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_LO:
+                           Arg = MakeHexArg (In->SRegLo);
+                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                           break;
+
+                       case REG_SREG_HI:
+                           Arg = MakeHexArg (In->SRegHi);
+                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                           break;
                    }
                }
                break;
 
            case OP65_TAX:
                if (E->RI->In.RegA >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegA);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI);
+                   Arg = MakeHexArg (In->RegA);
+                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_TAY:
                if (E->RI->In.RegA >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegA);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI);
+                   Arg = MakeHexArg (In->RegA);
+                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_TXA:
                if (E->RI->In.RegX >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegX);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI);
+                   Arg = MakeHexArg (In->RegX);
+                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
            case OP65_TYA:
                if (E->RI->In.RegY >= 0) {
-                   xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegY);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI);
+                   Arg = MakeHexArg (In->RegY);
+                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
                }
                break;
 
@@ -1089,220 +1675,7 @@ static unsigned OptDecouple (CodeSeg* S)
 
        /* Insert the replacement if we have one */
        if (X) {
-           CS_InsertEntry (S, X, I+1);
-           CS_DelEntry (S, I);
-           ++Changes;
-       }
-
-       /* Next entry */
-       ++I;
-
-    }
-
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
-    /* Return the number of changes made */
-    return Changes;
-}
-
-
-
-/*****************************************************************************/
-/*                            Size optimization                             */
-/*****************************************************************************/
-
-
-
-#if 0
-static unsigned OptSize1 (CodeSeg* S)
-/* Do size optimization by calling special subroutines that preload registers.
- * This routine does not work standalone, it needs a following register load
- * removal pass.
- */
-{
-    static const char* Func = {
-       "stax0sp",           /* staxysp, y = 0 */
-       "addeq0sp",
-       "ldax0sp",           /* ldaxysp, y = 1 */
-               "ldeax0sp",          /* ldeaxysp, y = 3 */
-       "push0",             /* pushax, a = 0, x = 0 */
-       "pusha0",            /* pushax, x = 0 */
-       "pushaFF",           /* pushax, x = ff */
-       "pusha0sp",          /* pushaysp, y = 0 */
-       "tosadda0",          /* tosaddax, x = 0 */
-       "tosanda0",          /* tosandax, x = 0 */
-       "tosdiva0",          /* tosdivax, x = 0 */
-       "toseqa0",           /* toseqax, x = 0 */
-       "tosgea0",           /* tosgeax, x = 0 */
-               "tosgta0",           /* tosgtax, x = 0 */
-       "tosadd0ax",         /* tosaddeax, sreg = 0 */
-       "laddeqa",           /* laddeq, sreg = 0, x = 0 */
-       "laddeq1",           /* laddeq, sreg = 0, x = 0, a = 1 */
-       "laddeq0sp",         /* laddeqysp, y = 0 */
-               "tosand0ax",         /* tosandeax, sreg = 0 */
-        "ldaxi",             /* ldaxidx, y = 1 */
-       "ldeaxi",            /* ldeaxidx, y = 3 */
-       "ldeax0sp",          /* ldeaxysp, y = 3 */
-       "tosdiv0ax",         /* tosdiveax, sreg = 0 */
-       "toslea0",           /* tosleax, x = 0 */
-       "tosmod0ax",         /* tosmodeax, sreg = 0 */
-       "tosmul0ax",         /* tosmuleax, sreg = 0 */
-               "tosumul0ax",        /* tosumuleax, sreg = 0 */
-       "tosor0ax",          /* tosoreax, sreg = 0 */
-       "push0ax",           /* pusheax, sreg = 0 */
-       "tosrsub0ax",        /* tosrsubeax, sreg = 0 */
-       "tosshl0ax",         /* tosshleax, sreg = 0 */
-       "tosasl0ax",         /* tosasleax, sreg = 0 */
-       "tosshr0ax",         /* tosshreax, sreg = 0 */
-       "tosasr0ax",         /* tosasreax, sreg = 0 */
-       "tossub0ax",         /* tossubeax, sreg = 0 */
-       "lsubeqa",           /* lsubeq, sreg = 0, x = 0 */
-       "lsubeq1",           /* lsubeq, sreg = 0, x = 0, a = 1 */
-       "lsubeq0sp",         /* lsubeqysp, y = 0 */
-       "toslta0",           /* tosltax, x = 0 */
-       "tosudiv0ax",        /* tosudiveax, sreg = 0 */
-       "tosumod0ax",        /* tosumodeax, sreg = 0 */
-       "tosxor0ax",         /* tosxoreax, sreg = 0 */
-       "tosmoda0",          /* tosmodax, x = 0 */
-       "tosmula0",          /* tosmulax, x = 0 */
-       "tosumula0",         /* tosumulax, x = 0 */
-       "tosnea0",           /* tosneax, x = 0 */
-       "tosora0",           /* tosorax, x = 0 */
-       "push1",             /* pushax, x = 0, a = 1 */
-               "push2",             /* pushax, x = 0, a = 2 */
-       "push3",             /* pushax, x = 0, a = 3 */
-       "push4",             /* pushax, x = 0, a = 4 */
-       "push5",             /* pushax, x = 0, a = 5 */
-       "push6",             /* pushax, x = 0, a = 6 */
-       "push7",             /* pushax, x = 0, a = 7 */
-       "pushc0",            /* pusha, a = 0 */
-               "pushc1",            /* pusha, a = 1 */
-       "pushc2",            /* pusha, a = 2 */
-       "tosrsuba0",         /* tosrsubax, x = 0 */
-       "tosshla0",          /* tosshlax, x = 0 */
-       "tosasla0",          /* tosaslax, x = 0 */
-       "tosshra0",          /* tosshrax, x = 0 */
-       "tosasra0",          /* tosasrax, x = 0 */
-       "steax0sp",          /* steaxsp, y = 0 */
-       "tossuba0",          /* tossubax, x = 0 */
-       "subeq0sp",          /* subeqysp, y = 0 */
-       "tosudiva0",         /* tosudivax, x = 0 */
-       "tosugea0",          /* tosugeax, x = 0 */
-               "tosugta0",          /* tosugtax, x = 0 */
-               "tosulea0",          /* tosuleax, x = 0 */
-               "tosulta0",          /* tosultax, x = 0 */
-               "tosumoda0",         /* tosumodax, x = 0 */
-               "tosxora0",          /* tosxorax, x = 0 */
-    };
-
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info for the following step */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
-
-
-       /* Next entry */
-       ++I;
-
-    }
-
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
-    /* Return the number of changes made */
-    return Changes;
-}
-#endif
-
-
-
-static unsigned OptSize2 (CodeSeg* S)
-/* Do size optimization by using shorter code sequences, even if this
- * introduces relations between instructions. This step must be one of the
- * last steps, because it makes further work much more difficult.
- */
-{
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info for the following step */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
-
-       /* Assume we have no replacement */
-       CodeEntry* X = 0;
-
-       /* Check the instruction */
-       switch (E->OPC) {
-
-           case OP65_LDA:
-               if (CE_KnownImm (E)) {
-                   short Val = (short) E->Num;
-                   if (Val == E->RI->In.RegX) {
-                       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
-                   } else if (Val == E->RI->In.RegY) {
-                       X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
-                   } else if (E->RI->In.RegA >= 0 && CPU >= CPU_65C02) {
-                       if (Val == ((E->RI->In.RegA - 1) & 0xFF)) {
-                           X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
-                       } else if (Val == ((E->RI->In.RegA + 1) & 0xFF)) {
-                           X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
-                       }
-                   }
-               }
-               break;
-
-           case OP65_LDX:
-               if (CE_KnownImm (E)) {
-                   short Val = (short) E->Num;
-                   if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX - 1) & 0xFF)) {
-                       X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
-                   } else if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX + 1) & 0xFF)) {
-                       X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
-                   } else if (Val == E->RI->In.RegA) {
-                       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
-                   }
-               }
-               break;
-
-           case OP65_LDY:
-               if (CE_KnownImm (E)) {
-                   short Val = (short) E->Num;
-                   if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY - 1) & 0xFF)) {
-                       X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
-                   } else if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY + 1) & 0xFF)) {
-                       X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
-                   } else if (Val == E->RI->In.RegA) {
-                       X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI);
-                   }
-               }
-               break;
-
-           default:
-               /* Avoid gcc warnings */
-               break;
-
-       }
-
-       /* Insert the replacement if we have one */
-       if (X) {
-           CS_InsertEntry (S, X, I+1);
+                   CS_InsertEntry (S, X, I+1);
            CS_DelEntry (S, I);
            ++Changes;
        }
@@ -1347,30 +1720,33 @@ struct OptFunc {
 
 
 
-/* Macro that builds a function description */
-#define OptFuncEntry(func) static OptFuncDesc D##func = { func, #func, 0 }
-
 /* A list of all the function descriptions */
+static OptFunc DOpt65C02BitOps  = { Opt65C02BitOps,  "Opt65C02BitOps",   66, 0, 0, 0, 0, 0 };
 static OptFunc DOpt65C02Ind            = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd1                = { OptAdd1,         "OptAdd1",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd2                = { OptAdd2,         "OptAdd2",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd3                = { OptAdd3,         "OptAdd3",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOpt65C02Stores  = { Opt65C02Stores,  "Opt65C02Stores",  100, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd1                = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd2                = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd3                = { OptAdd3,         "OptAdd3",          90, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd4                = { OptAdd4,         "OptAdd4",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd5                = { OptAdd5,         "OptAdd5",          40, 0, 0, 0, 0, 0 };
 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    100, 0, 0, 0, 0, 0 };
-static OptFunc DOptBranchDist          = { OptBranchDist,   "OptBranchDist",   100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp1                = { OptCmp1,         "OptCmp1",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp2                = { OptCmp2,         "OptCmp2",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp3                = { OptCmp3,         "OptCmp3",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBranchDist          = { OptBranchDist,   "OptBranchDist",     0, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp1                = { OptCmp1,         "OptCmp1",          42, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp2                = { OptCmp2,         "OptCmp2",          85, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp3                = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",          75, 0, 0, 0, 0, 0 };
 static OptFunc DOptCmp5                = { OptCmp5,         "OptCmp5",         100, 0, 0, 0, 0, 0 };
 static OptFunc DOptCmp6                = { OptCmp6,         "OptCmp6",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp7                = { OptCmp7,         "OptCmp7",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCondBranches        = { OptCondBranches, "OptCondBranches", 100, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp7                = { OptCmp7,         "OptCmp7",          85, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp8                = { OptCmp8,         "OptCmp8",          50, 0, 0, 0, 0, 0 };
+static OptFunc DOptCondBranches        = { OptCondBranches, "OptCondBranches",  80, 0, 0, 0, 0, 0 };
 static OptFunc DOptDeadCode            = { OptDeadCode,     "OptDeadCode",     100, 0, 0, 0, 0, 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",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpCascades        = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget          = { OptJumpTarget,   "OptJumpTarget",   100, 0, 0, 0, 0, 0 };
+static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
 static OptFunc DOptRTS                 = { OptRTS,          "OptRTS",          100, 0, 0, 0, 0, 0 };
 static OptFunc DOptRTSJumps1    = { OptRTSJumps1,    "OptRTSJumps1",           100, 0, 0, 0, 0, 0 };
 static OptFunc DOptRTSJumps2    = { OptRTSJumps2,    "OptRTSJumps2",           100, 0, 0, 0, 0, 0 };
@@ -1380,34 +1756,50 @@ static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       100, 0,
 static OptFunc DOptNegAX2              = { OptNegAX2,       "OptNegAX2",       100, 0, 0, 0, 0, 0 };
 static OptFunc DOptNegAX3              = { OptNegAX3,       "OptNegAX3",       100, 0, 0, 0, 0, 0 };
 static OptFunc DOptNegAX4              = { OptNegAX4,       "OptNegAX4",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPrecalc      = { OptPrecalc,      "OptPrecalc",             100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad1            = { OptPtrLoad1,     "OptPtrLoad1",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad2            = { OptPtrLoad2,     "OptPtrLoad2",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad3            = { OptPtrLoad3,     "OptPtrLoad3",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad4            = { OptPtrLoad4,     "OptPtrLoad4",     100, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad5            = { OptPtrLoad5,     "OptPtrLoad5",     100, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad5            = { OptPtrLoad5,     "OptPtrLoad5",      50, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",      65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad7            = { OptPtrLoad7,     "OptPtrLoad7",      86, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad8            = { OptPtrLoad8,     "OptPtrLoad8",     100, 0, 0, 0, 0, 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 DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",     40, 0, 0, 0, 0, 0 };
+static OptFunc DOptPush1               = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPush2               = { OptPush2,        "OptPush2",         50, 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 };*/
+static OptFunc DOptShift3              = { OptShift3,       "OptShift3",       110, 0, 0, 0, 0, 0 };
+static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };
 static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        100, 0, 0, 0, 0, 0 };
 static OptFunc DOptStackOps            = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
-static OptFunc DOptStoreLoad           = { OptStoreLoad,    "OptStoreLoad",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptStore1       = { OptStore1,       "OptStore1",        70, 0, 0, 0, 0, 0 };
+static OptFunc DOptStore2       = { OptStore2,       "OptStore2",       220, 0, 0, 0, 0, 0 };
+static OptFunc DOptStore3       = { OptStore3,       "OptStore3",       120, 0, 0, 0, 0, 0 };
+static OptFunc DOptStore4       = { OptStore4,       "OptStore4",        50, 0, 0, 0, 0, 0 };
+static OptFunc DOptStoreLoad           = { OptStoreLoad,    "OptStoreLoad",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptSub1                = { OptSub1,         "OptSub1",         100, 0, 0, 0, 0, 0 };
 static OptFunc DOptSub2                = { OptSub2,         "OptSub2",         100, 0, 0, 0, 0, 0 };
 static OptFunc DOptTest1               = { OptTest1,        "OptTest1",        100, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers           = { OptTransfers,    "OptTransfers",    100, 0, 0, 0, 0, 0 };
-static OptFunc DOptUnusedLoads         = { OptUnusedLoads,  "OptUnusedLoads",  100, 0, 0, 0, 0, 0 };
-static OptFunc DOptUnusedStores        = { OptUnusedStores, "OptUnusedStores", 100, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers1          = { OptTransfers1,   "OptTransfers1",     0, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers2          = { OptTransfers2,   "OptTransfers2",    60, 0, 0, 0, 0, 0 };
+static OptFunc DOptUnusedLoads         = { OptUnusedLoads,  "OptUnusedLoads",    0, 0, 0, 0, 0, 0 };
+static OptFunc DOptUnusedStores        = { OptUnusedStores, "OptUnusedStores",   0, 0, 0, 0, 0, 0 };
 
 
 /* Table containing all the steps in alphabetical order */
 static OptFunc* OptFuncs[] = {
+    &DOpt65C02BitOps,
     &DOpt65C02Ind,
+    &DOpt65C02Stores,
     &DOptAdd1,
     &DOptAdd2,
     &DOptAdd3,
+    &DOptAdd4,
+    &DOptAdd5,
     &DOptBoolTrans,
     &DOptBranchDist,
     &DOptCmp1,
@@ -1417,6 +1809,7 @@ static OptFunc* OptFuncs[] = {
     &DOptCmp5,
     &DOptCmp6,
     &DOptCmp7,
+    &DOptCmp8,
     &DOptCondBranches,
     &DOptDeadCode,
     &DOptDeadJumps,
@@ -1424,33 +1817,46 @@ static OptFunc* OptFuncs[] = {
     &DOptDupLoads,
     &DOptJumpCascades,
     &DOptJumpTarget,
+    &DOptLoad1,
     &DOptNegA1,
     &DOptNegA2,
     &DOptNegAX1,
     &DOptNegAX2,
     &DOptNegAX3,
     &DOptNegAX4,
+    &DOptPrecalc,
     &DOptPtrLoad1,
     &DOptPtrLoad2,
     &DOptPtrLoad3,
     &DOptPtrLoad4,
     &DOptPtrLoad5,
     &DOptPtrLoad6,
+    &DOptPtrLoad7,
+    &DOptPtrLoad8,
     &DOptPtrStore1,
     &DOptPtrStore2,
+    &DOptPush1,
+    &DOptPush2,
+    &DOptPushPop,
     &DOptRTS,
     &DOptRTSJumps1,
     &DOptRTSJumps2,
     &DOptShift1,
     &DOptShift2,
-    /*&DOptSize1,*/
+    &DOptShift3,
+    &DOptSize1,
     &DOptSize2,
     &DOptStackOps,
+    &DOptStore1,
+    &DOptStore2,
+    &DOptStore3,
+    &DOptStore4,
     &DOptStoreLoad,
     &DOptSub1,
     &DOptSub2,
     &DOptTest1,
-    &DOptTransfers,
+    &DOptTransfers1,
+    &DOptTransfers2,
     &DOptUnusedLoads,
     &DOptUnusedStores,
 };
@@ -1584,7 +1990,7 @@ static void ReadOptStats (const char* Name)
 
        /* Parse the line */
                if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
-           /* Syntax error */
+           /* Syntax error */
            continue;
        }
 
@@ -1619,15 +2025,21 @@ static void WriteOptStats (const char* Name)
        return;
     }
 
-    /* Write the file */
+    /* Write a header */
+    fprintf (F,
+            "; Optimizer               Total      Last       Total      Last\n"
+                    ";   Step                  Runs       Runs        Chg       Chg\n");
+
+
+    /* Write the data */
     for (I = 0; I < OPTFUNC_COUNT; ++I) {
-       const OptFunc* O = OptFuncs[I];
-       fprintf (F,
-                        "%-20s %6lu %6lu %6lu %6lu\n",
-                O->Name,
+       const OptFunc* O = OptFuncs[I];
+       fprintf (F,
+                        "%-20s %10lu %10lu %10lu %10lu\n",
+                O->Name,
                 O->TotalRuns,
-                O->LastRuns,
-                O->TotalChanges,
+                O->LastRuns,
+                O->TotalChanges,
                 O->LastChanges);
     }
 
@@ -1642,10 +2054,10 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 {
     unsigned Changes, C;
 
-    /* Don't run the function if it is disabled or if it is prohibited by the 
+    /* Don't run the function if it is disabled or if it is prohibited by the
      * code size factor
      */
-    if (F->Disabled || CodeSizeFactor < F->CodeSizeFactor) {
+    if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
        return 0;
     }
 
@@ -1671,131 +2083,206 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 
 
 
-static void RunOptGroup1 (CodeSeg* S)
+static unsigned RunOptGroup1 (CodeSeg* S)
 /* Run the first group of optimization steps. These steps translate known
  * patterns emitted by the code generator into more optimal patterns. Order
  * of the steps is important, because some of the steps done earlier cover
  * the same patterns as later steps as subpatterns.
  */
 {
-    RunOptFunc (S, &DOptPtrStore1, 1);
-    RunOptFunc (S, &DOptPtrStore2, 1);
-    RunOptFunc (S, &DOptPtrLoad1, 1);
-    RunOptFunc (S, &DOptPtrLoad2, 1);
-    RunOptFunc (S, &DOptPtrLoad3, 1);
-    RunOptFunc (S, &DOptPtrLoad4, 1);
-    RunOptFunc (S, &DOptPtrLoad5, 1);
-    RunOptFunc (S, &DOptNegAX1, 1);
-    RunOptFunc (S, &DOptNegAX2, 1);
-    RunOptFunc (S, &DOptNegAX3, 1);
-    RunOptFunc (S, &DOptNegAX4, 1);
-    RunOptFunc (S, &DOptAdd1, 1);
-    RunOptFunc (S, &DOptAdd2, 1);
-    RunOptFunc (S, &DOptShift1, 1);
-    RunOptFunc (S, &DOptShift2, 1);
+    unsigned Changes = 0;
+
+    Changes += RunOptFunc (S, &DOptPtrStore1, 1);
+    Changes += RunOptFunc (S, &DOptPtrStore2, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad3, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad7, 1);
+    Changes += RunOptFunc (S, &DOptNegAX1, 1);
+    Changes += RunOptFunc (S, &DOptNegAX2, 1);
+    Changes += RunOptFunc (S, &DOptNegAX3, 1);
+    Changes += RunOptFunc (S, &DOptNegAX4, 1);
+    Changes += RunOptFunc (S, &DOptAdd1, 1);
+    Changes += RunOptFunc (S, &DOptAdd2, 1);
+    Changes += RunOptFunc (S, &DOptAdd3, 1);
+    Changes += RunOptFunc (S, &DOptStore4, 1);
+    Changes += RunOptFunc (S, &DOptShift1, 1);
+    Changes += RunOptFunc (S, &DOptShift2, 1);
+    Changes += RunOptFunc (S, &DOptShift3, 1);
+    Changes += RunOptFunc (S, &DOptStore1, 1);
+    Changes += RunOptFunc (S, &DOptStore2, 5);
+    Changes += RunOptFunc (S, &DOptStore3, 5);
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
 
-static void RunOptGroup2 (CodeSeg* S)
+static unsigned RunOptGroup2 (CodeSeg* S)
 /* Run one group of optimization steps. This step involves just decoupling
  * instructions by replacing them by instructions that do not depend on
  * previous instructions. This makes it easier to find instructions that
  * aren't used.
  */
 {
-    RunOptFunc (S, &DOptDecouple, 1);
-}
+    unsigned Changes = 0;
+
+    Changes += RunOptFunc (S, &DOptDecouple, 1);
 
+    /* Return the number of changes */
+    return Changes;
+}
 
 
 
-static void RunOptGroup3 (CodeSeg* S)
+static unsigned RunOptGroup3 (CodeSeg* S)
 /* Run one group of optimization steps. These steps depend on each other,
  * that means that one step may allow another step to do additional work,
  * so we will repeat the steps as long as we see any changes.
  */
 {
-    unsigned Changes;
+    unsigned Changes, C;
 
+    Changes = 0;
     do {
-       Changes = 0;
-
-       Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
-               Changes += RunOptFunc (S, &DOptNegA1, 1);
-               Changes += RunOptFunc (S, &DOptNegA2, 1);
-               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);
-               Changes += RunOptFunc (S, &DOptDeadCode, 1);
-               Changes += RunOptFunc (S, &DOptJumpTarget, 1);
-       Changes += RunOptFunc (S, &DOptCondBranches, 1);
-       Changes += RunOptFunc (S, &DOptRTSJumps1, 1);
-       Changes += RunOptFunc (S, &DOptBoolTrans, 1);
-       Changes += RunOptFunc (S, &DOptCmp1, 1);
-       Changes += RunOptFunc (S, &DOptCmp2, 1);
-       Changes += RunOptFunc (S, &DOptCmp3, 1);
-       Changes += RunOptFunc (S, &DOptCmp4, 1);
-       Changes += RunOptFunc (S, &DOptCmp5, 1);
-       Changes += RunOptFunc (S, &DOptCmp6, 1);
-       Changes += RunOptFunc (S, &DOptCmp7, 1);
-       Changes += RunOptFunc (S, &DOptTest1, 1);
-       Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
-       Changes += RunOptFunc (S, &DOptUnusedStores, 1);
-       Changes += RunOptFunc (S, &DOptDupLoads, 1);
-       Changes += RunOptFunc (S, &DOptStoreLoad, 1);
-       Changes += RunOptFunc (S, &DOptTransfers, 1);
-
-    } while (Changes);
+               C = 0;
+
+               C += RunOptFunc (S, &DOptPtrLoad8, 1);
+               C += RunOptFunc (S, &DOptNegA1, 1);
+               C += RunOptFunc (S, &DOptNegA2, 1);
+               C += RunOptFunc (S, &DOptSub1, 1);
+               C += RunOptFunc (S, &DOptSub2, 1);
+               C += RunOptFunc (S, &DOptAdd4, 1);
+               C += RunOptFunc (S, &DOptAdd5, 1);
+               C += RunOptFunc (S, &DOptStackOps, 1);
+               C += RunOptFunc (S, &DOptJumpCascades, 1);
+               C += RunOptFunc (S, &DOptDeadJumps, 1);
+               C += RunOptFunc (S, &DOptRTS, 1);
+               C += RunOptFunc (S, &DOptDeadCode, 1);
+               C += RunOptFunc (S, &DOptJumpTarget, 1);
+               C += RunOptFunc (S, &DOptCondBranches, 1);
+               C += RunOptFunc (S, &DOptRTSJumps1, 1);
+               C += RunOptFunc (S, &DOptBoolTrans, 1);
+               C += RunOptFunc (S, &DOptCmp1, 1);
+               C += RunOptFunc (S, &DOptCmp2, 1);
+               C += RunOptFunc (S, &DOptCmp3, 1);
+               C += RunOptFunc (S, &DOptCmp4, 1);
+               C += RunOptFunc (S, &DOptCmp5, 1);
+               C += RunOptFunc (S, &DOptCmp6, 1);
+               C += RunOptFunc (S, &DOptCmp7, 1);
+               C += RunOptFunc (S, &DOptCmp8, 1);
+               C += RunOptFunc (S, &DOptTest1, 1);
+        C += RunOptFunc (S, &DOptLoad1, 1);
+               C += RunOptFunc (S, &DOptUnusedLoads, 1);
+               C += RunOptFunc (S, &DOptUnusedStores, 1);
+               C += RunOptFunc (S, &DOptDupLoads, 1);
+               C += RunOptFunc (S, &DOptStoreLoad, 1);
+               C += RunOptFunc (S, &DOptTransfers1, 1);
+        C += RunOptFunc (S, &DOptPushPop, 1);
+        C += RunOptFunc (S, &DOptPrecalc, 1);
+
+       Changes += C;
+
+    } while (C);
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
 
-static void RunOptGroup4 (CodeSeg* S)
+static unsigned RunOptGroup4 (CodeSeg* S)
 /* 65C02 specific optimizations. */
 {
-    if (CPU < CPU_65C02) {
-       return;
-    }
+    unsigned Changes = 0;
 
-    /* Replace (zp),y by (zp) if Y is zero. If we have changes, run register
-     * load optimization again, since loads of Y may have become unnecessary.
-     */
-    if (RunOptFunc (S, &DOpt65C02Ind, 1) > 0) {
-       RunOptFunc (S, &DOptUnusedLoads, 1);
+    if (CPUIsets[CPU] & CPU_ISET_65SC02) {
+        Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
+       Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
+        Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
+               if (Changes) {
+            /* The 65C02 replacement codes do often make the use of a register
+             * value unnecessary, so if we have changes, run another load
+             * removal pass.
+             */
+           Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+       }
     }
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
 
-static void RunOptGroup5 (CodeSeg* S)
-/* The last group of optimization steps. Adjust branches, do size optimizations.
+static unsigned RunOptGroup5 (CodeSeg* S)
+/* Run another round of pattern replacements. These are done late, since there
+ * may be better replacements before.
  */
 {
-    /* Optimize for size, that is replace operations by shorter ones, even
-     * if this does hinder further optimizations (no problem since we're
-     * done soon).
-     */
-    RunOptFunc (S, &DOptSize2, 1);
+    unsigned Changes = 0;
 
-    /* Run the jump target optimization again, since the size optimization
-     * above may have opened new oportunities.
-     */
-    RunOptFunc (S, &DOptJumpTarget, 5);
+    Changes += RunOptFunc (S, &DOptPush1, 1);
+    Changes += RunOptFunc (S, &DOptPush2, 1);
+    Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+    Changes += RunOptFunc (S, &DOptTransfers2, 1);
+
+    /* Return the number of changes */
+    return Changes;
+}
+
+
+
+static unsigned RunOptGroup6 (CodeSeg* S)
+/* The last group of optimization steps. Adjust branches, do size optimizations.
+ */
+{
+    unsigned Changes = 0;
+    unsigned C;
+
+    if (S->CodeSizeFactor <= 100) {
+        /* Optimize for size, that is replace operations by shorter ones, even
+         * if this does hinder further optimizations (no problem since we're
+         * done soon).
+         */
+        C = RunOptFunc (S, &DOptSize1, 1);
+        if (C) {
+            Changes += C;
+            /* Run some optimization passes again, since the size optimizations
+             * may have opened new oportunities.
+             */
+            Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+            Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+        }
+    }
+    C = RunOptFunc (S, &DOptSize2, 1);
+    if (C) {
+        Changes += C;
+        /* Run some optimization passes again, since the size optimizations
+         * may have opened new oportunities.
+         */
+        Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+        Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+    }
 
     /* Adjust branch distances */
-    RunOptFunc (S, &DOptBranchDist, 3);
+    Changes += RunOptFunc (S, &DOptBranchDist, 3);
 
     /* Replace conditional branches to RTS. If we had changes, we must run dead
      * code elimination again, since the change may have introduced dead code.
      */
-    if (RunOptFunc (S, &DOptRTSJumps2, 1)) {
-       RunOptFunc (S, &DOptDeadCode, 1);
+    C = RunOptFunc (S, &DOptRTSJumps2, 1);
+    Changes += C;
+    if (C) {
+       Changes += RunOptFunc (S, &DOptDeadCode, 1);
     }
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
@@ -1806,8 +2293,8 @@ void RunOpt (CodeSeg* S)
     const char* StatFileName;
 
     /* If we shouldn't run the optimizer, bail out */
-    if (!Optimize) {
-       return;
+    if (!S->Optimize) {
+       return;
     }
 
     /* Check if we are requested to write optimizer statistics */
@@ -1829,6 +2316,7 @@ void RunOpt (CodeSeg* S)
     RunOptGroup3 (S);
     RunOptGroup4 (S);
     RunOptGroup5 (S);
+    RunOptGroup6 (S);
 
     /* Write statistics */
     if (StatFileName) {