]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
Added HuC6280 cpu (will be treated as a 65C02)
[cc65] / src / cc65 / codeopt.c
index a7b46ca1b8258f9d2b11bc8f62fa8036cd96a5cf..e26e747f42c2d8451d847e85015fbed322fac581 100644 (file)
@@ -7,7 +7,7 @@
 /*                                                                           */
 /*                                                                           */
 /* (C) 2001-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
+/*               Römerstraße 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -42,7 +42,6 @@
 #include "cpu.h"
 #include "print.h"
 #include "xmalloc.h"
-#include "xsprintf.h"
 
 /* cc65 */
 #include "asmlabel.h"
@@ -138,8 +137,7 @@ static unsigned OptShift1 (CodeSeg* S)
 
 static unsigned OptShift2 (CodeSeg* S)
 /* A call to the shraxN routine may get replaced by one or more lsr insns
- * if the value of X is not used later, or if the value of X is known and
- * zero.
+ * if the value of X is zero.
  */
 {
     unsigned Changes = 0;
@@ -160,7 +158,7 @@ static unsigned OptShift2 (CodeSeg* S)
                    strncmp (E->Arg, "shrax", 5) == 0        &&
            strlen (E->Arg) == 6                     &&
            IsDigit (E->Arg[5])                      &&
-                   (E->RI->In.RegX == 0 || !RegXUsed (S, I+1))) {
+                   E->RI->In.RegX == 0) {
 
            /* Insert shift insns */
            unsigned Count = E->Arg[5] - '0';
@@ -461,6 +459,20 @@ static unsigned OptPtrStore1 (CodeSeg* S)
  *     subop
  *      ldy     yyy
  *      sta     (ptr1),y
+ *
+ * In case a/x is loaded from the register bank before the pushax, we can even
+ * use the register bank instead of ptr1.
+ */
+/*
+ *     jsr     pushax
+ *      ldy     xxx
+ *      jsr     ldauidx
+ *      ldx     #$00
+ *      lda     (zp),y
+ *      subop
+ *      ldy     yyy
+ *      sta     (zp),y
+ *     jsr     staspidx
  */
 {
     unsigned Changes = 0;
@@ -491,28 +503,66 @@ static unsigned OptPtrStore1 (CodeSeg* S)
            CE_IsCallTo (L[4+K], "staspidx")        &&
            !CE_HasLabel (L[4+K])) {
 
+
+            const char* RegBank = 0;
+            const char* ZPLoc   = "ptr1";
            CodeEntry* X;
 
-           /* Create and insert the stores */
-                   X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+1);
 
-           X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
-           CS_InsertEntry (S, X, I+2);
+            /* Get the preceeding two instructions and check them. We check
+             * for:
+             *          lda     regbank+n
+             *          ldx     regbank+n+1
+             */
+            if (I > 1) {
+                CodeEntry* P[2];
+                P[0] = CS_GetEntry (S, I-2);
+                P[1] = CS_GetEntry (S, I-1);
+                if (P[0]->OPC == OP65_LDA &&
+                    P[0]->AM  == AM65_ZP  &&
+                    P[1]->OPC == OP65_LDX &&
+                    P[1]->AM  == AM65_ZP  &&
+                    !CE_HasLabel (P[1])   &&
+                    strncmp (P[0]->Arg, "regbank+", 8) == 0) {
+
+                    unsigned Len = strlen (P[0]->Arg);
+
+                    if (strncmp (P[0]->Arg, P[1]->Arg, Len) == 0 &&
+                        P[1]->Arg[Len+0] == '+'                  &&
+                        P[1]->Arg[Len+1] == '1'                  &&
+                        P[1]->Arg[Len+2] == '\0') {
+
+                        /* Ok, found. Use the name of the register bank */
+                        RegBank = ZPLoc = P[0]->Arg;
+                    }
+                }
+            }
 
-           /* Insert the load from ptr1 */
+           /* Insert the load via the zp pointer */
            X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+5);
-           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[2]->LI);
-           CS_InsertEntry (S, X, I+6);
+           CS_InsertEntry (S, X, I+3);
+           X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, ZPLoc, 0, L[2]->LI);
+           CS_InsertEntry (S, X, I+4);
 
-           /* Insert the store through ptr1 */
-           X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
-           CS_InsertEntry (S, X, I+8+K);
+           /* Insert the store through the zp pointer */
+           X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLoc, 0, L[3]->LI);
+           CS_InsertEntry (S, X, I+6+K);
 
            /* Delete the old code */
