]> git.sur5r.net Git - cc65/blobdiff - src/cc65/optimize.c
Added the io module
[cc65] / src / cc65 / optimize.c
index 8302ebdc2bb2905c2d707a64ad1ac375ee64fb4c..48ce3fbb61233acae5c3c8dd4c2f05f0f501069d 100644 (file)
 
 
 #include <stdarg.h>
+#include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 
+/* common */
+#include "attrib.h"
+#include "xmalloc.h"
+
+/* cc65 */
 #include "asmlabel.h"
 #include "asmline.h"
 #include "check.h"
 #include "cpu.h"
 #include "error.h"
 #include "global.h"
-#include "io.h"
-#include "mem.h"
 #include "optimize.h"
 
 
@@ -125,7 +129,7 @@ static const struct {
     { "\tcpx\t",                 0,    REG_X,      REG_NONE      },
     { "\tcpy\t",                 0,    REG_Y,      REG_NONE      },
     { "\tdea",           1,    REG_A,      REG_NONE      },
-    { "\tdec\ta",        1,    REG_A,      REG_NONE      },
+    { "\tdec\ta",        1,    REG_A,      REG_NONE      },
     { "\tdec\t",                 0,    REG_NONE,   REG_NONE      },
     { "\tdex",                   1,    REG_X,      REG_NONE      },
     { "\tdey",                   1,    REG_Y,      REG_NONE      },
@@ -225,7 +229,7 @@ static const char* LongBranches [] = {
 
 
 /*****************************************************************************/
-/*                                        Forwards                                  */
+/*                                        Forwards                                  */
 /*****************************************************************************/
 
 
@@ -242,10 +246,19 @@ static unsigned GetLabelNum (const char* L);
 static unsigned RVUInt1 (Line* L, LineColl* LC, unsigned Used, unsigned Unused);
 /* Subfunction for RegValUsed. Will be called recursively in case of branches. */
 
+static Line* NewLineAfter (Line* LineBefore, const char* Format, ...) attribute ((format(printf,2,3)));
+/* Create a new line, insert it after L and return it. The new line is marked
+ * as code line.
+ */
+
+static Line* ReplaceLine (Line* L, const char* Format, ...)
+       attribute ((format(printf,2,3)));
+/* Replace one line by another */
+
 
 
 /*****************************************************************************/
-/*                                       List stuff                                 */
+/*                                       List stuff                                 */
 /*****************************************************************************/
 
 
@@ -1103,7 +1116,7 @@ static unsigned RVUInt2 (Line* L,
        do {
 
            /* Handle jumps to local labels (continue there) */
-                   if (LineMatch (L, "\tjmp\tL")) {
+                   if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) {
                /* Get the target of the jump */
                L = GetTargetLine (L->Line+5);
            }
@@ -1113,33 +1126,33 @@ static unsigned RVUInt2 (Line* L,
 
            /* Bail out if we're done */
            if (L == 0 || IsLabel (L)) {
-               /* Something is wrong */
-               return REG_ALL;
+               /* Something is wrong */
+               return REG_ALL;
            }
 
            /* Check if we had this line already. If so, bail out, if not,
             * add it to the list of known lines.
             */
            if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
-               goto ExitPoint;
+               goto ExitPoint;
            }
 
-       } while (LineMatch (L, "\tjmp\tL"));
+       } while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
 
        /* Special handling for branches */
        if (LineMatchX (L, ShortBranches) >= 0 ||
            LineMatchX (L, LongBranches) >= 0) {
            const char* Target = L->Line+5;
            if (Target[0] == 'L') {
-               /* Jump to local label. Check the register usage starting at
-                * the branch target and at the code following the branch.
-                * All registers that are unused in both execution flows are
-                * returned as unused.
-                */
-               unsigned U1, U2;
+               /* Jump to local label. Check the register usage starting at
+                * the branch target and at the code following the branch.
+                * All registers that are unused in both execution flows are
+                * returned as unused.
+                */
+               unsigned U1, U2;
                        U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
-               U1 = RVUInt1 (L, LC, Used, Unused);
-               return U1 | U2;         /* Used in any of the branches */
+               U1 = RVUInt1 (L, LC, Used, Unused);
+               return U1 | U2;         /* Used in any of the branches */
            }
        }
 
@@ -1758,7 +1771,7 @@ static void OptRegLoads (void)
 
            /* Search for a load of Y and check if the value is used later */
            else if (LineMatch (L, "\tldy\t")           &&
-                              !RegYUsed (L)                    &&
+                              !RegYUsed (L)                    &&
                       !IsCondJump (NextInstruction (L))) {
 
                /* Remember to delete this line */
@@ -1844,8 +1857,8 @@ static int OptPtrOps1 (Line** Start)
            /* Cannot get lines */
            return 0;
        }
-       if (LineFullMatch (L2[3], "\tclc")                      &&
-           LineMatch (L2[4], "\tadc\t#$")                      &&
+       if (LineFullMatch (L2[3], "\tclc")                      &&
+           LineMatch (L2[4], "\tadc\t#$")                      &&
            LineFullMatch (L2[5], "\tbcc\t*+3")                 &&
            LineFullMatch (L2[6], "\tinx")) {
            /* Inlined increment */
@@ -1859,9 +1872,9 @@ static int OptPtrOps1 (Line** Start)
     }
 
     /* Check for the remainder */
-    if (!LineMatch (L3[0], "\tsta\t")                          ||
+    if (!LineMatch (L3[0], "\tsta\t")                          ||
        strcmp (L3[0]->Line+5, L->Line+5) != 0                  ||
-       !LineMatch (L3[1], "\tstx\t")                           ||
+       !LineMatch (L3[1], "\tstx\t")                           ||
        strcmp (L3[1]->Line+5, L2[0]->Line+5) != 0              ||
        !LineFullMatch (L3[2], "\tlda\tregsave")                ||
        !LineFullMatch (L3[3], "\tldx\tregsave+1")) {
@@ -1871,18 +1884,14 @@ static int OptPtrOps1 (Line** Start)
     }
 
     /* Check if AX is actually used following the code above. If not,
-     * we don't need to load A/X from regsave. Since X will never by
+     * we don't need to load A/X from regsave. Since X will never be
      * used without A, check just for A.
      */
-    NeedLoad = 1;
-    if (!RegAUsed (L3[3])) {
-       /* We don't need to load regsave */
-       NeedLoad = 0;
-    }
+    NeedLoad = RegAUsed (L3[3]);
 
     /* Special code for register variables */
     Done = 0;
-    if (LineMatch (L, "\tlda\tregbank+")       &&
+    if (LineMatch (L, "\tlda\tregbank+")       &&
                GetNextCodeLines (L3[3], &L3[4], 1)     &&
        Inc == 1) {
 
@@ -2041,8 +2050,8 @@ static int OptPtrOps1 (Line** Start)
 
        /* If we need to load a/x, add the code */
        if (NeedLoad) {
-           L = NewLineAfter (L, "\ttax");
            L = NewLineAfter (L, "\tlda\tptr1");
+           L = NewLineAfter (L, "\tldx\tptr1+1");
        }
     }
 
@@ -2156,11 +2165,7 @@ static int OptPtrOps2 (Line** Start)
      * we don't need to load A/X from regsave. Since X will never by
      * used without A, check just for A.
      */
-    NeedLoad = 1;
-    if (!RegAUsed (L3[0])) {
-       /* We don't need to load regsave */
-       NeedLoad = 0;
-    }
+    NeedLoad = RegAUsed (L3[0]);
 
     /* Replace the ldy instruction, offset must point to the low byte */
     sprintf (L->Line+7, "%02X", Offs);
@@ -2250,8 +2255,8 @@ static int OptPtrOps2 (Line** Start)
 
     /* If we need to load a/x, add the code */
     if (NeedLoad) {
-       L = NewLineAfter (L, "\ttax");
        L = NewLineAfter (L, "\tlda\tptr1");
+       L = NewLineAfter (L, "\tldx\tptr1+1");
     }
 
     /* Remove the code that is no longer needed */
@@ -3635,6 +3640,9 @@ static Line* OptOneBlock (Line* L)
                }
            }
                } else if (LineMatch (L, "\tadc\t")) {
+           if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) {
+               L->Line[strlen(L->Line)-2] = '\0';
+           }
            A = -1;
        } else if (LineMatch (L, "\tand\t")) {
            A = -1;
@@ -3642,7 +3650,10 @@ static Line* OptOneBlock (Line* L)
            if (A != -1) {
                A = (A << 1) & 0xFF;
            }
-       } else if (CPU == CPU_65C02 && LineFullMatch (L, "\tdea")) {
+               } else if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) {
+           L->Line[strlen(L->Line)-2] = '\0';
+       } else if (CPU == CPU_65C02 && (LineFullMatch (L, "\tdea") ||
+                                       LineFullMatch (L, "\tdec\ta"))) {
            DEC (A, 1);
        } else if (LineFullMatch (L, "\tdex")) {
            DEC (X, 1);
@@ -3650,7 +3661,8 @@ static Line* OptOneBlock (Line* L)
            DEC (Y, 1);
        } else if (LineMatch (L, "\teor")) {
            A = -1;
-       } else if (CPU == CPU_65C02 && LineFullMatch (L, "\tina")) {
+       } else if (CPU == CPU_65C02 && (LineFullMatch (L, "\tina") ||
+                                       LineFullMatch (L, "\tinc\ta"))) {
            INC (A, 1);
        } else if (LineFullMatch (L, "\tinx")) {
            INC (X, 1);
@@ -3867,6 +3879,10 @@ static Line* OptOneBlock (Line* L)
        } else if (LineFullMatch (L, "\tjsr\tpushax")) {
            /* We know about this function */
            Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushaysp")) {
+           /* We know about this function */
+           A = -1;
+           Y = 0;
        } else if (LineFullMatch (L, "\tjsr\tpushc0")) {
            /* We know about this function */
            A = 0;
@@ -4088,6 +4104,9 @@ static Line* OptOneBlock (Line* L)
        } else if (LineFullMatch (L, "\trti")) {
            A = X = Y = -1;
        } else if (LineMatch (L, "\tsbc\t")) {
+           if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) {
+               L->Line[strlen(L->Line)-2] = '\0';
+           }
            A = -1;
        } else if (CPU == CPU_65C02 && LineMatch (L, "\tst")) {
            /* Try to replace by stz if possible */
@@ -4095,7 +4114,7 @@ static Line* OptOneBlock (Line* L)
                /* Not indirect and not Y allowed */
                if (L->Line[5] != '(' && !IsYAddrMode (L)) {
                    L->Line[3] = 'z';
-               }
+               }
            } else if (X == 0 && LineMatch (L, "\tstx\t")) {
                /* absolute,y not allowed */
                if (!IsYAddrMode (L)) {
@@ -4196,6 +4215,26 @@ static void OptJumps (void)
        }
        L = NextCodeLine (L);
     }
+
+    /* Special treatment for jumps on the 65C02 */
+    if (CPU == CPU_65C02) {
+
+       Line* L = FirstCode;
+       while (L) {
+           if (LineMatch (L, "\tjmp\tL")) {
+               Line* Target = GetTargetLine (L->Line+5);
+               unsigned Distance = GetJumpDistance (L, Target);
+               if (Distance < 123) {           /* Safety */
+                           L->Line [1] = 'b';          /* Make a short branch */
+                   L->Line [2] = 'r';
+                   L->Line [3] = 'a';
+                   L->Size = 2;                /* Set new size */
+               }
+           }
+           L = NextCodeLine (L);
+       }
+
+    }
 }