]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
More shift optimizations.
[cc65] / src / cc65 / codeopt.c
index 51dbfcec2d485457cfd762e7aa72fdf0729f3819..0a5eacc141a8f077b6fdc9d4b7d1bd9cd9e1fc16 100644 (file)
@@ -57,6 +57,7 @@
 #include "coptptrload.h"
 #include "coptptrstore.h"
 #include "coptpush.h"
+#include "coptshift.h"
 #include "coptsize.h"
 #include "coptstop.h"
 #include "coptstore.h"
 
 
 
-/*****************************************************************************/
-/*                                     Data                                  */
-/*****************************************************************************/
-
-
-
-/* Shift types */
-enum {
-    SHIFT_NONE,
-    SHIFT_ASR_1,
-    SHIFT_ASL_1,
-    SHIFT_LSR_1,
-    SHIFT_LSL_1
-};
-
-
-
-/*****************************************************************************/
-/*                             Optimize shifts                              */
-/*****************************************************************************/
-
-
-
-static unsigned OptShift1 (CodeSeg* S)
-/* A call to the shlaxN routine may get replaced by one or more asl insns
- * if the value of X is not used later. If X is used later, but it is zero
- * on entry and it's a shift by one, it may get replaced by:
- *
- *      asl     a
- *      bcc     L1
- *      inx
- *  L1:
- *
- */
-{
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-        CodeEntry* N;
-        CodeEntry* X;
-        CodeLabel* L;
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
-
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                       &&
-                   (strncmp (E->Arg, "shlax", 5) == 0 ||
-            strncmp (E->Arg, "aslax", 5) == 0)      &&
-           strlen (E->Arg) == 6                     &&
-           IsDigit (E->Arg[5])) {
-
-            if (!RegXUsed (S, I+1)) {
-
-                /* Insert shift insns */
-                unsigned Count = E->Arg[5] - '0';
-                while (Count--) {
-                    X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
-                    CS_InsertEntry (S, X, I+1);
-                }
-
-                /* Delete the call to shlax */
-                CS_DelEntry (S, I);
-
-                /* Remember, we had changes */
-                ++Changes;
-
-            } else if (E->RI->In.RegX == 0              &&
-                       E->Arg[5] == '1'                 &&
-                       (N = CS_GetNextEntry (S, I)) != 0) {
-
-                /* asl a */
-                X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
-                CS_InsertEntry (S, X, I+1);
-
-                /* bcc L1 */
-                L = CS_GenLabel (S, N);
-                X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, E->LI);
-                CS_InsertEntry (S, X, I+2);
-
-                /* inx */
-                X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
-                CS_InsertEntry (S, X, I+3);
-
-                /* Delete the call to shlax */
-                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;
-}
-
-
-
-static unsigned OptShift2(CodeSeg* S)
-/* A call to the asrax1 routines may get replaced by something simpler, if
- * X is not used later:
- *
- *      cmp     #$80
- *      ror     a
- *
- */
-{
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-        unsigned Count;
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
-
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                  &&
-                   strncmp (E->Arg, "asrax", 5) == 0   &&
-           strlen (E->Arg) == 6                &&
-           IsDigit (E->Arg[5])                 &&
-            (Count = (E->Arg[5] - '0')) >= 1    &&
-            Count * 100 <= S->CodeSizeFactor    &&
-            !RegXUsed (S, I+1)) {
-
-            CodeEntry* X;
-            unsigned J = I+1;
-
-            /* Generate the replacement sequence */
-            while (Count--) {
-                /* cmp #$80 */
-                X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, E->LI);
-                CS_InsertEntry (S, X, J++);
-
-                /* ror a */
-                X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI);
-                CS_InsertEntry (S, X, J++);
-            }
-
-            /* Delete the call to asrax */
-            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;
-}
-
-
-
-static unsigned OptShift3 (CodeSeg* S)
-/* The sequence
- *
- *      bcc     L
- *     inx
- * L:   jsr     shrax1
- *
- * may get replaced by
- *
- *      ror     a
- *
- * if X is zero on entry and unused later.
- */
-{
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-       CodeEntry* L[3];
-
-       /* Get next entry */
-               L[0] = CS_GetEntry (S, I);
-
-       /* Check for the sequence */
-               if ((L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC)    &&
-           L[0]->JumpTo != 0                                   &&
-            L[0]->RI->In.RegX == 0                              &&
-                   CS_GetEntries (S, L+1, I+1, 2)                      &&
-           L[1]->OPC == OP65_INX                               &&
-           L[0]->JumpTo->Owner == L[2]                         &&
-           !CS_RangeHasLabel (S, I, 2)                         &&
-            CE_IsCallTo (L[2], "shrax1")                        &&
-           !RegXUsed (S, I+3)) {
-
-            /* Add the replacement insn instead */
-            CodeEntry* X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
-            CS_InsertEntry (S, X, I+3);
-
-           /* Remove the bcs/dex/jsr */
-           CS_DelEntries (S, I, 3);
-
-           /* Remember, we had changes */
-           ++Changes;
-
-       }
-
-       /* Next entry */
-       ++I;
-
-    }
-
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
-    /* Return the number of changes made */
-    return Changes;
-}
-
-
-
-static unsigned OptShift4 (CodeSeg* S)
-/* A call to the shraxN routine may get replaced by one or more lsr insns
- * if the value of X is zero.
- */
-{
-    unsigned Changes = 0;
-    unsigned I;
-
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
-
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                       &&
-                   strncmp (E->Arg, "shrax", 5) == 0        &&
-           strlen (E->Arg) == 6                     &&
-           IsDigit (E->Arg[5])                      &&
-                   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);
-           }
-
-           /* Delete the call to shrax */
-           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;
-}
-
-
-
-static unsigned GetShiftType (const char* Sub)
-/* Helper function for OptShift5 */
-{
-    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 OptShift5 (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;
-}
-
-
-
-static unsigned OptShift6 (CodeSeg* S)
-/* Inline the shift subroutines. */
-{
-    unsigned Changes = 0;
-
-    /* Walk over the entries */
-    unsigned I = 0;
-    while (I < CS_GetEntryCount (S)) {
-
-        CodeEntry* X;
-        unsigned   IP;
-
-       /* Get next entry */
-       CodeEntry* E = CS_GetEntry (S, I);
-
-       /* Check for a call to one of the shift routine */
-       if (E->OPC == OP65_JSR                          &&
-                   (strncmp (E->Arg, "shlax", 5) == 0  ||
-             strncmp (E->Arg, "aslax", 5) == 0)         &&
-           strlen (E->Arg) == 6                        &&
-           IsDigit (E->Arg[5])) {
-
-            /* Get number of shifts */
-            unsigned ShiftCount = (E->Arg[5] - '0');
-
-            /* Code is:
-             *
-             *      stx     tmp1
-             *      asl     a
-             *      rol     tmp1
-             *      (repeat ShiftCount-1 times)
-             *      ldx     tmp1
-             *
-             * which makes 4 + 3 * ShiftCount bytes, compared to the original
-             * 3 bytes for the subroutine call. However, in most cases, the
-             * final load of the X register gets merged with some other insn
-             * and replaces a txa, so for a shift count of 1, we get a factor
-             * of 200, which matches nicely the CodeSizeFactor enabled with -Oi
-             */
-            if (ShiftCount > 1 || S->CodeSizeFactor > 200) {
-                unsigned Size = 4 + 3 * ShiftCount;
-                if ((Size * 100 / 3) > S->CodeSizeFactor) {
-                    /* Not acceptable */
-                    goto NextEntry;
-                }
-            }
-
-            /* Inline the code. Insertion point is behind the subroutine call */
-            IP = (I + 1);
-
-            /* stx tmp1 */
-            X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, E->LI);
-            CS_InsertEntry (S, X, IP++);
-
-            while (ShiftCount--) {
-                /* asl a */
-                X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
-                CS_InsertEntry (S, X, IP++);
-
-                /* rol tmp1 */
-                X = NewCodeEntry (OP65_ROL, AM65_ZP, "tmp1", 0, E->LI);
-                CS_InsertEntry (S, X, IP++);
-            }
-
-            /* ldx tmp1 */
-            X = NewCodeEntry (OP65_LDX, AM65_ZP, "tmp1", 0, E->LI);
-            CS_InsertEntry (S, X, IP++);
-
-            /* Remove the subroutine call */
-            CS_DelEntry (S, I);
-
-           /* Remember, we had changes */
-            ++Changes;
-       }
-
-NextEntry:
-       /* Next entry */
-       ++I;
-
-    }
-
-    /* Return the number of changes made */
-    return Changes;
-}
-
-
-
 /*****************************************************************************/
 /*                              Optimize loads                               */
 /*****************************************************************************/