-           CS_DelEntry (S, I+9+K);     /* jsr spaspidx */
-            CS_DelEntry (S, I+4);       /* jsr ldauidx */
+           CS_DelEntry (S, I+7+K);     /* jsr spaspidx */
+            CS_DelEntry (S, I+2);       /* jsr ldauidx */
+
+           /* Create and insert the stores into the zp pointer if needed */
+            if (RegBank == 0) {
+                X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+1);
+                X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
+                CS_InsertEntry (S, X, I+2);
+            }
+
+            /* Delete more old code. Do it here to keep a label attached to
+             * entry I in place.
+             */
             CS_DelEntry (S, I);         /* jsr pushax */
 
            /* Remember, we had changes */
@@ -978,7 +1028,7 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
                    L[1]->OPC == OP65_LDX                            &&
            L[1]->AM == AM65_IMM                             &&
            !CE_HasLabel (L[1])                              &&
-           L[2]->OPC == OP65_LDY                            &&
+           L[2]->OPC == OP65_LDY                            &&
            CE_KnownImm (L[2])                               &&
            !CE_HasLabel (L[2])                              &&
            L[3]->OPC == OP65_CLC                            &&
@@ -1008,7 +1058,7 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
            CodeEntry* X;
            char* Label;
 
-           /* Add the lda */
+           /* Add the lda */
            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
            CS_InsertEntry (S, X, I+3);
 
@@ -1028,7 +1078,7 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
            xfree (Label);
 
            /* Remove the old code */
-           CS_DelEntries (S, I, 2);
+           CS_DelEntries (S, I, 2);
            CS_DelEntries (S, I+5, 6);
 
            /* Remember, we had changes */
@@ -1048,6 +1098,152 @@ static unsigned OptPtrLoad4 (CodeSeg* S)
 
 
 static unsigned OptPtrLoad5 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ *      lda     regbank+n
