]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptneg.c
Fix 32/64-bit int/pointer casts
[cc65] / src / cc65 / coptneg.c
index 6aed9ccc2fbd9e54cb1e81d4c45856cce5881aaf..03b39eb4202520289fe04d18c5c3f95a4146b1a7 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                coptneg.c                                 */
+/*                                 coptneg.c                                 */
 /*                                                                           */
-/*                       Optimize negation sequences                        */
+/*                        Optimize negation sequences                        */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2001-2012, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 
 /*****************************************************************************/
-/*                           nega optimizations                             */
+/*                            bnega optimizations                            */
 /*****************************************************************************/
 
 
 
-unsigned OptNegA1 (CodeSeg* S)
+unsigned OptBNegA1 (CodeSeg* S)
 /* Check for
- *
- *     ldx     #$00
- *     lda     ..
- *     jsr     bnega
- *
- * Remove the ldx if the lda does not use it.
- */
+**
+**      ldx     #$00
+**      lda     ..
+**      jsr     bnega
+**
+** Remove the ldx if the lda does not use it.
+*/
 {
     unsigned Changes = 0;
 
@@ -62,33 +62,33 @@ unsigned OptNegA1 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[2];
+        CodeEntry* L[2];
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for a ldx */
-               if (E->OPC == OP65_LDX                  &&
-           E->AM == AM65_IMM                   &&
-           (E->Flags & CEF_NUMARG) != 0        &&
-           E->Num == 0                         &&
-           CS_GetEntries (S, L, I+1, 2)        &&
-           L[0]->OPC == OP65_LDA               &&
-           (L[0]->Use & REG_X) == 0            &&
-           !CE_HasLabel (L[0])                 &&
-           CE_IsCall (L[1], "bnega")           &&
-           !CE_HasLabel (L[1])) {
+        /* Check for a ldx */
+        if (E->OPC == OP65_LDX                  &&
+            E->AM == AM65_IMM                   &&
+            (E->Flags & CEF_NUMARG) != 0        &&
+            E->Num == 0                         &&
+            CS_GetEntries (S, L, I+1, 2)        &&
+            L[0]->OPC == OP65_LDA               &&
+            (L[0]->Use & REG_X) == 0            &&
+            !CE_HasLabel (L[0])                 &&
+            CE_IsCallTo (L[1], "bnega")         &&
+            !CE_HasLabel (L[1])) {
 
-           /* Remove the ldx instruction */
-           CS_DelEntry (S, I);
+            /* Remove the ldx instruction */
+            CS_DelEntry (S, I);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -98,15 +98,15 @@ unsigned OptNegA1 (CodeSeg* S)
 
 
 
-unsigned OptNegA2 (CodeSeg* S)
+unsigned OptBNegA2 (CodeSeg* S)
 /* Check for
- *
- *     lda     ..
- *     jsr     bnega
- *     jeq/jne ..
- *
- * Adjust the conditional branch and remove the call to the subroutine.
- */
+**
+**      lda     ..
+**      jsr     bnega
+**      jeq/jne ..
+**
+** Adjust the conditional branch and remove the call to the subroutine.
+*/
 {
     unsigned Changes = 0;
 
@@ -114,42 +114,42 @@ unsigned OptNegA2 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[2];
+        CodeEntry* L[2];
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-       if ((E->OPC == OP65_ADC ||
-            E->OPC == OP65_AND ||
-            E->OPC == OP65_DEA ||
-            E->OPC == OP65_EOR ||
-            E->OPC == OP65_INA ||
-                    E->OPC == OP65_LDA ||
-            E->OPC == OP65_ORA ||
-            E->OPC == OP65_PLA ||
-            E->OPC == OP65_SBC ||
-            E->OPC == OP65_TXA ||
-            E->OPC == OP65_TYA)                &&
-           CS_GetEntries (S, L, I+1, 2)        &&
-                   CE_IsCall (L[0], "bnega")           &&
-           !CE_HasLabel (L[0])                 &&
-           (L[1]->Info & OF_ZBRA) != 0         &&
-           !CE_HasLabel (L[1])) {
+        /* Check for the sequence */
+        if ((E->OPC == OP65_ADC ||
+             E->OPC == OP65_AND ||
+             E->OPC == OP65_DEA ||
+             E->OPC == OP65_EOR ||
+             E->OPC == OP65_INA ||
+             E->OPC == OP65_LDA ||
+             E->OPC == OP65_ORA ||
+             E->OPC == OP65_PLA ||
+             E->OPC == OP65_SBC ||
+             E->OPC == OP65_TXA ||
+             E->OPC == OP65_TYA)                &&
+            CS_GetEntries (S, L, I+1, 2)        &&
+            CE_IsCallTo (L[0], "bnega")         &&
+            !CE_HasLabel (L[0])                 &&
+            (L[1]->Info & OF_ZBRA) != 0         &&
+            !CE_HasLabel (L[1])) {
 
-           /* Invert the branch */
-           CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+            /* Invert the branch */
+            CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
 
-           /* Delete the subroutine call */
-           CS_DelEntry (S, I+1);
+            /* Delete the subroutine call */
+            CS_DelEntry (S, I+1);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -160,73 +160,65 @@ unsigned OptNegA2 (CodeSeg* S)
 
 
 /*****************************************************************************/
-/*                           negax optimizations                            */
+/*                            bnegax optimizations                           */
 /*****************************************************************************/
 
 
 
-unsigned OptNegAX1 (CodeSeg* S)
+unsigned OptBNegAX1 (CodeSeg* S)
 /* On a call to bnegax, if X is zero, the result depends only on the value in
- * A, so change the call to a call to bnega. This will get further optimized
- * later if possible.
- */
+** A, so change the call to a call to bnega. This will get further optimized
+** later if possible.
+*/
 {
     unsigned Changes = 0;
     unsigned I;
 
-    /* Generate register info for this step */
-    CS_GenRegInfo (S);
-
     /* Walk over the entries */
     I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check if this is a call to bnegax, and if X is known and zero */
-       if (E->RI->In.RegX == 0             &&
-                   CE_IsCall (E, "bnegax")) {
+        /* Check if this is a call to bnegax, and if X is known and zero */
+        if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "bnegax")) {
 
-           /* We're cheating somewhat here ... */
-           E->Arg[5] = '\0';
-           E->Use &= ~REG_X;
+            CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+            CS_DelEntry (S, I);
 
-           /* We had changes */
-           ++Changes;
-       }
+            /* We had changes */
+            ++Changes;
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
 
 
 
-unsigned OptNegAX2 (CodeSeg* S)
+unsigned OptBNegAX2 (CodeSeg* S)
 /* Search for the sequence:
- *
- *     lda     (xx),y
- *     tax
- *     dey
- *     lda     (xx),y
- *     jsr     bnegax
- *     jne/jeq ...
- *
- * and replace it by
- *
- *     lda     (xx),y
- *     dey
- *     ora     (xx),y
- *     jeq/jne ...
- */
+**
+**      ldy     #xx
+**      jsr     ldaxysp
+**      jsr     bnegax
+**      jne/jeq ...
+**
+** and replace it by
+**
+**      ldy     #xx
+**      lda     (sp),y
+**      dey
+**      ora     (sp),y
+**      jeq/jne ...
+*/
 {
     unsigned Changes = 0;
 
@@ -234,45 +226,47 @@ unsigned OptNegAX2 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[5];
+        CodeEntry* L[4];
+
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
+
+        /* Check for the sequence */
+        if (L[0]->OPC == OP65_LDY               &&
+            CE_IsConstImm (L[0])                &&
+            !CS_RangeHasLabel (S, I+1, 3)       &&
+            CS_GetEntries (S, L+1, I+1, 3)      &&
+            CE_IsCallTo (L[1], "ldaxysp")       &&
+            CE_IsCallTo (L[2], "bnegax")        &&
+            (L[3]->Info & OF_ZBRA) != 0) {
+
+            CodeEntry* X;
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+            /* lda (sp),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+1);
 
-       /* Check for the sequence */
-               if (E->OPC == OP65_LDA                  &&
-           E->AM == AM65_ZP_INDY               &&
-           CS_GetEntries (S, L, I+1, 5)        &&
-           L[0]->OPC == OP65_TAX               &&
-           L[1]->OPC == OP65_DEY               &&
-           L[2]->OPC == OP65_LDA               &&
-           L[2]->AM == AM65_ZP_INDY            &&
-           strcmp (L[2]->Arg, E->Arg) == 0     &&
-           !CE_HasLabel (L[2])                 &&
-                   CE_IsCall (L[3], "bnegax")          &&
-           !CE_HasLabel (L[3])                 &&
-                   (L[4]->Info & OF_ZBRA) != 0         &&
-           !CE_HasLabel (L[4])) {
+            /* dey */
+            X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+2);
 
-           /* lda --> ora */
-           CE_ReplaceOPC (L[2], OP65_ORA);
+            /* ora (sp),y */
+            X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+3);
 
-           /* Invert the branch */
-           CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
+            /* Invert the branch */
+            CE_ReplaceOPC (L[3], GetInverseBranch (L[3]->OPC));
 
-           /* Delete the entries no longer needed. Beware: Deleting entries
-            * will change the indices.
-            */
-                   CS_DelEntry (S, I+4);               /* jsr bnegax */
-           CS_DelEntry (S, I+1);               /* tax */
+            /* Delete the entries no longer needed. */
+            CS_DelEntries (S, I+4, 2);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -282,20 +276,20 @@ unsigned OptNegAX2 (CodeSeg* S)
 
 
 
-unsigned OptNegAX3 (CodeSeg* S)
+unsigned OptBNegAX3 (CodeSeg* S)
 /* Search for the sequence:
- *
- *     lda     xx
- *     ldx     yy
- *     jsr     bnegax
- *     jne/jeq ...
- *
- * and replace it by
- *
- *     lda     xx
- *     ora     xx+1
- *     jeq/jne ...
- */
+**
+**      lda     xx
+**      ldx     yy
+**      jsr     bnegax
+**      jne/jeq ...
+**
+** and replace it by
+**
+**      lda     xx
+**      ora     xx+1
+**      jeq/jne ...
+*/
 {
     unsigned Changes = 0;
 
@@ -303,37 +297,37 @@ unsigned OptNegAX3 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[3];
+        CodeEntry* L[3];
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-               if (E->OPC == OP65_LDA                  &&
-                   CS_GetEntries (S, L, I+1, 3)        &&
-           L[0]->OPC == OP65_LDX               &&
-           !CE_HasLabel (L[0])                 &&
-                   CE_IsCall (L[1], "bnegax")          &&
-           !CE_HasLabel (L[1])                 &&
-                   (L[2]->Info & OF_ZBRA) != 0         &&
-           !CE_HasLabel (L[2])) {
+        /* Check for the sequence */
+        if (E->OPC == OP65_LDA                  &&
+            CS_GetEntries (S, L, I+1, 3)        &&
+            L[0]->OPC == OP65_LDX               &&
+            !CE_HasLabel (L[0])                 &&
+            CE_IsCallTo (L[1], "bnegax")        &&
+            !CE_HasLabel (L[1])                 &&
+            (L[2]->Info & OF_ZBRA) != 0         &&
+            !CE_HasLabel (L[2])) {
 
-           /* ldx --> ora */
-           CE_ReplaceOPC (L[0], OP65_ORA);
+            /* ldx --> ora */
+            CE_ReplaceOPC (L[0], OP65_ORA);
 
-           /* Invert the branch */
-                   CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
+            /* Invert the branch */
+            CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
 
-           /* Delete the subroutine call */
-                   CS_DelEntry (S, I+2);
+            /* Delete the subroutine call */
+            CS_DelEntry (S, I+2);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -343,19 +337,19 @@ unsigned OptNegAX3 (CodeSeg* S)
 
 
 
-unsigned OptNegAX4 (CodeSeg* S)
+unsigned OptBNegAX4 (CodeSeg* S)
 /* Search for the sequence:
- *
- *     jsr     xxx
- *     jsr     bnega(x)
- *     jeq/jne ...
- *
- * and replace it by:
- *
- *      jsr    xxx
- *     <boolean test>
- *     jne/jeq ...
- */
+**
+**      jsr     xxx
+**      jsr     bnega(x)
+**      jeq/jne ...
+**
+** and replace it by:
+**
+**      jsr     xxx
+**      <boolean test>
+**      jne/jeq ...
+*/
 {
     unsigned Changes = 0;
 
@@ -363,51 +357,51 @@ unsigned OptNegAX4 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[2];
+        CodeEntry* L[2];
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-               if (E->OPC == OP65_JSR                  &&
-                   CS_GetEntries (S, L, I+1, 2)        &&
-                   L[0]->OPC == OP65_JSR               &&
-           strncmp (L[0]->Arg,"bnega",5) == 0  &&
-           !CE_HasLabel (L[0])                 &&
-                   (L[1]->Info & OF_ZBRA) != 0         &&
-           !CE_HasLabel (L[1])) {
+        /* Check for the sequence */
+        if (E->OPC == OP65_JSR                  &&
+            CS_GetEntries (S, L, I+1, 2)        &&
+            L[0]->OPC == OP65_JSR               &&
+            strncmp (L[0]->Arg,"bnega",5) == 0  &&
+            !CE_HasLabel (L[0])                 &&
+            (L[1]->Info & OF_ZBRA) != 0         &&
+            !CE_HasLabel (L[1])) {
 
-           CodeEntry* X;
+            CodeEntry* X;
 
-           /* Check if we're calling bnega or bnegax */
-           int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
+            /* Check if we're calling bnega or bnegax */
+            int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
 
-           /* Insert apropriate test code */
-           if (ByteSized) {
-               /* Test bytes */
-               X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
-               CS_InsertEntry (S, X, I+2);
-           } else {
-               /* Test words */
-               X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
-               CS_InsertEntry (S, X, I+2);
-               X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
-               CS_InsertEntry (S, X, I+3);
-           }
+            /* Insert apropriate test code */
+            if (ByteSized) {
+                /* Test bytes */
+                X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+2);
+            } else {
+                /* Test words */
+                X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+2);
+                X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+3);
+            }
 
-           /* Delete the subroutine call */
-           CS_DelEntry (S, I+1);
+            /* Delete the subroutine call */
+            CS_DelEntry (S, I+1);
 
-           /* Invert the branch */
-                   CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+            /* Invert the branch */
+            CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -417,3 +411,197 @@ unsigned OptNegAX4 (CodeSeg* S)
 
 
 
+/*****************************************************************************/
+/*                            negax optimizations                            */
+/*****************************************************************************/
+
+
+
+unsigned OptNegAX1 (CodeSeg* S)
+/* Search for a call to negax and replace it by
+**
+**      eor     #$FF
+**      clc
+**      adc     #$01
+**
+** if X isn't used later.
+*/
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
+
+        /* Check if this is a call to negax, and if X isn't used later */
+        if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) {
+
+            CodeEntry* X;
+
+            /* Add replacement code behind */
+            X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
+            CS_InsertEntry (S, X, I+2);
+
+            X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
+            CS_InsertEntry (S, X, I+3);
+
+            /* Delete the call to negax */
+            CS_DelEntry (S, I);
+
+            /* Skip the generated code */
+            I += 2;
+
+            /* We had changes */
+            ++Changes;
+        }
+
+        /* Next entry */
+        ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+unsigned OptNegAX2 (CodeSeg* S)
+/* Search for a call to negax and replace it by
+**
+**      ldx     #$FF
+**      eor     #$FF
+**      clc
+**      adc     #$01
+**      bne     L1
+**      inx
+** L1:
+**
+** if X is known and zero on entry.
+*/
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        CodeEntry* P;
+
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
+
+        /* Check if this is a call to negax, and if X is known and zero */
+        if (E->RI->In.RegX == 0                 &&
+            CE_IsCallTo (E, "negax")            &&
+            (P = CS_GetNextEntry (S, I)) != 0) {
+
+            CodeEntry* X;
+            CodeLabel* L;
+
+            /* Add replacement code behind */
+
+            /* ldx #$FF */
+            X = NewCodeEntry (OP65_LDX, AM65_IMM, "$FF", 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            /* eor #$FF */
+            X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+            CS_InsertEntry (S, X, I+2);
+
+            /* clc */
+            X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
+            CS_InsertEntry (S, X, I+3);
+
+            /* adc #$01 */
+            X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
+            CS_InsertEntry (S, X, I+4);
+
+            /* Get the label attached to the insn following the call */
+            L = CS_GenLabel (S, P);
+
+            /* bne L */
+            X = NewCodeEntry (OP65_BNE, AM65_BRA, L->Name, L, E->LI);
+            CS_InsertEntry (S, X, I+5);
+
+            /* inx */
+            X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
+            CS_InsertEntry (S, X, I+6);
+
+            /* Delete the call to negax */
+            CS_DelEntry (S, I);
+
+            /* Skip the generated code */
+            I += 5;
+
+            /* We had changes */
+            ++Changes;
+        }
+
+        /* Next entry */
+        ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                           complax optimizations                           */
+/*****************************************************************************/
+
+
+
+unsigned OptComplAX1 (CodeSeg* S)
+/* Search for a call to complax and replace it by
+**
+**      eor     #$FF
+**
+** if X isn't used later.
+*/
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
+
+        /* Check if this is a call to negax, and if X isn't used later */
+        if (CE_IsCallTo (E, "complax") && !RegXUsed (S, I+1)) {
+
+            CodeEntry* X;
+
+            /* Add replacement code behind */
+            X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
+
+            /* Delete the call to negax */
+            CS_DelEntry (S, I);
+
+            /* We had changes */
+            ++Changes;
+        }
+
+        /* Next entry */
+        ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}