]> git.sur5r.net Git - cc65/commitdiff
Moved some of the currently existing into a separate module.
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Mon, 14 May 2001 17:35:53 +0000 (17:35 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Mon, 14 May 2001 17:35:53 +0000 (17:35 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@723 b7a2c559-68d2-44c3-8de9-860c34a00d81

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

index 81273b01396196ef79d500396e21f7c545f98169..898ce17fb5a6f89b8fc65b8e09bc2788055cb2ca 100644 (file)
@@ -3466,6 +3466,14 @@ void g_lt (unsigned flags, unsigned long val)
                break;
 
            case CF_LONG:
+               if ((flags & CF_UNSIGNED) == 0 && val == 0) {
+                   /* If we have a signed compare against zero, we only need to
+                    * test the high byte.
+                    */
+                   AddCodeLine ("lda sreg+1");
+                   AddCodeLine ("jsr boollt");
+                   return;
+               }
                break;
 
            default:
@@ -3475,7 +3483,7 @@ void g_lt (unsigned flags, unsigned long val)
        /* If we go here, we didn't emit code. Push the lhs on stack and fall
         * into the normal, non-optimized stuff.
         */
-       g_push (flags & ~CF_CONST, 0);
+       g_push (flags & ~CF_CONST, 0);      
 
     }
 
@@ -3589,27 +3597,27 @@ void g_gt (unsigned flags, unsigned long val)
                if (flags & CF_UNSIGNED) {
                    /* If we have a compare > 0, we will replace it by
                     * != 0 here, since both are identical but the latter
-                    * is easier to optimize.
-                    */
-                   if ((val & 0xFFFF) == 0) {
-                       AddCodeLine ("stx tmp1");
-                       AddCodeLine ("ora tmp1");
-                       AddCodeLine ("jsr boolne");
-                   } else {
+                    * is easier to optimize.
+                    */
+                   if ((val & 0xFFFF) == 0) {
+                       AddCodeLine ("stx tmp1");
+                       AddCodeLine ("ora tmp1");
+                       AddCodeLine ("jsr boolne");
+                   } else {
                                AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
-                       AddCodeLine ("bne *+4");
-                       AddCodeLine ("cmp #$%02X", (unsigned char)val);
+                       AddCodeLine ("bne *+4");
+                       AddCodeLine ("cmp #$%02X", (unsigned char)val);
                                AddCodeLine ("jsr boolugt");
-                   }
-                   return;
+                   }
+                   return;
                        }
-               break;
+               break;
 
            case CF_LONG:
-               break;
+               break;
 
            default:
-               typeerror (flags);
+               typeerror (flags);
        }
 
        /* If we go here, we didn't emit code. Push the lhs on stack and fall
@@ -3662,20 +3670,37 @@ void g_ge (unsigned flags, unsigned long val)
                /* FALLTHROUGH */
 
            case CF_INT:
+               if ((flags & CF_UNSIGNED) == 0 && val == 0) {
+                   /* If we have a signed compare against zero, we only need to
+                    * test the high byte.
+                    */
+                   AddCodeLine ("txa");
+                   AddCodeLine ("jsr boolge");
+                   return;
+               }
+               /* Direct code only for unsigned data types */
                if (flags & CF_UNSIGNED) {
                            AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
                            AddCodeLine ("bne *+4");
                    AddCodeLine ("cmp #$%02X", (unsigned char)val);
                    AddCodeLine ("jsr booluge");
                    return;
-               }
+               }
                break;
 
            case CF_LONG:
-               break;
+               if ((flags & CF_UNSIGNED) == 0 && val == 0) {
+                   /* If we have a signed compare against zero, we only need to
+                    * test the high byte.
+                    */
+                   AddCodeLine ("lda sreg+1");
+                   AddCodeLine ("jsr boolge");
+                   return;
+               }
+               break;
 
            default:
