]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptshift.c
Fixed _textcolor definition.
[cc65] / src / cc65 / coptshift.c
index 6489ab1d32a2002654a3fff4f5694c0ed46d4d38..92210ebb5504d5d4eff7a83dd6eea0afe8827aa4 100644 (file)
@@ -128,10 +128,10 @@ enum {
 
 
 /* Macros to extract values from a shift type */
-#define SHIFT_COUNT(S)  ((S) & SHIFT_MASK_COUNT)
-#define SHIFT_DIR(S)    ((S) & SHIFT_MASK_DIR)
-#define SHIFT_MODE(S)   ((S) & SHIFT_MASK_MODE)
-#define SHIFT_TYPE(S)   ((S) & SHIFT_MASK_TYPE)
+#define SHIFT_COUNT(S)          ((S) & SHIFT_MASK_COUNT)
+#define SHIFT_DIR(S)            ((S) & SHIFT_MASK_DIR)
+#define SHIFT_MODE(S)           ((S) & SHIFT_MASK_MODE)
+#define SHIFT_TYPE(S)           ((S) & SHIFT_MASK_TYPE)
 
 
 
@@ -183,22 +183,21 @@ static unsigned GetShift (const char* Name)
 
 
 /*****************************************************************************/
-/*                             Optimize shifts                              */
+/*                              Optimize shifts                              */
 /*****************************************************************************/
 
 
 
 unsigned OptShift1 (CodeSeg* S)
 /* A call to the shlaxN routine may get replaced by one or more asl insns
- * if the value of X is not used later. If X is used later, but it is zero
- * on entry and it's a shift by one, it may get replaced by:
- *
- *      asl     a
- *      bcc     L1
- *      inx
- *  L1:
- *
- */
+** if the value of X is not used later. If X is used later, but it is zero
+** on entry and it's a shift by one, it may get replaced by:
+**
+**      asl     a
+**      bcc     L1
+**      inx
+**  L1:
+*/
 {
     unsigned Changes = 0;
     unsigned I;
@@ -208,33 +207,62 @@ unsigned OptShift1 (CodeSeg* S)
     while (I < CS_GetEntryCount (S)) {
 
         unsigned   Shift;
-        unsigned   Count;
         CodeEntry* N;
         CodeEntry* X;
         CodeLabel* L;
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                          &&
+        /* Check for the sequence */
+        if (E->OPC == OP65_JSR                          &&
             (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
-            SHIFT_DIR (Shift) == SHIFT_DIR_LEFT         &&
-            (Count = SHIFT_COUNT (Shift)) > 0) {
+            SHIFT_DIR (Shift) == SHIFT_DIR_LEFT) {
+
 
+            unsigned Count = SHIFT_COUNT (Shift);
             if (!RegXUsed (S, I+1)) {
 
-                /* Insert shift insns */
-                while (Count--) {
+                if (Count == SHIFT_COUNT_Y) {
+
+                    CodeLabel* L;
+
+                    if (S->CodeSizeFactor < 200) {
+                        goto NextEntry;
+                    }
+
+                    /* Change into
+                    **
+                    ** L1:  asl     a
+                    **      dey
+                    **      bpl     L1
+                    **      ror     a
+                    */
+
+                    /* asl a */
                     X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
                     CS_InsertEntry (S, X, I+1);
-                }
+                    L = CS_GenLabel (S, X);
 
-                /* Delete the call to shlax */
-                CS_DelEntry (S, I);
+                    /* dey */
+                    X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
+                    CS_InsertEntry (S, X, I+2);
 
-                /* Remember, we had changes */
-                ++Changes;
+                    /* bpl L1 */
+                    X = NewCodeEntry (OP65_BPL, AM65_BRA, L->Name, L, E->LI);
+                    CS_InsertEntry (S, X, I+3);
+
+                    /* ror a */
+                    X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI);
+                    CS_InsertEntry (S, X, I+4);
+
+                } else {
+                    /* Insert shift insns */
+                    while (Count--) {
+                        X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
+                        CS_InsertEntry (S, X, I+1);
+                    }
+                }
 
             } else if (E->RI->In.RegX == 0              &&
                        Count == 1                       &&
@@ -253,17 +281,23 @@ unsigned OptShift1 (CodeSeg* S)
                 X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
                 CS_InsertEntry (S, X, I+3);
 
-                /* Delete the call to shlax */
-                CS_DelEntry (S, I);
+            } else {
+
+                /* We won't handle this one */
+                goto NextEntry;
 
-                /* Remember, we had changes */
-                ++Changes;
             }
 
-       }
+            /* Delete the call to shlax */
+            CS_DelEntry (S, I);
 
-       /* Next entry */
-       ++I;
+            /* Remember, we had changes */
+            ++Changes;
+        }
+
+NextEntry:
+        /* Next entry */
+        ++I;
 
     }
 
@@ -273,60 +307,87 @@ unsigned OptShift1 (CodeSeg* S)
 
 
 
-unsigned OptShift2(CodeSeg* S)
-/* A call to the asrax1 routines may get replaced by something simpler, if
- * X is not used later:
- *
- *      cmp     #$80
- *      ror     a
- *
- */
+unsigned OptShift2 (CodeSeg* S)
+/* The sequence
+**
+**      bpl     L
+**      dex
+** L:   jsr     asraxN
+**
+** might be replaced by N copies of
+**
+**      cmp     #$80
+**      ror     a
+**
+** if X is not used later (X is assumed to be zero on entry).
+** If the sequence is followed immediately by another
+**
+**      jsr     asraxN
+**
+** then their shifts are combined.
+*/
 {
     unsigned Changes = 0;
-    unsigned I;
+    unsigned I = 0;
 
     /* Walk over the entries */
-    I = 0;
     while (I < CS_GetEntryCount (S)) {
-
         unsigned Shift;
-        unsigned Count;
-
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        unsigned Count, Count2;
+        unsigned K;
+        CodeEntry* L[4];
+
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
+
+        /* Check for the sequence */
+        if ((L[0]->OPC == OP65_BPL || L[0]->OPC == OP65_BCC)            &&
+            L[0]->JumpTo != 0                                           &&
+            CS_GetEntries (S, L+1, I+1, 3)                              &&
+            L[1]->OPC == OP65_DEX                                       &&
+            L[0]->JumpTo->Owner == L[2]                                 &&
+            !CS_RangeHasLabel (S, I, 2)                                 &&
+            L[2]->OPC == OP65_JSR                                       &&
+            SHIFT_TYPE (Shift = GetShift (L[2]->Arg)) == SHIFT_TYPE_ASR &&
+            (Count = SHIFT_COUNT (Shift)) > 0) {
 
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                          &&
-            (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
-            SHIFT_TYPE (Shift) == SHIFT_TYPE_ASR        &&
-            (Count = SHIFT_COUNT (Shift)) > 0           &&
-            Count * 100 <= S->CodeSizeFactor    &&
-            !RegXUsed (S, I+1)) {
+            if (L[3]->OPC == OP65_JSR                                           &&
+                SHIFT_TYPE (Shift = GetShift (L[3]->Arg)) == SHIFT_TYPE_ASR     &&
+                (Count2 = SHIFT_COUNT (Shift)) > 0) {
 
-            CodeEntry* X;
-            unsigned J = I+1;
+                /* Found a second jsr asraxN */
+                Count += Count2;
+                K = 4;
+            } else {
+                K = 3;
+            }
+            if (Count * 100 <= S->CodeSizeFactor        &&
+                !RegXUsed (S, I+K)) {
 
-            /* Generate the replacement sequence */
-            while (Count--) {
-                /* cmp #$80 */
-                X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, E->LI);
-                CS_InsertEntry (S, X, J++);
+                CodeEntry* X;
+                unsigned J = I+K;
 
-                /* ror a */
-                X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI);
-                CS_InsertEntry (S, X, J++);
-            }
+                /* Generate the replacement sequence */
+                do {
+                    /* cmp #$80 */
+                    X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, J++);
 
-            /* Delete the call to asrax */
-            CS_DelEntry (S, I);
+                    /* ror a */
+                    X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
+                    CS_InsertEntry (S, X, J++);
+                } while (--Count);
 
-            /* Remember, we had changes */
-            ++Changes;
-       }
+                /* Remove the bpl/dex/jsr */
+                CS_DelEntries (S, I, K);
 
-       /* Next entry */
-       ++I;
+                /* Remember, we had changes */
+                ++Changes;
+            }
+        }
 
