]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptcmp.c
Fixed initializers for standard behaviour (hopefully ok now)
[cc65] / src / cc65 / coptcmp.c
index dd24c48c4e55667695e9e3f9da4f2ea1954e19ba..012291e9acc4da9be9906c60778b883446d90c9e 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
+/* (C) 2001-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
 
 
 
-/* Defines for the conditions in a compare */
-typedef enum {
-    CMP_INV = -1,
-    CMP_EQ,
-    CMP_NE,
-    CMP_GT,
-    CMP_GE,
-    CMP_LT,
-    CMP_LE,
-    CMP_UGT,
-    CMP_UGE,
-    CMP_ULT,
-    CMP_ULE
-} cmp_t;
-
-/* Table with the compare suffixes */
-static const char CmpSuffixTab [][4] = {
-    "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
-};
-
 /* Table used to invert a condition, indexed by condition */
 static const unsigned char CmpInvertTab [] = {
     CMP_NE, CMP_EQ,
@@ -89,59 +69,6 @@ static const char CmpSignedTab [] = {
 
 
 
-static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
-/* Search for a compare condition by the given code using the given length */
-{
-    unsigned I;
-
-    /* Linear search */
-    for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
-       if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
-           /* Found */
-           return I;
-       }
-    }
-
-    /* Not found */
-    return CMP_INV;
-}
-
-
-
-static cmp_t FindBoolCmpCond (const char* Name)
-/* Map a condition suffix to a code. Return the code or CMP_INV on failure */
-{
-    /* Check for the correct subroutine name */
-    if (strncmp (Name, "bool", 4) == 0) {
-       /* Name is ok, search for the code in the table */
-       return FindCmpCond (Name+4, strlen(Name)-4);
-    } else {
-       /* Not found */
-       return CMP_INV;
-    }
-}
-
-
-
-static cmp_t FindTosCmpCond (const char* Name)
-/* Check if this is a call to one of the TOS compare functions (tosgtax).
- * Return the condition code or CMP_INV on failure.
- */
-{
-    unsigned Len = strlen (Name);
-
-    /* Check for the correct subroutine name */
-    if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
-       /* Name is ok, search for the code in the table */
-       return FindCmpCond (Name+3, Len-3-2);
-    } else {
-       /* Not found */
-       return CMP_INV;
-    }
-}
-
-
-
 static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
 /* Helper function for the replacement of routines that return a boolean
  * followed by a conditional jump. Instead of the boolean value, the condition
@@ -283,63 +210,6 @@ static int GetCmpRegVal (const CodeEntry* E)
 
 
 
-static int IsCmpToZero (const CodeEntry* E)
-/* Check if the given instrcuction is a compare to zero instruction */
-{
-    return (E->OPC == OP65_CMP            &&
-           E->AM  == AM65_IMM            &&
-           (E->Flags & CEF_NUMARG) != 0  &&
-           E->Num == 0);
-}
-
-
-
-static int IsSpLoad (const CodeEntry* E)
-/* Return true if this is the load of A from the stack */
-{
-    return E->OPC == OP65_LDA && E->AM == AM65_ZP_INDY && strcmp (E->Arg, "sp") == 0;
-}
-
-
-
-static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
-                         CodeEntry** L, unsigned Count)
-/* Check if a 16 bit load of a local variable follows:
- *
- *      ldy     #$xx
- *      lda     (sp),y
- *      tax
- *      dey
- *      lda     (sp),y
- *
- * If so, read Count entries following the first ldy into L and return true
- * if this is possible. Otherwise return false.
- */
-{
-    /* Be sure we read enough entries for the check */
-    CHECK (Count >= 5);
-
-    /* Read the first entry */
-    L[0] = CS_GetEntry (S, Index);
-
-    /* Check for the sequence */
-    return (L[0]->OPC == OP65_LDY                        &&
-           CE_KnownImm (L[0])                           &&
-                   CS_GetEntries (S, L+1, Index+1, Count-1)     &&
-                   IsSpLoad (L[1])                              &&
-           !CE_HasLabel (L[1])                          &&
-           L[2]->OPC == OP65_TAX                        &&
-           !CE_HasLabel (L[2])                          &&
-           L[3]->OPC == OP65_LDY                        &&
-           CE_KnownImm (L[3])                           &&
-           L[3]->Num == L[0]->Num - 1                   &&
-           !CE_HasLabel (L[3])                          &&
-           IsSpLoad (L[4])                              &&
-           !CE_HasLabel (L[4]));
-}
-
-
-
 /*****************************************************************************/
 /*            Remove calls to the bool transformer subroutines              */
 /*****************************************************************************/
@@ -434,13 +304,12 @@ unsigned OptCmp1 (CodeSeg* S)
 
        /* Check for the sequence */
                if (E->OPC == OP65_STX                  &&
+           !CS_RangeHasLabel (S, I+1, 2)       &&
            CS_GetEntries (S, L, I+1, 2)        &&
                    L[0]->OPC == OP65_STX               &&
            strcmp (L[0]->Arg, "tmp1") == 0     &&
-           !CE_HasLabel (L[0])                 &&
            L[1]->OPC == OP65_ORA               &&
-           strcmp (L[1]->Arg, "tmp1") == 0     &&
-           !CE_HasLabel (L[1])) {
+           strcmp (L[1]->Arg, "tmp1") == 0) {
 
            /* Remove the remaining instructions */
            CS_DelEntries (S, I+1, 2);
@@ -484,37 +353,93 @@ unsigned OptCmp2 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[2];
+       CodeEntry* L[3];
 
        /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+               L[0] = 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)               &&