-               typeerror (flags);
+               typeerror (flags);
        }
 
        /* If we go here, we didn't emit code. Push the lhs on stack and fall
index b52212dbbd9ebda5b96bd8b4dfd72b32b0684d03..c97cfa06fe0d7af38110e7e7675d590da924d881 100644 (file)
@@ -43,6 +43,7 @@
 #include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
+#include "coptind.h"
 #include "error.h"
 #include "global.h"
 #include "codeopt.h"
 
 
 
-/* Counter for the number of changes in one run. The optimizer process is
- * repeated until there are no more changes.
- */
-static unsigned OptChanges;
-
 /* Defines for the conditions in a compare */
 typedef enum {
     CMP_INV = -1,
@@ -119,434 +115,24 @@ static cmp_t FindCmpCond (const char* Suffix)
 
 
 
-/*****************************************************************************/
-/*                            Remove dead jumps                             */
-/*****************************************************************************/
-
-
-
-static void OptDeadJumps (CodeSeg* S)
-/* Remove dead jumps (jumps to the next instruction) */
-{
-    CodeEntry* E;
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have less than two entries */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count < 2) {
-       return;
-    }
-
-    /* Walk over all entries minus the last one */
-    I = 0;
-    while (I < Count-1) {
-
-       /* Get the next entry */
-       E = GetCodeEntry (S, I);
-
-       /* Check if it's a branch, if it has a local target, and if the target
-        * is the next instruction.
-        */
-       if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
-
-           /* Delete the dead jump */
-           DelCodeEntry (S, I);
-
-           /* Keep the number of entries updated */
-           --Count;
-
-           /* Remember, we had changes */
-           ++OptChanges;
-
-       } else {
-
-           /* Next entry */
-           ++I;
-
-       }
-    }
-}
-
-
-
-/*****************************************************************************/
-/*                            Remove dead code                              */
-/*****************************************************************************/
-
-
-
-static void OptDeadCode (CodeSeg* S)
-/* Remove dead code (code that follows an unconditional jump or an rts/rti
- * and has no label)
- */
-{
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have less than two entries */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count < 2) {
-       return;
-    }
-
-    /* Walk over all entries minus the last one */
-    I = 0;
-    while (I < Count-1) {
-
-       /* Get this entry */
-       CodeEntry* E = GetCodeEntry (S, I);
-
-               /* Check if it's an unconditional branch, and if the next entry has
-        * no labels attached
-        */
-               if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
-
-           /* Delete the next entry */
-           DelCodeEntry (S, I+1);
-
-           /* Keep the number of entries updated */
-           --Count;
-
-           /* Remember, we had changes */
-           ++OptChanges;
-
-       } else {
-
-           /* Next entry */
-           ++I;
-
-       }
-    }
-}
-
-
-
-/*****************************************************************************/
-/*                         Optimize jump cascades                           */
-/*****************************************************************************/
-
-
-
-static void OptJumpCascades (CodeSeg* S)
-/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
- * replaced by a jump to the final location. This will in some cases produce
- * worse code, because some jump targets are no longer reachable by short
- * branches, but this is quite rare, so there are more advantages than
- * disadvantages.
- */
-{
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have no entries */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count == 0) {
-       return;
-    }
-
-    /* Walk over all entries */
-    I = 0;
-    while (I < Count) {
-
-       /* Get this entry */
-       CodeEntry* E = GetCodeEntry (S, I);
-
-               /* Check if it's a branch, if it has a jump label, and if this jump
-        * label is not attached to the instruction itself.
-        */
-       if ((E->Info & OF_BRA) != 0 && E->JumpTo != 0 && E->JumpTo->Owner != E) {
-
-           /* Get the label this insn is branching to */
-           CodeLabel* OldLabel = E->JumpTo;
-
-           /* Get the entry we're branching to */
-           CodeEntry* N = OldLabel->Owner;
-
-           /* If the entry we're branching to is not itself a branch, it is
-            * not what we're searching for.
-            */
-           if ((N->Info & OF_BRA) == 0) {
-               goto NextEntry;
-           }
-
-           /* Check if we can use the final target label. This is the case,
-            * if the target branch is an absolut branch, or if it is a
-            * conditional branch checking the same condition as the first one.
-            */
-           if ((N->Info & OF_UBRA) != 0 ||
-                       ((E->Info & OF_CBRA) != 0 &&
-                GetBranchCond (E->OPC)  == GetBranchCond (N->OPC))) {
-
-               /* This is a jump cascade and we may jump to the final target.
-                * If we have a label, move the reference to this label. If
-                * we don't have a label, use the argument instead.
-                */
-               if (N->JumpTo) {
-                   /* Move the reference to the new insn */
-                   MoveCodeLabelRef (S, E, N->JumpTo);
-               } else {
-                   /* Remove the reference to the old label */
-                   RemoveCodeLabelRef (S, E);
-               }
-
-               /* Use the new argument */
-               CodeEntrySetArg (E, N->Arg);
-
-               /* Use the usage information from the new instruction */
-               E->Use = N->Use;
-               E->Chg = N->Chg;
-
-               /* Remember, we had changes */
-               ++OptChanges;
-
-               /* Done */
-               continue;
-
-           }
-
-           /* Check if both are conditional branches, and the condition of
-            * the second is the inverse of that of the first. In this case,
-            * the second branch will never be taken, and we may jump directly
-            * to the instruction behind this one.
-            */
-           goto NextEntry;
-
-       }
-
-NextEntry:
-       /* Next entry */
-       ++I;
-
-    }
-}
-
-
-
-/*****************************************************************************/
-/*                            Optimize jsr/rts                              */
-/*****************************************************************************/
-
-
-
-static void OptRTS (CodeSeg* S)
-/* Optimize subroutine calls followed by an RTS. The subroutine call will get
- * replaced by a jump. Don't bother to delete the RTS if it does not have a
- * label, the dead code elimination should take care of it.
- */
-{
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have less than 2 entries */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count < 2) {
-       return;
-    }
-
-    /* Walk over all entries minus the last one */
-    I = 0;
-    while (I < Count-1) {
-
-       /* Get this entry */
-       CodeEntry* E = GetCodeEntry (S, I);
-
-       /* Check if it's a subroutine call and if the following insn is RTS */
-       if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
-
-           /* Change the jsr to a jmp and use the additional info for a jump */
-           E->OPC  = OPC_JMP;
-           E->AM   = AM_BRA;
-           E->Info = GetOPCInfo (OPC_JMP);
-
-                   /* Remember, we had changes */
-           ++OptChanges;
-
-       }
-
-       /* Next entry */
-       ++I;
-
-    }
-}
-
-
-
-/*****************************************************************************/
-/*                          Optimize jump targets                           */
-/*****************************************************************************/
-
-
-
-static void OptJumpTarget (CodeSeg* S)
-/* If the instruction preceeding an unconditional branch is the same as the
- * instruction preceeding the jump target, the jump target may be moved
- * one entry back. This is a size optimization, since the instruction before
- * the branch gets removed.
- */
-{
-    CodeEntry* E1;     /* Entry 1 */
-    CodeEntry* E2;     /* Entry 2 */
-    CodeEntry* T1;     /* Jump target entry 1 */
-    CodeEntry* T2;     /* Jump target entry 2 */
-    CodeLabel* TL1;    /* Target label 1 */
-    unsigned TI;       /* Target index */
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have not enough */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count < 3) {
-       return;
-    }
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < Count-1) {
-
-       /* Get next entry */
-               E2 = GetCodeEntry (S, I+1);
-
-       /* Check if we have a jump or branch, and a matching label */
-               if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
-
-           /* Get the target instruction for the label */
-           T2 = E2->JumpTo->Owner;
-
-           /* Get the entry preceeding this one (if possible) */
-           TI = GetCodeEntryIndex (S, T2);
-           if (TI == 0) {
-               /* There is no entry before this one */
-               goto NextEntry;
-           }
-           T1 = GetCodeEntry (S, TI-1);
-
-           /* Get the entry preceeding the jump */
-           E1 = GetCodeEntry (S, I);
-
-           /* Check if both preceeding instructions are identical */
-           if (!CodeEntriesAreEqual (E1, T1)) {
-               /* Not equal, try next */
-               goto NextEntry;
-           }
-
-           /* Get the label for the instruction preceeding the jump target.
-            * This routine will create a new label if the instruction does
-            * not already have one.
-            */
-           TL1 = GenCodeLabel (S, T1);
-
-           /* Change the jump target to point to this new label */
-           MoveCodeLabelRef (S, E2, TL1);
-
-           /* If the instruction preceeding the jump has labels attached,
-            * move references to this label to the new label.
-            */
-           if (CodeEntryHasLabel (E1)) {
-               MoveCodeLabels (S, E1, T1);
-           }
-
-           /* Remove the entry preceeding the jump */
-           DelCodeEntry (S, I);
-           --Count;
-
-                   /* Remember, we had changes */
-           ++OptChanges;
-
-       }
-
-NextEntry:
-       /* Next entry */
-       ++I;
-
-    }
-}
-
-
-
-/*****************************************************************************/
-/*                  Remove conditional jumps never taken                    */
-/*****************************************************************************/
-
-
-
-static void OptDeadCondBranches (CodeSeg* S)
-/* If an immidiate load of a register is followed by a conditional jump that
- * is never taken because the load of the register sets the flags in such a
- * manner, remove the conditional branch.
- */
-{
-    unsigned I;
-
-    /* Get the number of entries, bail out if we have not enough */
-    unsigned Count = GetCodeEntryCount (S);
-    if (Count < 2) {
-       return;
-    }
-
-    /* Walk over the entries */
-    I = 0;
-    while (I < Count-1) {
-
-       /* Get next entry */
-               CodeEntry* E = GetCodeEntry (S, I);
-
-       /* Check if it's a register load */
-               if ((E->Info & OF_LOAD) != 0 && E->AM == AM_IMM && (E->Flags & CEF_NUMARG) != 0) {
-
-           bc_t BC;
-
-           /* Immidiate register load, get next instruction */
-           CodeEntry* N = GetCodeEntry (S, I+1);
-
-           /* Check if the following insn is a conditional branch or if it
-            * has a label attached.
-            */
-           if ((N->Info & OF_CBRA) == 0 || CodeEntryHasLabel (E)) {
-               /* No conditional jump or label attached, bail out */
-               goto NextEntry;
-           }
-
-           /* Get the branch condition */
-           BC = GetBranchCond (N->OPC);
-
-           /* Check the argument against the branch condition */
-                   if ((BC == BC_EQ && E->Num != 0)            ||
-               (BC == BC_NE && E->Num == 0)            ||
-               (BC == BC_PL && (E->Num & 0x80) != 0)   ||
-               (BC == BC_MI && (E->Num & 0x80) == 0)) {
-
-               /* Remove the conditional branch */
-               DelCodeEntry (S, I+1);
-               --Count;
-
-               /* Remember, we had changes */
-               ++OptChanges;
-
-           }
-       }
-
-NextEntry:
-       /* Next entry */
-       ++I;
-
-    }
-}
-
-
-
 /*****************************************************************************/
 /*            Remove calls to the bool transformer subroutines              */
 /*****************************************************************************/
 
 
 