+        /* Next entry */
+        ++I;
     }
 
     /* Return the number of changes made */
@@ -337,21 +398,21 @@ unsigned OptShift2(CodeSeg* S)
 
 unsigned OptShift3 (CodeSeg* S)
 /* The sequence
- *
- *      bcc     L
- *     inx
- * L:   jsr     shrax1
- *
- * may get replaced by
- *
- *      ror     a
- *
- * if X is zero on entry and unused later. For shift counts > 1, more
- *
- *      shr     a
- *
- * must be added.
- */
+**
+**      bcc     L
+**      inx
+** L:   jsr     shrax1
+**
+** may get replaced by
+**
+**      ror     a
+**
+** if X is zero on entry. For shift counts > 1, more
+**
+**      shr     a
+**
+** must be added.
+*/
 {
     unsigned Changes = 0;
     unsigned I;
@@ -362,24 +423,23 @@ unsigned OptShift3 (CodeSeg* S)
 
         unsigned   Shift;
         unsigned   Count;
-       CodeEntry* L[3];
+        CodeEntry* L[3];
 
-       /* Get next entry */
-               L[0] = CS_GetEntry (S, I);
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-               if ((L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC)    &&
-           L[0]->JumpTo != 0                                   &&
+        /* Check for the sequence */
+        if ((L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC)    &&
+            L[0]->JumpTo != 0                                   &&
             L[0]->RI->In.RegX == 0                              &&
-                   CS_GetEntries (S, L+1, I+1, 2)                      &&
-           L[1]->OPC == OP65_INX                               &&
-           L[0]->JumpTo->Owner == L[2]                         &&
-           !CS_RangeHasLabel (S, I, 2)                         &&
+            CS_GetEntries (S, L+1, I+1, 2)                      &&
+            L[1]->OPC == OP65_INX                               &&
+            L[0]->JumpTo->Owner == L[2]                         &&
+            !CS_RangeHasLabel (S, I, 2)                         &&
             L[2]->OPC == OP65_JSR                               &&
             (Shift = GetShift (L[2]->Arg)) != SHIFT_NONE        &&
-            SHIFT_TYPE (Shift) == SHIFT_TYPE_ASR                &&
-            (Count = SHIFT_COUNT (Shift)) > 0                   &&
-           !RegXUsed (S, I+3)) {
+            SHIFT_DIR (Shift) == SHIFT_DIR_RIGHT                &&
+            (Count = SHIFT_COUNT (Shift)) > 0) {
 
             /* Add the replacement insn instead */
             CodeEntry* X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
@@ -389,16 +449,16 @@ unsigned OptShift3 (CodeSeg* S)
                 CS_InsertEntry (S, X, I+4);
             }
 
-           /* Remove the bcs/dex/jsr */
-           CS_DelEntries (S, I, 3);
+            /* Remove the bcc/inx/jsr */
+            CS_DelEntries (S, I, 3);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -410,8 +470,8 @@ unsigned OptShift3 (CodeSeg* S)
 
 unsigned OptShift4 (CodeSeg* S)
 /* Calls to the asraxN or shraxN routines may get replaced by one or more lsr
- * insns if the value of X is zero.
- */
+** insns if the value of X is zero.
+*/
 {
     unsigned Changes = 0;
     unsigned I;
@@ -423,14 +483,14 @@ unsigned OptShift4 (CodeSeg* S)
         unsigned Shift;
         unsigned Count;
 
-       /* Get next entry */
-               CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-       if (E->OPC == OP65_JSR                          &&
+        /* Check for the sequence */
+        if (E->OPC == OP65_JSR                          &&
             (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
             SHIFT_DIR (Shift) == SHIFT_DIR_RIGHT        &&
-                   E->RI->In.RegX == 0) {
+            E->RI->In.RegX == 0) {
 
             CodeEntry* X;
 
@@ -438,15 +498,26 @@ unsigned OptShift4 (CodeSeg* S)
             Count = SHIFT_COUNT (Shift);
             if (Count == SHIFT_COUNT_Y) {
 
-                /* Generate:
-                 *
-                 * L1: lsr     a
-                 *     dey
-                 *     bpl     L1
-                 *     rol     a
-                 */
                 CodeLabel* L;
 
+                if (S->CodeSizeFactor < 200) {
+                    /* Not acceptable */
+                    goto NextEntry;
+                }
+
+                /* Generate:
+                **
+                ** L1: lsr     a
+                **     dey
+                **     bpl     L1
+                **     rol     a
+                **
+                ** A negative shift count or one that is greater or equal than
+                ** the bit width of the left operand (which is promoted to
+                ** integer before the operation) causes undefined behaviour, so
+                ** above transformation is safe.
+                */
+
                 /* lsr a */
                 X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI);
                 CS_InsertEntry (S, X, I+1);
@@ -473,16 +544,17 @@ unsigned OptShift4 (CodeSeg* S)
 
             }
 
-           /* Delete the call to shrax */
-           CS_DelEntry (S, I);
+            /* Delete the call to shrax */
+            CS_DelEntry (S, I);
 
-           /* Remember, we had changes */
-           ++Changes;
+            /* Remember, we had changes */
+            ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+NextEntry:
+        /* Next entry */
+        ++I;
 
     }
 
@@ -494,24 +566,24 @@ unsigned OptShift4 (CodeSeg* S)
 
 unsigned OptShift5 (CodeSeg* S)
 /* Search for the sequence
- *
- *      lda     xxx
- *      ldx     yyy
- *      jsr     aslax1/asrax1/shlax1/shrax1
- *      sta     aaa
- *      stx     bbb
- *
- * and replace it by
- *
- *      lda     xxx
- *      asl     a
- *      sta     aaa
- *      lda     yyy
- *      rol     a
- *      sta     bbb
- *
- * or similar, provided that a/x is not used later
- */
+**
+**      lda     xxx
+**      ldx     yyy
+**      jsr     aslax1/asrax1/shlax1/shrax1
+**      sta     aaa
+**      stx     bbb
+**
+** and replace it by
+**
+**      lda     xxx
+**      asl     a
+**      sta     aaa
+**      lda     yyy
+**      rol     a
+**      sta     bbb
+**
+** or similar, provided that a/x is not used later
+*/
 {
     unsigned Changes = 0;
 
@@ -520,22 +592,22 @@ unsigned OptShift5 (CodeSeg* S)
     while (I < CS_GetEntryCount (S)) {
 
         unsigned ShiftType;
-       CodeEntry* L[5];
+        CodeEntry* L[5];
 
-       /* Get next entry */
-               L[0] = CS_GetEntry (S, I);
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-               if (L[0]->OPC == OP65_LDA                               &&
+        /* Check for the sequence */
+        if (L[0]->OPC == OP65_LDA                               &&
             (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP)       &&
-                   CS_GetEntries (S, L+1, I+1, 4)                      &&
+            CS_GetEntries (S, L+1, I+1, 4)                      &&
             !CS_RangeHasLabel (S, I+1, 4)                       &&
             L[1]->OPC == OP65_LDX                               &&
             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP)       &&
             L[2]->OPC == OP65_JSR                               &&
             (ShiftType = GetShift (L[2]->Arg)) != SHIFT_NONE    &&
             SHIFT_COUNT(ShiftType) == 1                         &&
-                   L[3]->OPC == OP65_STA                               &&
+            L[3]->OPC == OP65_STA                               &&
             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)       &&
             L[4]->OPC == OP65_STX                               &&
             (L[4]->AM == AM65_ABS || L[4]->AM == AM65_ZP)       &&
@@ -598,13 +670,13 @@ unsigned OptShift5 (CodeSeg* S)
 
             }
 
-           /* Remember, we had changes */
+            /* Remember, we had changes */
             ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -628,29 +700,29 @@ unsigned OptShift6 (CodeSeg* S)
         CodeEntry* X;
         unsigned   IP;
 
-       /* Get next entry */
-       CodeEntry* E = CS_GetEntry (S, I);
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
 
-       /* Check for a call to one of the shift routine */
-       if (E->OPC == OP65_JSR                          &&
+        /* Check for a call to one of the shift routine */
+        if (E->OPC == OP65_JSR                          &&
             (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
             SHIFT_DIR (Shift) == SHIFT_DIR_LEFT         &&
             (Count = SHIFT_COUNT (Shift)) > 0) {
 
             /* Code is:
-             *
-             *      stx     tmp1
-             *      asl     a
-             *      rol     tmp1
-             *      (repeat ShiftCount-1 times)
-             *      ldx     tmp1
-             *
-             * which makes 4 + 3 * ShiftCount bytes, compared to the original
-             * 3 bytes for the subroutine call. However, in most cases, the
-             * final load of the X register gets merged with some other insn
-             * and replaces a txa, so for a shift count of 1, we get a factor
-             * of 200, which matches nicely the CodeSizeFactor enabled with -Oi
-             */
+            **
+            **      stx     tmp1
+            **      asl     a
+            **      rol     tmp1
+            **      (repeat ShiftCount-1 times)
+            **      ldx     tmp1
+            **
+            ** which makes 4 + 3 * ShiftCount bytes, compared to the original
+            ** 3 bytes for the subroutine call. However, in most cases, the
+            ** final load of the X register gets merged with some other insn
+            ** and replaces a txa, so for a shift count of 1, we get a factor
+            ** of 200, which matches nicely the CodeSizeFactor enabled with -Oi
+            */
             if (Count > 1 || S->CodeSizeFactor > 200) {
                 unsigned Size = 4 + 3 * Count;
                 if ((Size * 100 / 3) > S->CodeSizeFactor) {
@@ -683,19 +755,16 @@ unsigned OptShift6 (CodeSeg* S)
             /* Remove the subroutine call */
             CS_DelEntry (S, I);
 
-           /* Remember, we had changes */
+            /* Remember, we had changes */
             ++Changes;
-       }
+        }
 
 NextEntry:
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
     /* Return the number of changes made */
     return Changes;
 }
-
-
-