]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptneg.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / cc65 / coptneg.c
index 9c41a8fe5be7f703f46665793cf7dfe5fa9a059f..fe1683ceb6d0f35d214e0d58cc83ff168e7c36cf 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                coptneg.c                                 */
+/*                                 coptneg.c                                 */
 /*                                                                           */
-/*                       Optimize negation sequences                        */
+/*                        Optimize negation sequences                        */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
@@ -41,7 +41,7 @@
 
 
 /*****************************************************************************/
-/*                           bnega optimizations                            */
+/*                            bnega optimizations                            */
 /*****************************************************************************/
 
 
@@ -49,9 +49,9 @@
 unsigned OptBNegA1 (CodeSeg* S)
 /* Check for
  *
- *     ldx     #$00
- *     lda     ..
- *     jsr     bnega
+ *      ldx     #$00
+ *      lda     ..
+ *      jsr     bnega
  *
  * Remove the ldx if the lda does not use it.
  */
@@ -62,33 +62,33 @@ unsigned OptBNegA1 (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_IsCallTo (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;
 
     }
 
@@ -101,9 +101,9 @@ unsigned OptBNegA1 (CodeSeg* S)
 unsigned OptBNegA2 (CodeSeg* S)
 /* Check for
  *
- *     lda     ..
- *     jsr     bnega
- *     jeq/jne ..
+ *      lda     ..
+ *      jsr     bnega
+ *      jeq/jne ..
  *
  * Adjust the conditional branch and remove the call to the subroutine.
  */
@@ -114,42 +114,42 @@ unsigned OptBNegA2 (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_IsCallTo (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,7 +160,7 @@ unsigned OptBNegA2 (CodeSeg* S)
 
 
 /*****************************************************************************/
-/*                           bnegax optimizations                           */
+/*                            bnegax optimizations                           */
 /*****************************************************************************/
 
 
@@ -174,35 +174,29 @@ unsigned OptBNegAX1 (CodeSeg* S)
     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_IsCallTo (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")) {
 
-           CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI);
-           CS_InsertEntry (S, X, I+1);
-           CS_DelEntry (S, I);
+            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;
 }
@@ -214,16 +208,16 @@ unsigned OptBNegAX2 (CodeSeg* S)
  *
  *      ldy     #xx
  *      jsr     ldaxysp
- *     jsr     bnegax
- *     jne/jeq ...
+ *      jsr     bnegax
+ *      jne/jeq ...
  *
  * and replace it by
  *
  *      ldy     #xx
- *     lda     (sp),y
- *     dey
- *     ora     (sp),y
- *     jeq/jne ...
+ *      lda     (sp),y
+ *      dey
+ *      ora     (sp),y
+ *      jeq/jne ...
  */
 {
     unsigned Changes = 0;
@@ -232,47 +226,47 @@ unsigned OptBNegAX2 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[4];
+        CodeEntry* L[4];
 
-       /* Get next entry */
-               L[0] = CS_GetEntry (S, I);
+        /* 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) {
+        /* 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;
+            CodeEntry* X;
 
-           /* lda (sp),y */
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
-           CS_InsertEntry (S, X, I+1);
+            /* lda (sp),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+1);
 
-           /* dey */
-           X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI);
-           CS_InsertEntry (S, X, I+2);
+            /* dey */
+            X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI);
+            CS_InsertEntry (S, X, I+2);
 
-           /* ora (sp),y */
-           X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
-           CS_InsertEntry (S, X, I+3);
+            /* 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[3], GetInverseBranch (L[3]->OPC));
+            /* Invert the branch */
+            CE_ReplaceOPC (L[3], GetInverseBranch (L[3]->OPC));
 
-           /* Delete the entries no longer needed. */
-                   CS_DelEntries (S, I+4, 2);
+            /* 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;
 
     }
 
@@ -285,16 +279,16 @@ unsigned OptBNegAX2 (CodeSeg* S)
 unsigned OptBNegAX3 (CodeSeg* S)
 /* Search for the sequence:
  *
- *     lda     xx
- *     ldx     yy
- *     jsr     bnegax
- *     jne/jeq ...
+ *      lda     xx
+ *      ldx     yy
+ *      jsr     bnegax
+ *      jne/jeq ...
  *
  * and replace it by
  *
- *     lda     xx
- *     ora     xx+1
- *     jeq/jne ...
+ *      lda     xx
+ *      ora     xx+1
+ *      jeq/jne ...
  */
 {
     unsigned Changes = 0;
@@ -303,37 +297,37 @@ unsigned OptBNegAX3 (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_IsCallTo (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;
 
     }
 
@@ -346,15 +340,15 @@ unsigned OptBNegAX3 (CodeSeg* S)
 unsigned OptBNegAX4 (CodeSeg* S)
 /* Search for the sequence:
  *
- *     jsr     xxx
- *     jsr     bnega(x)
- *     jeq/jne ...
+ *      jsr     xxx
+ *      jsr     bnega(x)
+ *      jeq/jne ...
  *
  * and replace it by:
  *
- *      jsr    xxx
- *     <boolean test>
- *     jne/jeq ...
+ *      jsr     xxx
+ *      <boolean test>
+ *      jne/jeq ...
  */
 {
     unsigned Changes = 0;
@@ -363,51 +357,113 @@ unsigned OptBNegAX4 (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);
+
+        /* 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;
+
+            /* 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);
+            }
+
+            /* Delete the subroutine call */
+            CS_DelEntry (S, I+1);
+
+            /* Invert the branch */
+            CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+
+            /* Remember, we had changes */
+            ++Changes;
+
+        }
+
+        /* Next entry */
+        ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                            negax optimizations                            */
+/*****************************************************************************/
+
+
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+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;
 
-       /* 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])) {
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-           CodeEntry* X;
+        /* Check if this is a call to negax, and if X isn't used later */
+        if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) {
 
-           /* Check if we're calling bnega or bnegax */
-           int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
+            CodeEntry* X;
 
-           /* 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);
-           }
+            /* Add replacement code behind */
+            X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+            CS_InsertEntry (S, X, I+1);
 
-           /* Delete the subroutine call */
-           CS_DelEntry (S, I+1);
+            X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
+            CS_InsertEntry (S, X, I+2);
 
-           /* Invert the branch */
-                   CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+            X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
+            CS_InsertEntry (S, X, I+3);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Delete the call to negax */
+            CS_DelEntry (S, I);
 
-       }
+            /* Skip the generated code */
+            I += 2;
 
-       /* Next entry */
-       ++I;
+            /* We had changes */
+            ++Changes;
+        }
+
+        /* Next entry */
+        ++I;
 
     }
 
@@ -417,3 +473,135 @@ unsigned OptBNegAX4 (CodeSeg* S)
 
 
 
+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;
+}