]> git.sur5r.net Git - cc65/commitdiff
More optimizations
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 25 Sep 2001 20:37:58 +0000 (20:37 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 25 Sep 2001 20:37:58 +0000 (20:37 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@971 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeinfo.c
src/cc65/codeinfo.h
src/cc65/codeopt.c
src/cc65/coptind.h
src/cc65/coptstop.c [new file with mode: 0644]
src/cc65/coptstop.h [new file with mode: 0644]
src/cc65/make/gcc.mak
src/cc65/make/watcom.mak

index 9dd6e9b95214e85df3715b4cbbc37edce4995a78..8592e32c8b1426d10f2fca66f16e004b65bfe6ef 100644 (file)
@@ -144,6 +144,8 @@ static const FuncInfo FuncInfoTable[] = {
     { "staspidx",       REG_A | REG_Y,        REG_Y | REG_TMP1 | REG_PTR1    },
     { "stax0sp",        REG_AX,               REG_Y                         },
     { "staxysp",        REG_AXY,              REG_Y                         },
+    { "tosadda0",       REG_A,                REG_AXY                        },
+    { "tosaddax",       REG_AX,               REG_AXY                        },
     { "tosicmp",               REG_AX,               REG_AXY | REG_SREG             },
     { "tosdiva0",       REG_AX,                      REG_ALL                        },
     { "tosdivax",       REG_AX,                      REG_ALL                        },
@@ -164,22 +166,24 @@ static const ZPInfo ZPInfoTable[] = {
     {   0, "ptr1+1",    REG_PTR1_HI,   REG_PTR1        },
     {          0, "ptr2",      REG_PTR2_LO,    REG_PTR2        },
     {   0, "ptr2+1",    REG_PTR2_HI,   REG_PTR2        },
-    {          4, "ptr3",      REG_NONE,       REG_NONE        },
-    {          4, "ptr4",      REG_NONE,       REG_NONE        },
-    {   7, "regbank",   REG_NONE,      REG_NONE        },
+    {          4, "ptr3",      REG_NONE,       REG_NONE        },
+    {          4, "ptr4",      REG_NONE,       REG_NONE        },
+    {   7, "regbank",   REG_NONE,      REG_NONE        },
     {   0, "regsave",   REG_SAVE_LO,   REG_SAVE        },
     {   0, "regsave+1", REG_SAVE_HI,   REG_SAVE        },
-    {   2, "sp",        REG_NONE,      REG_NONE        },
+    {   0, "sp",        REG_SP_LO,             REG_SP          },
+    {   0, "sp+1",      REG_SP_HI,      REG_SP          },
     {   0, "sreg",      REG_SREG_LO,   REG_SREG        },
     {  0, "sreg+1",    REG_SREG_HI,    REG_SREG        },
-    {   0, "tmp1",      REG_TMP1,      REG_TMP1        },
-    {   0, "tmp2",      REG_NONE,      REG_NONE        },
-    {   0, "tmp3",      REG_NONE,      REG_NONE        },
-    {   0, "tmp4",      REG_NONE,      REG_NONE        },
+    {   0, "tmp1",      REG_TMP1,      REG_TMP1        },
+    {   0, "tmp2",      REG_NONE,      REG_NONE        },
+    {   0, "tmp3",      REG_NONE,      REG_NONE        },
+    {   0, "tmp4",      REG_NONE,      REG_NONE        },
 };
 #define ZPInfoCount            (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0]))
 
 
+
 /*****************************************************************************/
 /*                                          Code                                    */
 /*****************************************************************************/
@@ -395,7 +399,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
                unsigned U2;
 
                U1 = GetRegInfo2 (S, E->JumpTo->Owner, -1, Visited, Used, Unused, Wanted);
-               if (U1 == REG_AXY) {
+               if (U1 == REG_ALL) {
                    /* All registers used, no need for second call */
                    return REG_AXY;
                }
@@ -434,7 +438,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
 }
 
 
-
+                                
 static unsigned GetRegInfo1 (CodeSeg* S,
                             CodeEntry* E,
                             int Index,
index c445bd4312760a696652b9102a81cb6ce26aac25..435e49884e794ceca474c0887b37cc037c63620a 100644 (file)
@@ -68,17 +68,21 @@ struct CodeSeg;
 #define REG_SREG_HI     0x0200U
 #define REG_SAVE_LO     0x0400U
 #define REG_SAVE_HI     0x0800U
+#define REG_SP_LO       0x1000U
+#define REG_SP_HI       0x2000U
+
 
 /* Combined register defines */
 #define REG_PTR1        (REG_PTR1_LO | REG_PTR1_HI)
 #define REG_PTR2        (REG_PTR2_LO | REG_PTR2_HI)
 #define REG_SREG        (REG_SREG_LO | REG_SREG_HI)
 #define REG_SAVE        (REG_SAVE_LO | REG_SAVE_HI)
+#define REG_SP          (REG_SP_LO | REG_SP_HI)
 #define        REG_AX          (REG_A | REG_X)
 #define REG_AY          (REG_A | REG_Y)
 #define REG_XY         (REG_X | REG_Y)
 #define REG_AXY                (REG_AX | REG_Y)
-#define REG_EAX         (REG_AX | REG_SREG)
+#define REG_EAX         (REG_AX | REG_SREG)    
 #define REG_EAXY        (REG_EAX | REG_Y)
 #define REG_ZP          0xFFF8U
 #define REG_ALL         0xFFFFU
index 789c177d1d73ce38820dd386cac5b4df8967c9a5..0e8012864a00bf05730a2f4edfd8e4f1048b0164 100644 (file)
@@ -47,6 +47,7 @@
 #include "codeent.h"
 #include "codeinfo.h"
 #include "coptind.h"
+#include "coptstop.h"
 #include "error.h"
 #include "global.h"
 #include "codeopt.h"
@@ -1005,7 +1006,7 @@ static unsigned OptCmp2 (CodeSeg* S)
 
     /* Return the number of changes made */
     return Changes;
-}                
+}
 
 
 
@@ -1301,25 +1302,25 @@ static unsigned OptCmp7 (CodeSeg* S)
 
                /* Evaluate the branch condition */
                int Cond;
-               switch (GetBranchCond (N->OPC)) {
-                   case BC_CC:
-                       Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
-                       break;
+               switch (GetBranchCond (N->OPC)) {
+                   case BC_CC:
+                       Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
+                       break;
 
-                   case BC_CS:
-                       Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
-                       break;
+                   case BC_CS:
+                       Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
+                       break;
 
-                   case BC_EQ:
-                       Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
-                       break;
+                   case BC_EQ:
+                       Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
+                       break;
 
-                   case BC_MI:
+                   case BC_MI:
                                Cond = ((signed char)RegVal) < ((signed char)E->Num);
-                       break;
+                       break;
 
-                   case BC_NE:
-                       Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
+                   case BC_NE:
+                       Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
                        break;
 
                    case BC_PL:
@@ -1328,7 +1329,17 @@ static unsigned OptCmp7 (CodeSeg* S)
 
                    case BC_VC:
                    case BC_VS:
-               }
+                       /* Not set by the compare operation, bail out (Note:
+                        * Just skipping anything here is rather stupid, but
+                        * the sequence is never generated by the compiler,
+                        * so it's quite safe to skip).
+                        */
+                       goto NextEntry;
+
+                   default:
+                       Internal ("Unknown branch condition");
+
+               }
 
                /* If the condition is false, we may remove the jump. Otherwise
                 * the branch will always be taken, so we may replace it by a
@@ -1355,7 +1366,8 @@ static unsigned OptCmp7 (CodeSeg* S)
 
        }
 
-       /* Next entry */
+NextEntry:
+       /* Next entry */
        ++I;
 
     }
@@ -2709,6 +2721,8 @@ static OptFunc OptFuncs [] = {
     OptEntry (OptDuplicateLoads, optMain),
     OptEntry (OptStoreLoad, optMain),
     OptEntry (OptTransfers, optMain),
+    /* Optimize operations that use the stack to pass operands */
+    OptEntry (OptStackOps, optMain),
     /* Optimize branch distance */
     OptEntry (OptBranchDist, optPost),
 };
index 746637092bb88a193286ea48454bea0a2af4e971..ae6bb37209914f52cd4244ab61a59a0d005e597b 100644 (file)
 
 
 
+/* cc65 */
 #include "codeseg.h"
 
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                  Code                                    */
 /*****************************************************************************/
 
 
diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c
new file mode 100644 (file)
index 0000000..40d6354
--- /dev/null
@@ -0,0 +1,299 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptstop.c                                */
+/*                                                                           */
+/*          Optimize operations that take operands via the stack            */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2001      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+/* cc65 */
+#include "codeent.h"
+#include "codeinfo.h"
+#include "codeopt.h"
+#include "error.h"
+#include "coptstop.h"
+
+
+
+/*****************************************************************************/
+/*                                 Helpers                                  */
+/*****************************************************************************/
+
+
+
+static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add)
+/* Optimize the tosaddax sequence if possible */
+{
+    unsigned I;
+    CodeEntry* N;
+    CodeEntry* X;
+    CodeEntry* PushEntry;
+    CodeEntry* AddEntry;
+    const char* ZPLo;
+    const char* ZPHi;
+
+    /* Check if the sequence is safe. This means that there may not be any
+     * jumps between the two data points, and no usage of the stack. Handling
+     * these conditions is possible and may be done later.
+     */
+    unsigned UsedRegs = REG_NONE;
+    for (I = Push + 1; I < Add; ++I) {
+       CodeEntry* E = CS_GetEntry (S, I);
+       if ((E->Info & OF_BRA) != 0 ||
+           (E->Use & REG_SP) != 0  ||
+           CE_HasLabel (E)) {
+           /* A jump or stack pointer usage - bail out */
+           return 0;
+       }
+       UsedRegs |= (E->Use | E->Chg);
+    }
+
+    /* We prefer usage of sreg for the intermediate value, since sreg is
+     * tracked and optimized.
+     */
+    UsedRegs |= GetRegInfo (S, Push+1, REG_ALL);
+    if ((UsedRegs & REG_SREG) == REG_NONE) {
+       /* SREG is available */
+       ZPLo = "sreg";
+       ZPHi = "sreg+1";
+    } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
+       ZPLo = "ptr1";
+       ZPHi = "ptr1+1";
+    } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
+       ZPLo = "ptr2";
+       ZPHi = "ptr2+1";
+    } else {
+       /* No registers available */
+       return 0;
+    }
+
+    /* We need the entry behind the add */
+    if ((N = CS_GetNextEntry (S, Add)) == 0) {
+       /* Unavailable */
+       return 0;
+    }
+
+    /* Generate register info */
+    CS_GenRegInfo (S);
+
+    /* Get the push entry */
+    PushEntry = CS_GetEntry (S, Push);
+
+    /* Store the value into sreg instead of pushing it */
+    X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+1);
+    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+2);
+
+    /* Correct the index of the add and get a pointer to the entry */
+    Add += 2;
+    AddEntry = CS_GetEntry (S, Add);
+
+    /* Inline the add */
+    X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI);
+    CS_InsertEntry (S, X, Add+1);
+    X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
+    CS_InsertEntry (S, X, Add+2);
+    if (PushEntry->RI->In.RegX == 0 && AddEntry->RI->In.RegX == 0) {
+       /* The high byte is zero on entry */
+       CodeLabel* L = CS_GenLabel (S, N);
+       X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+3);
+       X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+4);
+    } else {
+       /* High byte is unknown */
+       X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+3);
+       X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+4);
+       X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPHi, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+5);
+       X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+6);
+       X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, AddEntry->LI);
+       CS_InsertEntry (S, X, Add+7);
+    }
+
+    /* Remove the push and the call to the tosaddax function */
+    CS_DelEntry (S, Add);
+    CS_DelEntry (S, Push);
+
+    /* Free the register info */
+    CS_FreeRegInfo (S);
+
+    /* We changed the sequence */
+    return 1;
+}
+
+
+
+static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store)
+/* Optimize the staspidx sequence if possible */
+{
+    unsigned I;
+    CodeEntry* N;
+    CodeEntry* X;
+    CodeEntry* PushEntry;
+    CodeEntry* StoreEntry;
+    const char* ZPLo;
+    const char* ZPHi;
+
+    /* Check if the sequence is safe. This means that there may not be any
+     * jumps between the two data points, and no usage of the stack. Handling
+     * these conditions is possible and may be done later.
+     */
+    unsigned UsedRegs = REG_NONE;
+    for (I = Push + 1; I < Store; ++I) {
+       CodeEntry* E = CS_GetEntry (S, I);
+       if ((E->Info & OF_BRA) != 0 ||
+           (E->Use & REG_SP) != 0  ||
+           CE_HasLabel (E)) {
+           /* A jump or stack pointer usage - bail out */
+           return 0;
+       }
+       UsedRegs |= (E->Use | E->Chg);
+    }
+
+    /* We prefer usage of sreg for the intermediate value, since sreg is
+     * tracked and optimized.
+     */
+    UsedRegs |= GetRegInfo (S, Push+1, REG_SREG | REG_PTR1 | REG_PTR2);
+    if ((UsedRegs & REG_SREG) == REG_NONE) {
+       /* SREG is available */
+       ZPLo = "sreg";
+       ZPHi = "sreg+1";
+    } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
+       ZPLo = "ptr1";
+       ZPHi = "ptr1+1";
+    } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
+       ZPLo = "ptr2";
+       ZPHi = "ptr2+1";
+    } else {
+       /* No registers available */
+       return 0;
+    }
+
+    /* We need the entry behind the store */
+    if ((N = CS_GetNextEntry (S, Store)) == 0) {
+       /* Unavailable */
+       return 0;
+    }
+
+    /* Generate register info */
+    CS_GenRegInfo (S);
+
+    /* Get the push entry */
+    PushEntry = CS_GetEntry (S, Push);
+
+    /* Store the value into sreg instead of pushing it */
+    X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+1);
+    X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
+    CS_InsertEntry (S, X, Push+2);
+
+    /* Correct the index of the store and get a pointer to the entry */
+    Store += 2;
+    StoreEntry = CS_GetEntry (S, Store);
+
+    /* Inline the store */
+    X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
+    CS_InsertEntry (S, X, Store+1);
+
+    /* Remove the push and the call to the staspidx function */
+    CS_DelEntry (S, Store);
+    CS_DelEntry (S, Push);
+
+    /* Free the register info */
+    CS_FreeRegInfo (S);
+
+    /* We changed the sequence */
+    return 1;
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned OptStackOps (CodeSeg* S)
+/* Optimize operations that take operands via the stack */
+{
+    unsigned Changes = 0;          /* Number of changes in one run */
+    int LastPush = -1;             /* Last call to pushax */
+
+    /* Walk over all entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       /* Get the next entry */
+       CodeEntry* E = CS_GetEntry (S, I);
+
+       /* Check for a subroutine call */
+       if (E->OPC == OP65_JSR) {
+
+           /* We look for two things: A call to pushax, and a call to one
+            * of the known functions we're going to replace. We're only
+            * interested in the latter ones, if we had a push before.
+            */
+           if (strcmp (E->Arg, "pushax") == 0) {
+
+               /* Just remember it */
+               LastPush = I;
+
+           } else if (LastPush >= 0) {
+
+               if (strcmp (E->Arg, "tosaddax") == 0) {
+                   Changes += Opt_tosaddax (S, LastPush, I);
+                   LastPush = -1;
+               } else if (strcmp (E->Arg, "staspidx") == 0) {
+                   Changes += Opt_staspidx (S, LastPush, I);
+                   LastPush = -1;
+               }
+
+           }
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
diff --git a/src/cc65/coptstop.h b/src/cc65/coptstop.h
new file mode 100644 (file)
index 0000000..786158e
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptstop.h                                */
+/*                                                                           */
+/*          Optimize operations that take operands via the stack            */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2001      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef COPTSTOP_H
+#define COPTSTOP_H
+
+
+
+/* cc65 */
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned OptStackOps (CodeSeg* S);
+/* Optimize operations that take operands via the stack */
+
+
+
+/* End of coptstop.h */
+#endif
+
+
+
index fb547852965b9b1b87fbc5283989b26156705cfd..de707c8065e9af33ffbfc0d9f5be08940c7d2940 100644 (file)
@@ -34,6 +34,7 @@ OBJS =        anonname.o      \
        codeseg.o       \
        compile.o       \
        coptind.o       \
+       coptstop.o      \
        cpu.o           \
        dataseg.o       \
        datatype.o      \
@@ -105,3 +106,4 @@ depend dep: $(OBJS:.o=.c)
        $(CC) -I$(COMMON) -MM $^ > .depend
 
 
+                        
index ad6585172c8be426e9b9fca8270e801532f2f967..2d21b640abebfcccda5ab8d7da158bc03136c845 100644 (file)
@@ -79,6 +79,7 @@ OBJS =        anonname.obj    \
        codeseg.obj     \
        compile.obj     \
        coptind.obj     \
+       coptstop.obj    \
        cpu.obj         \
        dataseg.obj     \
        datatype.obj    \
@@ -148,6 +149,7 @@ FILE codeopt.obj
 FILE codeseg.obj
 FILE compile.obj
 FILE coptind.obj
+FILE coptstop.obj
 FILE cpu.obj
 FILE dataseg.obj
 FILE datatype.obj