@@ -613,9 +83,6 @@ static unsigned OptLoad1 (CodeSeg* S)
     unsigned I;
     unsigned Changes = 0;
 
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
     /* Walk over the entries */
     I = 0;
     while (I < CS_GetEntryCount (S)) {
@@ -654,9 +121,6 @@ static unsigned OptLoad1 (CodeSeg* S)
 
     }
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
@@ -669,9 +133,6 @@ static unsigned OptLoad2 (CodeSeg* S)
     unsigned I;
     unsigned Changes = 0;
 
-    /* Generate register info */
-    CS_GenRegInfo (S);
-
     /* Walk over the entries */
     I = 0;
     while (I < CS_GetEntryCount (S)) {
@@ -757,9 +218,6 @@ static unsigned OptLoad2 (CodeSeg* S)
        ++I;
     }
 
-    /* Free the register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
@@ -793,9 +251,6 @@ static unsigned OptDecouple (CodeSeg* S)
     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)) {
@@ -993,9 +448,6 @@ static unsigned OptDecouple (CodeSeg* S)
 
     }
 
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
@@ -1036,9 +488,6 @@ static unsigned OptStackPtrOps (CodeSeg* S)
     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)) {
@@ -1093,9 +542,6 @@ static unsigned OptStackPtrOps (CodeSeg* S)
 
     }
 
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
@@ -1138,6 +584,12 @@ static OptFunc DOptAdd3           = { OptAdd3,         "OptAdd3",          65, 0,
 static OptFunc DOptAdd4                = { OptAdd4,         "OptAdd4",          90, 0, 0, 0, 0, 0 };
 static OptFunc DOptAdd5                = { OptAdd5,         "OptAdd5",         100, 0, 0, 0, 0, 0 };
 static OptFunc DOptAdd6                = { OptAdd6,         "OptAdd6",          40, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegA1       = { OptBNegA1,       "OptBNegA1",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegA2       = { OptBNegA2,       "OptBNegA2",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegAX1      = { OptBNegAX1,      "OptBNegAX1",      100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegAX2      = { OptBNegAX2,      "OptBNegAX2",      100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegAX3      = { OptBNegAX3,      "OptBNegAX3",      100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBNegAX4      = { OptBNegAX4,      "OptBNegAX4",      100, 0, 0, 0, 0, 0 };
 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    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 };
@@ -1163,15 +615,11 @@ static OptFunc DOptJumpTarget2  = { OptJumpTarget2,  "OptJumpTarget2",  100, 0,
 static OptFunc DOptJumpTarget3  = { OptJumpTarget3,  "OptJumpTarget3",  100, 0, 0, 0, 0, 0 };
 static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
 static OptFunc DOptLoad2        = { OptLoad2,        "OptLoad2",        200, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       165, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX2       = { OptNegAX2,       "OptNegAX2",       200, 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 };
-static OptFunc DOptNegA1               = { OptNegA1,        "OptNegA1",        100, 0, 0, 0, 0, 0 };
-static OptFunc DOptNegA2               = { OptNegA2,        "OptNegA2",        100, 0, 0, 0, 0, 0 };
-static OptFunc DOptNegAX1              = { OptNegAX1,       "OptNegAX1",       100, 0, 0, 0, 0, 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 };
@@ -1187,11 +635,9 @@ static OptFunc DOptPtrLoad14      = { OptPtrLoad14,    "OptPtrLoad14",    108, 0,
 static OptFunc DOptPtrLoad15           = { OptPtrLoad15,    "OptPtrLoad15",     86, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad16           = { OptPtrLoad16,    "OptPtrLoad16",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad17           = { OptPtrLoad17,    "OptPtrLoad17",    190, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",     40, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",     50, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore3           = { OptPtrStore3,    "OptPtrStore3",     50, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore4           = { OptPtrStore4,    "OptPtrStore4",     65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore5           = { OptPtrStore5,    "OptPtrStore5",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore3           = { OptPtrStore3,    "OptPtrStore3",    100, 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 };
@@ -1235,6 +681,12 @@ static OptFunc* OptFuncs[] = {
     &DOptAdd4,
     &DOptAdd5,
     &DOptAdd6,
+    &DOptBNegA1,
+    &DOptBNegA2,
+    &DOptBNegAX1,
+    &DOptBNegAX2,
+    &DOptBNegAX3,
+    &DOptBNegAX4,
     &DOptBoolTrans,
     &DOptBranchDist,
     &DOptCmp1,
@@ -1260,12 +712,8 @@ static OptFunc* OptFuncs[] = {
     &DOptJumpTarget3,
     &DOptLoad1,
     &DOptLoad2,
-    &DOptNegA1,
-    &DOptNegA2,
     &DOptNegAX1,
     &DOptNegAX2,
-    &DOptNegAX3,
-    &DOptNegAX4,
     &DOptPrecalc,
     &DOptPtrLoad1,
     &DOptPtrLoad11,
@@ -1284,8 +732,6 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrStore1,
     &DOptPtrStore2,
     &DOptPtrStore3,
-    &DOptPtrStore4,
-    &DOptPtrStore5,
     &DOptPush1,
     &DOptPush2,
     &DOptPushPop,
@@ -1497,10 +943,10 @@ static void WriteOptStats (const char* Name)
        fprintf (F,
                         "%-20s %10lu %10lu %10lu %10lu\n",
                 O->Name,
-                O->TotalRuns,
+                O->TotalRuns,
                 O->LastRuns,
-                O->TotalChanges,
-                O->LastChanges);
+                O->TotalChanges,
+                O->LastChanges);
     }
 
     /* Close the file, ignore errors here. */
