]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptcmp.c
Added classification macros for file types from struct dirent.
[cc65] / src / cc65 / coptcmp.c
index 91f929b5d8473f43f33a9b5bb27aaf7454bb2bf3..b99c1a69a48c544d0829ad63f83351bca560ba52 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* 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       */
@@ -56,11 +56,6 @@ static const unsigned char CmpInvertTab [] = {
     CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
 };
 
-/* Table to show which compares are signed (use the N flag) */
-static const char CmpSignedTab [] = {
-    0, 0, 1, 1, 1, 1, 0, 0, 0, 0
-};
-
 
 
 /*****************************************************************************/
@@ -279,6 +274,63 @@ unsigned OptBoolTrans (CodeSeg* S)
 
 
 unsigned OptCmp1 (CodeSeg* S)
+/* Search for the sequence
+ *
+ *     ldx     xx
+ *     stx     tmp1
+ *     ora     tmp1
+ *
+ * and replace it by
+ *
+ *     ora     xx
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned 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_LDX               &&
+           !CS_RangeHasLabel (S, I+1, 2)       &&
+           CS_GetEntries (S, L+1, I+1, 2)      &&
+                   L[1]->OPC == OP65_STX               &&
+           strcmp (L[1]->Arg, "tmp1") == 0     &&
+           L[2]->OPC == OP65_ORA               &&
+           strcmp (L[2]->Arg, "tmp1") == 0) {
+
+            CodeEntry* X;
+
+           /* Insert the ora instead */
+            X = NewCodeEntry (OP65_ORA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
+           CS_InsertEntry (S, X, I);
+
+           /* Remove all other instructions */
+           CS_DelEntries (S, I+1, 3);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+unsigned OptCmp2 (CodeSeg* S)
 /* Search for the sequence
  *
  *     stx     xx
@@ -303,12 +355,12 @@ unsigned OptCmp1 (CodeSeg* S)
                CodeEntry* E = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (E->OPC == OP65_STX                  &&
+               if (E->OPC == OP65_STX                  &&
            !CS_RangeHasLabel (S, I+1, 2)       &&
            CS_GetEntries (S, L, I+1, 2)        &&
-                   L[0]->OPC == OP65_STX               &&
+                   L[0]->OPC == OP65_STX               &&
            strcmp (L[0]->Arg, "tmp1") == 0     &&
-           L[1]->OPC == OP65_ORA               &&
+           L[1]->OPC == OP65_ORA               &&
            strcmp (L[1]->Arg, "tmp1") == 0) {
 
            /* Remove the remaining instructions */
@@ -333,7 +385,7 @@ unsigned OptCmp1 (CodeSeg* S)
 
 
 
-unsigned OptCmp2 (CodeSeg* S)
+unsigned OptCmp3 (CodeSeg* S)
 /* Search for
  *
  *             lda/and/ora/eor ...
@@ -375,73 +427,50 @@ unsigned OptCmp2 (CodeSeg* S)
            !CS_RangeHasLabel (S, I+1, 2)   &&
            CS_GetEntries (S, L+1, I+1, 2)  &&
            L[1]->OPC == OP65_CMP           &&
-           CE_KnownImm (L[1])              &&
-           L[1]->Num == 0) {
+           CE_IsKnownImm (L[1], 0)) {
+
+            int Delete = 0;
 
            /* Check for the call to boolxx. We only remove the compare if
             * the carry flag is evaluated later, because the load will not
             * set the carry flag.
             */
            if (L[2]->OPC == OP65_JSR) {
-               switch (FindBoolCmpCond (L[2]->Arg)) {
-
-                   case CMP_EQ:
-                   case CMP_NE:
-                   case CMP_GT:
-                   case CMP_GE:
-                   case CMP_LT:
-                   case CMP_LE:
-                       /* Remove the compare */
-                       CS_DelEntry (S, I+1);
-                       ++Changes;
-                       break;
-
-                   case CMP_UGT:
+               switch (FindBoolCmpCond (L[2]->Arg)) {
+
+                   case CMP_EQ:
+                   case CMP_NE:
+                   case CMP_GT:
+                   case CMP_GE:
+                   case CMP_LT:
+                   case CMP_LE:
+                       /* Remove the compare */
+                        Delete = 1;
+                       break;
+
+                   case CMP_UGT:
                    case CMP_UGE:
-                   case CMP_ULT:
-                   case CMP_ULE:
-                   case CMP_INV:
-                       /* Leave it alone */
-                       break;
-               }
-
-           } else {
-
-               /* Check for a branch on conditions that are set by the load.
-                        * Beware: The insn may branch to another conditional branch
-                * that evaluates other flags, so check that.
-                */
-               CodeEntry* E = L[2];
-               int Delete = 0;
-                       while (1) {
-                   if ((E->Info & (OF_CBRA|OF_UBRA)) != 0) {
-                       /* A conditional branch. Check if it jumps on a
-                        * condition not set by the load.
-                        */
-                       if ((E->Info & (OF_FBRA|OF_UBRA)) == 0) {
-                           /* Invalid branch */
-                           break;
-                       } else if (E->JumpTo == 0) {
-                           /* Jump to external */
-                           Delete = 1;
-                           break;
-                       } else {
-                           /* Check target of branch */
-                           E = E->JumpTo->Owner;
-                       }
-                   } else {
-                       /* Some other insn */
-                       Delete = 1;
-                       break;
-                   }
-               }
-
-               /* Delete the compare if we can */
-               if (Delete) {
-                   CS_DelEntry (S, I+1);
-                   ++Changes;
-               }
-           }
+                   case CMP_ULT:
+                   case CMP_ULE:
+                   case CMP_INV:
+                       /* Leave it alone */
+                       break;
+               }
+
+           } else if ((L[2]->Info & OF_FBRA) != 0) {
+
+                /* The following insn branches on the condition of a load, so
+                 * the compare instruction can be removed.
+                 */
+                Delete = 1;
+
+            }
+
+            /* Delete the compare if we can */
+            if (Delete) {
+                CS_DelEntry (S, I+1);
+                ++Changes;
+            }
        }
 
        /* Next entry */