-                   IsCmpToZero (L[0])                         &&
-           !CE_HasLabel (L[0])                        &&
-                   ((L[1]->Info & OF_FBRA) != 0         ||
-            (L[1]->OPC == OP65_JSR        &&
-             FindBoolCmpCond (L[1]->Arg) != CMP_INV)) &&
-           !CE_HasLabel (L[1])) {
-
-           /* Remove the compare */
-           CS_DelEntry (S, I+1);
+               if ((L[0]->OPC == OP65_ADC ||
+                    L[0]->OPC == OP65_AND ||
+                    L[0]->OPC == OP65_DEA ||
+                    L[0]->OPC == OP65_EOR ||
+                    L[0]->OPC == OP65_INA ||
+                    L[0]->OPC == OP65_LDA ||
+                    L[0]->OPC == OP65_ORA ||
+                    L[0]->OPC == OP65_PLA ||
+                    L[0]->OPC == OP65_SBC ||
+                    L[0]->OPC == OP65_TXA ||
+                    L[0]->OPC == OP65_TYA)         &&
+           !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) {
+
+           /* Check for the call to boolxx. We cannot 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:
+                   case CMP_UGE:
+                   case CMP_ULT:
+                   case CMP_ULE:
+                   case CMP_INV:
+                       /* Leave it alone */
+                       break;
+               }
 
-           /* Remember, we had changes */
-           ++Changes;
+           } 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;
+               }
+           }
        }
 
        /* Next entry */
@@ -562,7 +487,7 @@ unsigned OptCmp3 (CodeSeg* S)
 
        /* Check for the sequence */
                if (E->OPC == OP65_LDA               &&
-           CS_GetEntries (S, L, I+1, 5) &&
+           CS_GetEntries (S, L, I+1, 5)     &&
            L[0]->OPC == OP65_LDX            &&
            !CE_HasLabel (L[0])              &&
            IsImmCmp16 (L+1)                 &&
@@ -610,10 +535,7 @@ unsigned OptCmp4 (CodeSeg* S)
 /* Optimize compares of local variables:
  *
  *      ldy     #o
- *      lda     (sp),y
- *      tax
- *      dey
- *      lda     (sp),y
+ *      jsr     ldaxysp
  *      cpx     #a
  *      bne     L1
  *     cmp     #b
@@ -626,26 +548,52 @@ unsigned OptCmp4 (CodeSeg* S)
     unsigned I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* L[9];
+       CodeEntry* L[6];
+
+       /* Get the next entry */
+       L[0] = CS_GetEntry (S, I);
 
        /* Check for the sequence */
-               if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) {
+       if (L[0]->OPC == OP65_LDY           &&
+           CE_KnownImm (L[0])              &&
+           CS_GetEntries (S, L+1, I+1, 5)  &&
+           !CE_HasLabel (L[1])             &&
+           CE_IsCallTo (L[1], "ldaxysp")   &&
+           IsImmCmp16 (L+2)) {
 
-                   if ((L[8]->Info & OF_FBRA) != 0 && L[5]->Num == 0 && L[7]->Num == 0) {
+                   if ((L[5]->Info & OF_FBRA) != 0 && L[2]->Num == 0 && L[4]->Num == 0) {
 
-               /* The value is zero, we may use the simple code version:
-                *      ldy     #o
-                *      lda     (sp),y
+               CodeEntry* X;
+               char Buf[20];
+
+               /* The value is zero, we may use the simple code version:
                 *      ldy     #o-1
+                *      lda     (sp),y
+                *      ldy     #o
                 *      ora     (sp),y
                 *      jne/jeq ...
                 */
-               CE_ReplaceOPC (L[4], OP65_ORA);
+               sprintf (Buf, "$%02X", (int)(L[0]->Num-1));
+               X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI);
+               CS_InsertEntry (S, X, I+1);
+
+               X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+               CS_InsertEntry (S, X, I+2);
+
+               X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
+               CS_InsertEntry (S, X, I+3);
+
+               X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+               CS_InsertEntry (S, X, I+4);
+
                CS_DelEntries (S, I+5, 3);   /* cpx/bne/cmp */
-               CS_DelEntry (S, I+2);        /* tax */
+               CS_DelEntry (S, I);          /* ldy */
 
                    } else {
 
+               CodeEntry* X;
+               char Buf[20];
+
                /* Change the code to just use the A register. Move the load
                 * of the low byte after the first branch if possible:
                 *
@@ -658,10 +606,23 @@ unsigned OptCmp4 (CodeSeg* S)
                 *      cmp     #b
                 *      jne/jeq ...
                 */
-                       CS_DelEntry (S, I+2);             /* tax */
-               CE_ReplaceOPC (L[5], OP65_CMP);   /* cpx -> cmp */
-               CS_MoveEntry (S, I+4, I+2);       /* cmp */
-               CS_MoveEntry (S, I+5, I+3);       /* bne */
+               X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
+               CS_InsertEntry (S, X, I+3);
+
+               X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+               CS_InsertEntry (S, X, I+4);
+
+               X = NewCodeEntry (OP65_CMP, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
+               CS_InsertEntry (S, X, I+5);
+
+               sprintf (Buf, "$%02X", (int)(L[0]->Num-1));
+               X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI);
+               CS_InsertEntry (S, X, I+7);
+
+               X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
+               CS_InsertEntry (S, X, I+8);
+
+               CS_DelEntries (S, I, 3);          /* ldy/jsr/cpx */
 
            }
 
@@ -901,3 +862,4 @@ NextEntry:
 
 
 
+