@@ -1525,7 +971,7 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
     Changes = 0;
     do {
 
-       /* Run the function */
+       /* Run the function */
        C = F->Func (S);
         if (Debug && C > 0) {
             printf ("Applied %s: %u changes\n", F->Name, C);
@@ -1538,6 +984,11 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
        F->TotalChanges += C;
        F->LastChanges  += C;
 
+        /* If we had changes, regenerate register info */
+        if (C) {
+            CS_GenRegInfo (S);
+        }
+
     } while (--Max && C > 0);
 
     /* Return the number of changes */
@@ -1559,8 +1010,6 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
     Changes += RunOptFunc (S, &DOptPtrStore2, 1);
     Changes += RunOptFunc (S, &DOptPtrStore3, 1);
-    Changes += RunOptFunc (S, &DOptPtrStore4, 1);
-    Changes += RunOptFunc (S, &DOptPtrStore5, 1);
     Changes += RunOptFunc (S, &DOptAdd3, 1);    /* Before OptPtrLoad5! */
     Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
@@ -1576,10 +1025,10 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad15, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad16, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad17, 1);
-    Changes += RunOptFunc (S, &DOptNegAX1, 1);
-    Changes += RunOptFunc (S, &DOptNegAX2, 1);
-    Changes += RunOptFunc (S, &DOptNegAX3, 1);
-    Changes += RunOptFunc (S, &DOptNegAX4, 1);
+    Changes += RunOptFunc (S, &DOptBNegAX1, 1);
+    Changes += RunOptFunc (S, &DOptBNegAX2, 1);
+    Changes += RunOptFunc (S, &DOptBNegAX3, 1);
+    Changes += RunOptFunc (S, &DOptBNegAX4, 1);
     Changes += RunOptFunc (S, &DOptAdd1, 1);
     Changes += RunOptFunc (S, &DOptAdd2, 1);
     Changes += RunOptFunc (S, &DOptAdd4, 1);
