]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
added optimization for indexed 16-bit array load of form (array[i & 0x7f])
[cc65] / src / cc65 / codeopt.c
index e44bf2bf5590976edc1afe29ed3c09e4ed3f4ccc..d920f001a6134488cad838e84aa3302a56e45db3 100644 (file)
@@ -69,7 +69,7 @@
 #include "error.h"
 #include "global.h"
 #include "output.h"
-
+#include "symtab.h"
 
 
 /*****************************************************************************/
@@ -613,7 +613,116 @@ static unsigned OptStackPtrOps (CodeSeg* S)
     return Changes;
 }
 
+static unsigned OptGotoSPAdj (CodeSeg* S)
+/* Optimize SP adjustment for forward 'goto' */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        CodeEntry* L[10], *X;
+        unsigned short adjustment;
+        const char* Arg;
+
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
+
+        /* Check for the sequence generated by g_lateadjustSP */
+        if (L[0]->OPC == OP65_PHA            &&
+            CS_GetEntries (S, L+1, I+1, 9)   &&
+            L[1]->OPC == OP65_LDA            &&
+            L[1]->AM == AM65_ABS             &&
+            L[2]->OPC == OP65_CLC            &&
+            L[3]->OPC == OP65_ADC            &&
+            strcmp (L[3]->Arg, "sp") == 0    &&
+            L[6]->OPC == OP65_ADC            &&
+            strcmp (L[6]->Arg, "sp+1") == 0  &&
+            L[9]->OPC == OP65_JMP) {
+            adjustment = FindSPAdjustment (L[1]->Arg);
+
+            if (adjustment == 0) {
+                /* No SP adjustment needed, remove the whole sequence */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment >= 65536 - 8) {
+                /* If adjustment is in range [-8, 0) we use decsp* calls */
+                char Buf[20];
+                adjustment = 65536 - adjustment;
+                xsprintf (Buf, sizeof (Buf), "decsp%u", adjustment);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment >= 65536 - 255) {
+                /* For range [-255, -8) we have ldy #, jsr subysp */
+                adjustment = 65536 - adjustment;
+                Arg = MakeHexArg (adjustment);
+                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 10);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment > 255) {
+                /* For ranges [-32768, 255) and (255, 32767) the only modification
+                ** is to replace the absolute with immediate addressing
+                */
+                Arg = MakeHexArg (adjustment & 0xff);
+                X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 1);
+                Arg = MakeHexArg (adjustment >> 8);
+                X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, L[5]->LI);
+                CS_InsertEntry (S, X, I + 6);
+
+                /* Delete the old code */
+                CS_DelEntry (S, I + 2);
+                CS_DelEntry (S, I + 6);
+            }
+            else if (adjustment > 8) {
+                /* For range (8, 255] we have ldy #, jsr addysp */
+                Arg = MakeHexArg (adjustment & 0xff);
+                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, "addysp", 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 10);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else {
+                /* If adjustment is in range (0, 8] we use incsp* calls */
+                char Buf[20];
+                xsprintf (Buf, sizeof (Buf), "incsp%u", adjustment);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            /* Regenerate register info */
+            CS_GenRegInfo (S);
+
+            /* Remember we had changes */
+            Changes++;
+
+        } else {
+
+            /* Next entry */
+            ++I;
+        }
 
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
 
 /*****************************************************************************/
 /*                              struct OptFunc                               */
@@ -675,6 +784,7 @@ static OptFunc DOptDeadCode     = { OptDeadCode,     "OptDeadCode",     100, 0,
 static OptFunc DOptDeadJumps    = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
+static OptFunc DOptGotoSPAdj    = { OptGotoSPAdj,    "OptGotoSPAdj",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptIndLoads1    = { OptIndLoads1,    "OptIndLoads1",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptIndLoads2    = { OptIndLoads2,    "OptIndLoads2",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
@@ -704,6 +814,8 @@ static OptFunc DOptPtrLoad14    = { OptPtrLoad14,    "OptPtrLoad14",    108, 0,
 static OptFunc DOptPtrLoad15    = { OptPtrLoad15,    "OptPtrLoad15",     86, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad16    = { OptPtrLoad16,    "OptPtrLoad16",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad17    = { OptPtrLoad17,    "OptPtrLoad17",    190, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad18    = { OptPtrLoad18,    "OptPtrLoad18",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad19    = { OptPtrLoad19,    "OptPtrLoad19",     65, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore1    = { OptPtrStore1,    "OptPtrStore1",     65, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore2    = { OptPtrStore2,    "OptPtrStore2",     65, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore3    = { OptPtrStore3,    "OptPtrStore3",    100, 0, 0, 0, 0, 0 };
@@ -774,6 +886,7 @@ static OptFunc* OptFuncs[] = {
     &DOptDeadJumps,
     &DOptDecouple,
     &DOptDupLoads,
+    &DOptGotoSPAdj,
     &DOptIndLoads1,
     &DOptIndLoads2,
     &DOptJumpCascades,
@@ -794,6 +907,8 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrLoad15,
     &DOptPtrLoad16,
     &DOptPtrLoad17,
+    &DOptPtrLoad18,
+    &DOptPtrLoad19,
     &DOptPtrLoad2,
     &DOptPtrLoad3,
     &DOptPtrLoad4,
@@ -870,7 +985,7 @@ static OptFunc* GetOptFunc (const char* Name)
     OptFunc* F = FindOptFunc (Name);
     if (F == 0) {
         /* Not found */
-        AbEnd ("Optimization step `%s' not found", Name);
+        AbEnd ("Optimization step '%s' not found", Name);
     }
     return F;
 }
@@ -1057,10 +1172,10 @@ static void WriteDebugOutput (CodeSeg* S, const char* Step)
         /* Output a header line */
         if (Step == 0) {
             /* Initial output */
-            WriteOutput ("Initial code for function `%s':\n",
+            WriteOutput ("Initial code for function '%s':\n",
                          S->Func? S->Func->Name : "<global>");
         } else {
-            WriteOutput ("Code after applying `%s':\n", Step);
+            WriteOutput ("Code after applying '%s':\n", Step);
         }
 
         /* Output the code segment */
@@ -1122,6 +1237,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
 {
     unsigned Changes = 0;
 
+    Changes += RunOptFunc (S, &DOptGotoSPAdj, 1);
     Changes += RunOptFunc (S, &DOptStackPtrOps, 5);
     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
     Changes += RunOptFunc (S, &DOptPtrStore2, 1);
@@ -1134,6 +1250,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad7, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad18, 1); /* Before OptPtrLoad11 */
     Changes += RunOptFunc (S, &DOptPtrLoad11, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad12, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad13, 1);
@@ -1141,6 +1258,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad15, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad16, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad17, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad19, 1);
     Changes += RunOptFunc (S, &DOptBNegAX1, 1);
     Changes += RunOptFunc (S, &DOptBNegAX2, 1);
     Changes += RunOptFunc (S, &DOptBNegAX3, 1);
@@ -1400,7 +1518,7 @@ void RunOpt (CodeSeg* S)
 
     /* Print the name of the function we are working on */
     if (S->Func) {
-        Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
+        Print (stdout, 1, "Running optimizer for function '%s'\n", S->Func->Name);
     } else {
         Print (stdout, 1, "Running optimizer for global code segment\n");
     }