-static void OptBoolTransforms (CodeSeg* S)
+static unsigned OptBoolTransforms (CodeSeg* S)
 /* Try to remove the call to boolean transformer routines where the call is
  * not really needed.
  */
 {
+    unsigned Changes = 0;
     unsigned I;
 
     /* Get the number of entries, bail out if we have not enough */
     unsigned Count = GetCodeEntryCount (S);
     if (Count < 2) {
-       return;
+       return 0;
     }
 
     /* Walk over the entries */
@@ -640,7 +226,7 @@ static void OptBoolTransforms (CodeSeg* S)
            --Count;
 
            /* Remember, we had changes */
-           ++OptChanges;
+           ++Changes;
 
        }
 
@@ -649,6 +235,9 @@ NextEntry:
        ++I;
 
     }
+
+    /* Return the number of changes made */
+    return Changes;
 }
 
 
@@ -662,7 +251,7 @@ NextEntry:
 /* Table with all the optimization functions */
 typedef struct OptFunc OptFunc;
 struct OptFunc {
-    void (*Func) (CodeSeg*);   /* Optimizer function */
+    unsigned (*Func) (CodeSeg*);/* Optimizer function */
     const char*        Name;           /* Name of optimizer step */
     char       Disabled;       /* True if pass disabled */
 };