@@ -455,7 +484,7 @@ unsigned OptCmp2 (CodeSeg* S)
 
 
 
-unsigned OptCmp3 (CodeSeg* S)
+unsigned OptCmp4 (CodeSeg* S)
 /* Search for
  *
  *     lda     x
@@ -533,7 +562,7 @@ unsigned OptCmp3 (CodeSeg* S)
 
 
 
-unsigned OptCmp4 (CodeSeg* S)
+unsigned OptCmp5 (CodeSeg* S)
 /* Optimize compares of local variables:
  *
  *      ldy     #o
@@ -557,7 +586,7 @@ unsigned OptCmp4 (CodeSeg* S)
 
        /* Check for the sequence */
        if (L[0]->OPC == OP65_LDY           &&
-           CE_KnownImm (L[0])              &&
+           CE_IsConstImm (L[0])            &&
            CS_GetEntries (S, L+1, I+1, 5)  &&
            !CE_HasLabel (L[1])             &&
            CE_IsCallTo (L[1], "ldaxysp")   &&
@@ -642,7 +671,7 @@ unsigned OptCmp4 (CodeSeg* S)
 
 
 
-unsigned OptCmp5 (CodeSeg* S)
+unsigned OptCmp6 (CodeSeg* S)
 /* Search for calls to compare subroutines followed by a conditional branch
  * and replace them by cheaper versions, since the branch means that the
  * boolean value returned by these routines is not needed (we may also check
@@ -704,7 +733,7 @@ unsigned OptCmp5 (CodeSeg* S)
 
 
 
-unsigned OptCmp6 (CodeSeg* S)
+unsigned OptCmp7 (CodeSeg* S)
 /* Search for a sequence ldx/txa/branch and remove the txa if A is not
  * used later.
  */
@@ -748,7 +777,7 @@ unsigned OptCmp6 (CodeSeg* S)
 
 
 
-unsigned OptCmp7 (CodeSeg* S)
+unsigned OptCmp8 (CodeSeg* S)
 /* Check for register compares where the contents of the register and therefore
  * the result of the compare is known.
  */
@@ -756,9 +785,6 @@ unsigned OptCmp7 (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)) {
@@ -771,7 +797,7 @@ unsigned OptCmp7 (CodeSeg* S)
        /* Check for a compare against an immediate value */
                if ((E->Info & OF_CMP) != 0           &&
            (RegVal = GetCmpRegVal (E)) >= 0  &&
-           CE_KnownImm (E)) {
+           CE_IsConstImm (E)) {
 
            /* We are able to evaluate the compare at compile time. Check if
             * one or more branches are ahead.
@@ -855,13 +881,79 @@ NextEntry:
 
     }
 
-    /* Free register info */
-    CS_FreeRegInfo (S);
-
     /* Return the number of changes made */
     return Changes;
 }
 
 
 
+unsigned OptCmp9 (CodeSeg* S)
+/* Search for the sequence
+ *
+ *    sbc       xx
+ *    bvs/bvc   L
+ *    eor       #$80
+ * L: asl       a
+ *    bcc/bcs   somewhere
+ *
+ * If A is not used later (which should be the case), we can branch on the N
+ * flag instead of the carry flag and remove the asl.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Walk over the entries */
+    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_SBC                       &&
+                   CS_GetEntries (S, L+1, I+1, 4)              &&
+            (L[1]->OPC == OP65_BVC              ||
+             L[1]->OPC == OP65_BVS)                     &&
+            L[1]->JumpTo != 0                           &&
+            L[1]->JumpTo->Owner == L[3]                 &&
+            L[2]->OPC == OP65_EOR                       &&
+            CE_IsKnownImm (L[2], 0x80)                  &&
+            L[3]->OPC == OP65_ASL                       &&
+            L[3]->AM == AM65_ACC                        &&
+            (L[4]->OPC == OP65_BCC              ||
+             L[4]->OPC == OP65_BCS              ||
+             L[4]->OPC == OP65_JCC              ||
+             L[4]->OPC == OP65_JCS)                     &&
+            !CE_HasLabel (L[4])                         &&
+            !RegAUsed (S, I+4)) {
+
+           /* Replace the branch condition */
+           switch (GetBranchCond (L[4]->OPC)) {
+                case BC_CC:     CE_ReplaceOPC (L[4], OP65_JPL); break;
+                case BC_CS:     CE_ReplaceOPC (L[4], OP65_JMI); break;
+                default:        Internal ("Unknown branch condition in OptCmp9");
+            }
+
+            /* Delete the asl insn */
+            CS_DelEntry (S, I+3);
+
+            /* Next sequence is somewhat ahead (if any) */
+            I += 3;
+
+            /* Remember, we had changes */
+            ++Changes;
+       }
+
+       /* Next entry */
+       ++I;
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+