+ *      ldx     regbank+n+1
+ *      sta     regsave
+ *      stx     regsave+1
+ *      clc
+ *      adc     #$01
+ *      bcc     L0005
+ *      inx
+ * L:   sta     regbank+n
+ *      stx     regbank+n+1
+ *      lda     regsave
+ *      ldx     regsave+1
+ *      ldy     #$00
+ *      jsr     ldauidx
+ *
+ * and replace it by:
+ *
+ *      ldy     #$00
+ *      ldx     #$00
+ *      lda     (regbank+n),y
+ *      inc     regbank+n
+ *      bne     L1
+ *      inc     regbank+n+1
+ * L1:  tay                     <- only if flags are used
+ *
+ * This function must execute before OptPtrLoad5!
+ *
+ */
+{
+    unsigned Changes = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+               CodeEntry* L[15];
+       unsigned Len;
+
+       /* Get next entry */
+               L[0] = CS_GetEntry (S, I);
+
+       /* Check for the sequence */
+               if (L[0]->OPC == OP65_LDA                               &&
+            L[0]->AM == AM65_ZP                                 &&
+            strncmp (L[0]->Arg, "regbank+", 8) == 0             &&
+            (Len = strlen (L[0]->Arg)) > 0                      &&
+                   CS_GetEntries (S, L+1, I+1, 14)                     &&
+            !CS_RangeHasLabel (S, I+1, 7)                       &&
+            !CS_RangeHasLabel (S, I+9, 5)                       &&
+            L[1]->OPC == OP65_LDX                               &&
+            L[1]->AM == AM65_ZP                                 &&
+            strncmp (L[1]->Arg, L[0]->Arg, Len) == 0            &&
+            strcmp (L[1]->Arg+Len, "+1") == 0                   &&
+            L[2]->OPC == OP65_STA                               &&
+            L[2]->AM == AM65_ZP                                 &&
+            strcmp (L[2]->Arg, "regsave") == 0                  &&
+            L[3]->OPC == OP65_STX                               &&
+            L[3]->AM == AM65_ZP                                 &&
+            strcmp (L[3]->Arg, "regsave+1") == 0                &&
+            L[4]->OPC == OP65_CLC                               &&
+            L[5]->OPC == OP65_ADC                               &&
+            CE_KnownImm (L[5])                                  &&
+            L[5]->Num == 1                                      &&
+            L[6]->OPC == OP65_BCC                               &&
+            L[6]->JumpTo != 0                                   &&
+            L[6]->JumpTo->Owner == L[8]                         &&
+            L[7]->OPC == OP65_INX                               &&
+            L[8]->OPC == OP65_STA                               &&
+            L[8]->AM == AM65_ZP                                 &&
+            strcmp (L[8]->Arg, L[0]->Arg) == 0                  &&
+            L[9]->OPC == OP65_STX                               &&
+            L[9]->AM == AM65_ZP                                 &&
+            strcmp (L[9]->Arg, L[1]->Arg) == 0                  &&
+            L[10]->OPC == OP65_LDA                              &&
+            L[10]->AM == AM65_ZP                                &&
+            strcmp (L[10]->Arg, "regsave") == 0                 &&
+            L[11]->OPC == OP65_LDX                              &&
+            L[11]->AM == AM65_ZP                                &&
+            strcmp (L[11]->Arg, "regsave+1") == 0               &&
+            L[12]->OPC == OP65_LDY                              &&
+            CE_KnownImm (L[12])                                 &&
+            CE_IsCallTo (L[13], "ldauidx")) {
+
+           CodeEntry* X;
+            CodeLabel* Label;
+
+            /* Check if the instruction following the sequence uses the flags
+             * set by the load. If so, insert a test of the value in the
+             * accumulator.
+             */
+            if (CE_UseLoadFlags (L[14])) {
+                X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI);
+                CS_InsertEntry (S, X, I+14);
+            }
+
+            /* Attach a label to L[14]. This may be either the just inserted
+             * instruction, or the one following the sequence.
+             */
+            Label = CS_GenLabel (S, L[14]);
+
+           /* ldy #$xx */
+           X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI);
+           CS_InsertEntry (S, X, I+14);
+
+           /* ldx #$xx */
+           X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI);
+           CS_InsertEntry (S, X, I+15);
+
+            /* lda (regbank+n),y */
+            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI);
+            CS_InsertEntry (S, X, I+16);
+
+            /* inc regbank+n */
+            X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI);
+            CS_InsertEntry (S, X, I+17);
+
+            /* bne ... */
+            X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI);
+            CS_InsertEntry (S, X, I+18);
+
+            /* inc regbank+n+1 */
+            X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI);
+            CS_InsertEntry (S, X, I+19);
+
+            /* Delete the old code */
+           CS_DelEntries (S, I, 14);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned OptPtrLoad6 (CodeSeg* S)
 /* Search for the sequence:
  *
  *      lda     zp
@@ -1115,7 +1311,7 @@ static unsigned OptPtrLoad5 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad6 (CodeSeg* S)
+static unsigned OptPtrLoad7 (CodeSeg* S)
 /* Search for the sequence:
  *
  *      lda     zp
@@ -1193,7 +1389,7 @@ static unsigned OptPtrLoad6 (CodeSeg* S)
 
 
 
-static unsigned OptPtrLoad7 (CodeSeg* S)
+static unsigned OptPtrLoad8 (CodeSeg* S)
 /* Search for the sequence
  *
  *      ldy     ...
@@ -1207,7 +1403,7 @@ static unsigned OptPtrLoad7 (CodeSeg* S)
  *      ldx     #$00
  *      lda     (ptr1),y
  *
- * This step must be execute *after* OptPtrLoad1!
+ * This step must be executed *after* OptPtrLoad1!
  */
 {
     unsigned Changes = 0;
@@ -1535,13 +1731,14 @@ static OptFunc DOptAdd4         = { OptAdd4,         "OptAdd4",         100, 0,
 static OptFunc DOptAdd5                = { OptAdd5,         "OptAdd5",          40, 0, 0, 0, 0, 0 };
 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptBranchDist          = { OptBranchDist,   "OptBranchDist",     0, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp1                = { OptCmp1,         "OptCmp1",          85, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp2                = { OptCmp2,         "OptCmp2",          75, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp1                = { OptCmp1,         "OptCmp1",          42, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp2                = { OptCmp2,         "OptCmp2",          85, 0, 0, 0, 0, 0 };
 static OptFunc DOptCmp3                = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",          75, 0, 0, 0, 0, 0 };
 static OptFunc DOptCmp5                = { OptCmp5,         "OptCmp5",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp6                = { OptCmp6,         "OptCmp6",          85, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp7                = { OptCmp7,         "OptCmp7",          50, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp6                = { OptCmp6,         "OptCmp6",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp7                = { OptCmp7,         "OptCmp7",          85, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp8                = { OptCmp8,         "OptCmp8",          50, 0, 0, 0, 0, 0 };
 static OptFunc DOptCondBranches        = { OptCondBranches, "OptCondBranches",  80, 0, 0, 0, 0, 0 };
 static OptFunc DOptDeadCode            = { OptDeadCode,     "OptDeadCode",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptDeadJumps           = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
@@ -1564,9 +1761,10 @@ static OptFunc DOptPtrLoad1      = { OptPtrLoad1,     "OptPtrLoad1",     100, 0,
 static OptFunc DOptPtrLoad2            = { OptPtrLoad2,     "OptPtrLoad2",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad3            = { OptPtrLoad3,     "OptPtrLoad3",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrLoad4            = { OptPtrLoad4,     "OptPtrLoad4",     100, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad5            = { OptPtrLoad5,     "OptPtrLoad5",      65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",      86, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad7            = { OptPtrLoad7,     "OptPtrLoad7",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad5            = { OptPtrLoad5,     "OptPtrLoad5",      50, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",      65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad7            = { OptPtrLoad7,     "OptPtrLoad7",      86, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad8            = { OptPtrLoad8,     "OptPtrLoad8",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",    100, 0, 0, 0, 0, 0 };
 static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",     40, 0, 0, 0, 0, 0 };
 static OptFunc DOptPush1               = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
@@ -1611,6 +1809,7 @@ static OptFunc* OptFuncs[] = {
     &DOptCmp5,
     &DOptCmp6,
     &DOptCmp7,
+    &DOptCmp8,
     &DOptCondBranches,
     &DOptDeadCode,
     &DOptDeadJumps,
@@ -1633,6 +1832,7 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrLoad5,
     &DOptPtrLoad6,
     &DOptPtrLoad7,
+    &DOptPtrLoad8,
     &DOptPtrStore1,
     &DOptPtrStore2,
     &DOptPush1,
@@ -1857,7 +2057,7 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
     /* Don't run the function if it is disabled or if it is prohibited by the
      * code size factor
      */
-    if (F->Disabled || F->CodeSizeFactor > CodeSizeFactor) {
+    if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
        return 0;
     }
 
@@ -1900,6 +2100,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad7, 1);
     Changes += RunOptFunc (S, &DOptNegAX1, 1);
     Changes += RunOptFunc (S, &DOptNegAX2, 1);
     Changes += RunOptFunc (S, &DOptNegAX3, 1);
@@ -1907,13 +2108,13 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptAdd1, 1);
     Changes += RunOptFunc (S, &DOptAdd2, 1);
     Changes += RunOptFunc (S, &DOptAdd3, 1);
+    Changes += RunOptFunc (S, &DOptStore4, 1);
     Changes += RunOptFunc (S, &DOptShift1, 1);
     Changes += RunOptFunc (S, &DOptShift2, 1);
     Changes += RunOptFunc (S, &DOptShift3, 1);
     Changes += RunOptFunc (S, &DOptStore1, 1);
     Changes += RunOptFunc (S, &DOptStore2, 5);
     Changes += RunOptFunc (S, &DOptStore3, 5);
-    Changes += RunOptFunc (S, &DOptStore4, 1);
 
     /* Return the number of changes */
     return Changes;
@@ -1950,7 +2151,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
     do {
                C = 0;
 
-               C += RunOptFunc (S, &DOptPtrLoad7, 1);
+               C += RunOptFunc (S, &DOptPtrLoad8, 1);
                C += RunOptFunc (S, &DOptNegA1, 1);
                C += RunOptFunc (S, &DOptNegA2, 1);
                C += RunOptFunc (S, &DOptSub1, 1);
@@ -1973,6 +2174,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
                C += RunOptFunc (S, &DOptCmp5, 1);
                C += RunOptFunc (S, &DOptCmp6, 1);
                C += RunOptFunc (S, &DOptCmp7, 1);
+               C += RunOptFunc (S, &DOptCmp8, 1);
                C += RunOptFunc (S, &DOptTest1, 1);
         C += RunOptFunc (S, &DOptLoad1, 1);
                C += RunOptFunc (S, &DOptUnusedLoads, 1);
@@ -1998,7 +2200,7 @@ static unsigned RunOptGroup4 (CodeSeg* S)
 {
     unsigned Changes = 0;
 
-    if (CPU >= CPU_65C02) {
+    if (CPUIsets[CPU] & CPU_ISET_65SC02) {
         Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
        Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
         Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
@@ -2042,7 +2244,7 @@ static unsigned RunOptGroup6 (CodeSeg* S)
     unsigned Changes = 0;
     unsigned C;
 
-    if (CodeSizeFactor <= 100) {
+    if (S->CodeSizeFactor <= 100) {
         /* Optimize for size, that is replace operations by shorter ones, even
          * if this does hinder further optimizations (no problem since we're
          * done soon).
@@ -2091,7 +2293,7 @@ void RunOpt (CodeSeg* S)
     const char* StatFileName;
 
     /* If we shouldn't run the optimizer, bail out */
-    if (!Optimize) {
+    if (!S->Optimize) {
        return;
     }