@@ -691,7 +280,7 @@ static OptFunc OptFuncs [] = {
 
 static OptFunc* FindOptStep (const char* Name)
 /* Find an optimizer step by name in the table and return a pointer. Print an
- * error and cann AbEnd if not found.
+ * error and call AbEnd if not found.
  */
 {
     unsigned I;
@@ -732,7 +321,9 @@ void EnableOpt (const char* Name)
 void RunOpt (CodeSeg* S)
 /* Run the optimizer */
 {
+    unsigned I;
     unsigned Pass = 0;
+    unsigned OptChanges;
 
     /* Print the name of the function we are working on */
     if (S->Func) {
@@ -743,9 +334,6 @@ void RunOpt (CodeSeg* S)
 
     /* Repeat all steps until there are no more changes */
     do {
-
-               unsigned I;
-
        /* Reset the number of changes */
        OptChanges = 0;
 
@@ -763,9 +351,8 @@ void RunOpt (CodeSeg* S)
                    if (OptFuncs[I].Disabled) {
                Print (stdout, 1, "Disabled\n");
            } else {
-               unsigned Changes = OptChanges;
-               OptFuncs[I].Func (S);
-               Changes = OptChanges - Changes;
+               unsigned Changes = OptFuncs[I].Func (S);
+               OptChanges += Changes;
                Print (stdout, 1, "%u Changes\n", Changes);
            }
        }
diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c
new file mode 100644 (file)
index 0000000..f01546d
--- /dev/null
@@ -0,0 +1,481 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptind.c                                 */
+/*                                                                           */
+/*             Environment independent low level optimizations              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (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 "coptind.h"
+
+
+
+/*****************************************************************************/
+/*                            Remove dead jumps                             */
+/*****************************************************************************/
+
+
+
+unsigned OptDeadJumps (CodeSeg* S)
+/* Remove dead jumps (jumps to the next instruction) */
+{
+    unsigned Changes = 0;
+    CodeEntry* E;
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have less than two entries */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count < 2) {
+       return 0;
+    }
+
+    /* Walk over all entries minus the last one */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get the next entry */
+       E = GetCodeEntry (S, I);
+
+       /* Check if it's a branch, if it has a local target, and if the target
+        * is the next instruction.
+        */
+       if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
+
+           /* Delete the dead jump */
+           DelCodeEntry (S, I);
+
+           /* Keep the number of entries updated */
+           --Count;
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       } else {
+
+           /* Next entry */
+           ++I;
+
+       }
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                            Remove dead code                              */
+/*****************************************************************************/
+
+
+
+unsigned OptDeadCode (CodeSeg* S)
+/* Remove dead code (code that follows an unconditional jump or an rts/rti
+ * and has no label)
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have less than two entries */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count < 2) {
+       return 0;
+    }
+
+    /* Walk over all entries minus the last one */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get this entry */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+               /* Check if it's an unconditional branch, and if the next entry has
+        * no labels attached
+        */
+               if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
+
+           /* Delete the next entry */
+           DelCodeEntry (S, I+1);
+
+           /* Keep the number of entries updated */
+           --Count;
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       } else {
+
+           /* Next entry */
+           ++I;
+
+       }
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                         Optimize jump cascades                           */
+/*****************************************************************************/
+
+
+
+unsigned OptJumpCascades (CodeSeg* S)
+/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
+ * replaced by a jump to the final location. This will in some cases produce
+ * worse code, because some jump targets are no longer reachable by short
+ * branches, but this is quite rare, so there are more advantages than
+ * disadvantages.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have no entries */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count == 0) {
+       return 0;
+    }
+
+    /* Walk over all entries */
+    I = 0;
+    while (I < Count) {
+
+       /* Get this entry */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+               /* Check if it's a branch, if it has a jump label, and if this jump
+        * label is not attached to the instruction itself.
+        */
+       if ((E->Info & OF_BRA) != 0 && E->JumpTo != 0 && E->JumpTo->Owner != E) {
+
+           /* Get the label this insn is branching to */
+           CodeLabel* OldLabel = E->JumpTo;
+
+           /* Get the entry we're branching to */
+           CodeEntry* N = OldLabel->Owner;
+
+           /* If the entry we're branching to is not itself a branch, it is
+            * not what we're searching for.
+            */
+           if ((N->Info & OF_BRA) == 0) {
+               goto NextEntry;
+           }
+
+           /* Check if we can use the final target label. This is the case,
+            * if the target branch is an absolut branch, or if it is a
+            * conditional branch checking the same condition as the first one.
+            */
+           if ((N->Info & OF_UBRA) != 0 ||
+                       ((E->Info & OF_CBRA) != 0 &&
+                GetBranchCond (E->OPC)  == GetBranchCond (N->OPC))) {
+
+               /* This is a jump cascade and we may jump to the final target.
+                * If we have a label, move the reference to this label. If
+                * we don't have a label, use the argument instead.
+                */
+               if (N->JumpTo) {
+                   /* Move the reference to the new insn */
+                   MoveCodeLabelRef (S, E, N->JumpTo);
+               } else {
+                   /* Remove the reference to the old label */
+                   RemoveCodeLabelRef (S, E);
+               }
+
+               /* Use the new argument */
+               CodeEntrySetArg (E, N->Arg);
+
+               /* Use the usage information from the new instruction */
+               E->Use = N->Use;
+               E->Chg = N->Chg;
+
+               /* Remember, we had changes */
+               ++Changes;
+
+               /* Done */
+               continue;
+
+           }
+
+           /* Check if both are conditional branches, and the condition of
+            * the second is the inverse of that of the first. In this case,
+            * the second branch will never be taken, and we may jump directly
+            * to the instruction behind this one.
+            */
+           goto NextEntry;
+
+       }
+
+NextEntry:
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                            Optimize jsr/rts                              */
+/*****************************************************************************/
+
+
+
+unsigned OptRTS (CodeSeg* S)
+/* Optimize subroutine calls followed by an RTS. The subroutine call will get
+ * replaced by a jump. Don't bother to delete the RTS if it does not have a
+ * label, the dead code elimination should take care of it.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;          
+
+    /* Get the number of entries, bail out if we have less than 2 entries */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count < 2) {
+       return 0;
+    }
+
+    /* Walk over all entries minus the last one */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get this entry */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+       /* Check if it's a subroutine call and if the following insn is RTS */
+       if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
+
+           /* Change the jsr to a jmp and use the additional info for a jump */
+           E->OPC  = OPC_JMP;
+           E->AM   = AM_BRA;
+           E->Info = GetOPCInfo (OPC_JMP);
+
+                   /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                          Optimize jump targets                           */
+/*****************************************************************************/
+
+
+
+unsigned OptJumpTarget (CodeSeg* S)
+/* If the instruction preceeding an unconditional branch is the same as the
+ * instruction preceeding the jump target, the jump target may be moved
+ * one entry back. This is a size optimization, since the instruction before
+ * the branch gets removed.
+ */
+{
+    unsigned Changes = 0;
+    CodeEntry* E1;                     /* Entry 1 */
+    CodeEntry* E2;             /* Entry 2 */
+    CodeEntry* T1;             /* Jump target entry 1 */
+    CodeEntry* T2;             /* Jump target entry 2 */
+    CodeLabel* TL1;            /* Target label 1 */
+    unsigned TI;               /* Target index */
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have not enough */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count < 3) {
+       return 0;
+    }
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get next entry */
+               E2 = GetCodeEntry (S, I+1);
+
+       /* Check if we have a jump or branch, and a matching label */
+               if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
+
+           /* Get the target instruction for the label */
+           T2 = E2->JumpTo->Owner;
+
+           /* Get the entry preceeding this one (if possible) */
+           TI = GetCodeEntryIndex (S, T2);
+           if (TI == 0) {
+               /* There is no entry before this one */
+               goto NextEntry;
+           }
+           T1 = GetCodeEntry (S, TI-1);
+
+           /* Get the entry preceeding the jump */
+           E1 = GetCodeEntry (S, I);
+
+           /* Check if both preceeding instructions are identical */
+           if (!CodeEntriesAreEqual (E1, T1)) {
+               /* Not equal, try next */
+               goto NextEntry;
+           }
+
+           /* Get the label for the instruction preceeding the jump target.
+            * This routine will create a new label if the instruction does
+            * not already have one.
+            */
+           TL1 = GenCodeLabel (S, T1);
+
+           /* Change the jump target to point to this new label */
+           MoveCodeLabelRef (S, E2, TL1);
+
+           /* If the instruction preceeding the jump has labels attached,
+            * move references to this label to the new label.
+            */
+           if (CodeEntryHasLabel (E1)) {
+               MoveCodeLabels (S, E1, T1);
+           }
+
+           /* Remove the entry preceeding the jump */
+           DelCodeEntry (S, I);
+           --Count;
+
+                   /* Remember, we had changes */
+           ++Changes;
+
+       }
+
+NextEntry:
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+/*****************************************************************************/
+/*                  Remove conditional jumps never taken                    */
+/*****************************************************************************/
+
+
+
+unsigned OptDeadCondBranches (CodeSeg* S)
+/* If an immidiate load of a register is followed by a conditional jump that
+ * is never taken because the load of the register sets the flags in such a
+ * manner, remove the conditional branch.
+ */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have not enough */
+    unsigned Count = GetCodeEntryCount (S);
+    if (Count < 2) {
+       return 0;
+    }
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get next entry */
+               CodeEntry* E = GetCodeEntry (S, I);
+
+       /* Check if it's a register load */
+               if ((E->Info & OF_LOAD) != 0 && E->AM == AM_IMM && (E->Flags & CEF_NUMARG) != 0) {
+
+           bc_t BC;
+
+           /* Immidiate register load, get next instruction */
+           CodeEntry* N = GetCodeEntry (S, I+1);
+
+           /* Check if the following insn is a conditional branch or if it
+            * has a label attached.
+            */
+           if ((N->Info & OF_CBRA) == 0 || CodeEntryHasLabel (E)) {
+               /* No conditional jump or label attached, bail out */
+               goto NextEntry;
+           }
+
+           /* Get the branch condition */
+           BC = GetBranchCond (N->OPC);
+
+           /* Check the argument against the branch condition */
+                   if ((BC == BC_EQ && E->Num != 0)            ||
+               (BC == BC_NE && E->Num == 0)            ||
+               (BC == BC_PL && (E->Num & 0x80) != 0)   ||
+               (BC == BC_MI && (E->Num & 0x80) == 0)) {
+
+               /* Remove the conditional branch */
+               DelCodeEntry (S, I+1);
+               --Count;
+
+               /* Remember, we had changes */
+               ++Changes;
+
+           }
+       }
+
+NextEntry:
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}       
+
+
+
diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h
new file mode 100644 (file)
index 0000000..bcb9e5a
--- /dev/null
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptind.h                                 */
+/*                                                                           */
+/*             Environment independent low level optimizations              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (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 COPTIND_H
+#define COPTIND_H
+
+
+
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned OptDeadJumps (CodeSeg* S);
+/* Remove dead jumps (jumps to the next instruction) */
+
+unsigned OptDeadCode (CodeSeg* S);
+/* Remove dead code (code that follows an unconditional jump or an rts/rti
+ * and has no label)
+ */
+
+unsigned OptJumpCascades (CodeSeg* S);
+/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
+ * replaced by a jump to the final location. This will in some cases produce
+ * worse code, because some jump targets are no longer reachable by short
+ * branches, but this is quite rare, so there are more advantages than
+ * disadvantages.
+ */
+
+unsigned OptRTS (CodeSeg* S);
+/* Optimize subroutine calls followed by an RTS. The subroutine call will get
+ * replaced by a jump. Don't bother to delete the RTS if it does not have a
+ * label, the dead code elimination should take care of it.
+ */
+
+unsigned OptJumpTarget (CodeSeg* S);
+/* If the instruction preceeding an unconditional branch is the same as the
+ * instruction preceeding the jump target, the jump target may be moved
+ * one entry back. This is a size optimization, since the instruction before
+ * the branch gets removed.
+ */
+
+unsigned OptDeadCondBranches (CodeSeg* S);
+/* If an immidiate load of a register is followed by a conditional jump that
+ * is never taken because the load of the register sets the flags in such a
+ * manner, remove the conditional branch.
+ */
+
+
+
+/* End of coptind.h */
+#endif
+
+
+
index d24e87cfe3441a3061343c0cd10d022cb1649bd1..1f34b4c28334f81e33d718a649570b519a82532e 100644 (file)
@@ -32,6 +32,7 @@ OBJS =        anonname.o      \
        codeopt.o       \
        codeseg.o       \
        compile.o       \
+       coptind.o       \
        cpu.o           \
        dataseg.o       \
        datatype.o      \