@@ -1591,7 +1040,6 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptStore5, 1);
     Changes += RunOptFunc (S, &DOptShift1, 1);
     Changes += RunOptFunc (S, &DOptShift2, 1);
-    Changes += RunOptFunc (S, &DOptShift4, 1);
     Changes += RunOptFunc (S, &DOptShift5, 1);
     Changes += RunOptFunc (S, &DOptShift6, 1);
     Changes += RunOptFunc (S, &DOptStore1, 1);
@@ -1633,9 +1081,13 @@ static unsigned RunOptGroup3 (CodeSeg* S)
     do {
                C = 0;
 
-               C += RunOptFunc (S, &DOptNegA1, 1);
-               C += RunOptFunc (S, &DOptNegA2, 1);
-               C += RunOptFunc (S, &DOptStackOps, 1);
+               C += RunOptFunc (S, &DOptBNegA1, 1);
+               C += RunOptFunc (S, &DOptBNegA2, 1);
+        C += RunOptFunc (S, &DOptNegAX1, 1);
+        C += RunOptFunc (S, &DOptNegAX2, 1);
+               C += RunOptFunc (S, &DOptStackOps, 3);
+        C += RunOptFunc (S, &DOptShift1, 1);
+        C += RunOptFunc (S, &DOptShift4, 1);
                C += RunOptFunc (S, &DOptSub1, 1);
                C += RunOptFunc (S, &DOptSub2, 1);
                C += RunOptFunc (S, &DOptSub3, 1);
@@ -1789,6 +1241,7 @@ static unsigned RunOptGroup7 (CodeSeg* S)
         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
         Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
         Changes += RunOptFunc (S, &DOptStore5, 1);
+        Changes += RunOptFunc (S, &DOptTransfers1, 1);
         Changes += RunOptFunc (S, &DOptTransfers3, 1);
     }
 
@@ -1833,6 +1286,9 @@ void RunOpt (CodeSeg* S)
        Print (stdout, 1, "Running optimizer for global code segment\n");
     }
 
+    /* Generate register info for all instructions */
+    CS_GenRegInfo (S);
+
     /* Run groups of optimizations */
     RunOptGroup1 (S);
     RunOptGroup2 (S);
@@ -1842,6 +1298,9 @@ void RunOpt (CodeSeg* S)
     RunOptGroup6 (S);
     RunOptGroup7 (S);
 
+    /* Free register info */
+    CS_FreeRegInfo (S);
+
     /* Write statistics */
     if (StatFileName) {
        WriteOptStats (StatFileName);