]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
Add code size factor for optimizer routines
[cc65] / src / cc65 / codeopt.c
index 5508d2beedd7685f36c420283974b6d382c15de8..f4fe3f435b69f841907301ff4b0e3290beb5db93 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2001      Ullrich von Bassewitz                                       */
+/* (C) 2001-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
 #include "codeent.h"
 #include "codeinfo.h"
 #include "coptadd.h"
+#include "coptc02.h"
 #include "coptcmp.h"
 #include "coptind.h"
 #include "coptneg.h"
+#include "coptpush.h"
 #include "coptstop.h"
 #include "coptsub.h"
 #include "copttest.h"
@@ -1112,7 +1114,7 @@ static unsigned OptDecouple (CodeSeg* S)
 /*****************************************************************************/
 
 
-               
+
 #if 0
 static unsigned OptSize1 (CodeSeg* S)
 /* Do size optimization by calling special subroutines that preload registers.
@@ -1330,6 +1332,7 @@ typedef struct OptFunc OptFunc;
 struct OptFunc {
     unsigned       (*Func) (CodeSeg*);  /* Optimizer function */
     const char*    Name;                /* Name of the function/group */
+    unsigned       CodeSizeFactor;      /* Code size factor for this opt func */
     unsigned long  TotalRuns;          /* Total number of runs */
     unsigned long  LastRuns;            /* Last number of runs */
     unsigned long  TotalChanges;        /* Total number of changes */
@@ -1349,57 +1352,61 @@ struct OptFunc {
 #define OptFuncEntry(func) static OptFuncDesc D##func = { func, #func, 0 }
 
 /* A list of all the function descriptions */
-static OptFunc DOptAdd1                = { OptAdd1,         "OptAdd1",         0, 0, 0, 0, 0 };
-static OptFunc DOptAdd2                = { OptAdd2,         "OptAdd2",         0, 0, 0, 0, 0 };
-static OptFunc DOptAdd3                = { OptAdd3,         "OptAdd3",         0, 0, 0, 0, 0 };
-static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    0, 0, 0, 0, 0 };
-static OptFunc DOptBranchDist          = { OptBranchDist,   "OptBranchDist",   0, 0, 0, 0, 0 };
-static OptFunc DOptCmp1                = { OptCmp1,         "OptCmp1",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp2                = { OptCmp2,         "OptCmp2",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp3                = { OptCmp3,         "OptCmp3",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp5                = { OptCmp5,         "OptCmp5",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp6                = { OptCmp6,         "OptCmp6",         0, 0, 0, 0, 0 };
-static OptFunc DOptCmp7                = { OptCmp7,         "OptCmp7",         0, 0, 0, 0, 0 };
-static OptFunc DOptCondBranches        = { OptCondBranches, "OptCondBranches", 0, 0, 0, 0, 0 };
-static OptFunc DOptDeadCode            = { OptDeadCode,     "OptDeadCode",     0, 0, 0, 0, 0 };
-static OptFunc DOptDeadJumps           = { OptDeadJumps,    "OptDeadJumps",    0, 0, 0, 0, 0 };
-static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     0, 0, 0, 0, 0 };
-static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",     0, 0, 0, 0, 0 };
-static OptFunc DOptJumpCascades        = { OptJumpCascades, "OptJumpCascades", 0, 0, 0, 0, 0 };
-static OptFunc DOptJumpTarget          = { OptJumpTarget,   "OptJumpTarget",   0, 0, 0, 0, 0 };
-static OptFunc DOptRTS                 = { OptRTS,          "OptRTS",          0, 0, 0, 0, 0 };
-static OptFunc DOptRTSJumps            = { OptRTSJumps,     "OptRTSJumps",     0, 0, 0, 0, 0 };
-static OptFunc DOptNegA1               = { OptNegA1,        "OptNegA1",        0, 0, 0, 0, 0 };
-static OptFunc DOptNegA2               = { OptNegA2,        "OptNegA2",        0, 0, 0, 0, 0 };
-static OptFunc DOptNegAX1              = { OptNegAX1,       "OptNegAX1",       0, 0, 0, 0, 0 };
-static OptFunc DOptNegAX2              = { OptNegAX2,       "OptNegAX2",       0, 0, 0, 0, 0 };
-static OptFunc DOptNegAX3              = { OptNegAX3,       "OptNegAX3",       0, 0, 0, 0, 0 };
-static OptFunc DOptNegAX4              = { OptNegAX4,       "OptNegAX4",       0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad1            = { OptPtrLoad1,     "OptPtrLoad1",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad2            = { OptPtrLoad2,     "OptPtrLoad2",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad3            = { OptPtrLoad3,     "OptPtrLoad3",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad4            = { OptPtrLoad4,     "OptPtrLoad4",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad5            = { OptPtrLoad5,     "OptPtrLoad5",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",     0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",    0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",    0, 0, 0, 0, 0 };
-static OptFunc DOptShift1              = { OptShift1,       "OptShift1",       0, 0, 0, 0, 0 };
-static OptFunc DOptShift2              = { OptShift2,       "OptShift2",       0, 0, 0, 0, 0 };
-/*static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        0, 0, 0, 0, 0 };*/
-static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        0, 0, 0, 0, 0 };
-static OptFunc DOptStackOps            = { OptStackOps,     "OptStackOps",     0, 0, 0, 0, 0 };
-static OptFunc DOptStoreLoad           = { OptStoreLoad,    "OptStoreLoad",    0, 0, 0, 0, 0 };
-static OptFunc DOptSub1                = { OptSub1,         "OptSub1",         0, 0, 0, 0, 0 };
-static OptFunc DOptSub2                = { OptSub2,         "OptSub2",         0, 0, 0, 0, 0 };
-static OptFunc DOptTest1               = { OptTest1,        "OptTest1",        0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers           = { OptTransfers,    "OptTransfers",    0, 0, 0, 0, 0 };
-static OptFunc DOptUnusedLoads         = { OptUnusedLoads,  "OptUnusedLoads",  0, 0, 0, 0, 0 };
-static OptFunc DOptUnusedStores        = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0 };
+static OptFunc DOpt65C02Ind            = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd1                = { OptAdd1,         "OptAdd1",          60, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd2                = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd3                = { OptAdd3,         "OptAdd3",          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 DOptCmp3                = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp4                = { OptCmp4,         "OptCmp4",         100, 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 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 };
+static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
+static OptFunc DOptJumpCascades        = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
+static OptFunc DOptJumpTarget          = { OptJumpTarget,   "OptJumpTarget",   100, 0, 0, 0, 0, 0 };
+static OptFunc DOptRTS                 = { OptRTS,          "OptRTS",          100, 0, 0, 0, 0, 0 };
+static OptFunc DOptRTSJumps1    = { OptRTSJumps1,    "OptRTSJumps1",           100, 0, 0, 0, 0, 0 };
+static OptFunc DOptRTSJumps2    = { OptRTSJumps2,    "OptRTSJumps2",           100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegA1               = { OptNegA1,        "OptNegA1",        100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegA2               = { OptNegA2,        "OptNegA2",        100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX1              = { OptNegAX1,       "OptNegAX1",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX2              = { OptNegAX2,       "OptNegAX2",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX3              = { OptNegAX3,       "OptNegAX3",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptNegAX4              = { OptNegAX4,       "OptNegAX4",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad1            = { OptPtrLoad1,     "OptPtrLoad1",     100, 0, 0, 0, 0, 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",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPush1               = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
+static OptFunc DOptShift1              = { OptShift1,       "OptShift1",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptShift2              = { OptShift2,       "OptShift2",       100, 0, 0, 0, 0, 0 };
+/*static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };*/
+static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        100, 0, 0, 0, 0, 0 };
+static OptFunc DOptStackOps            = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOptStoreLoad           = { OptStoreLoad,    "OptStoreLoad",      0, 0, 0, 0, 0, 0 };
+static OptFunc DOptSub1                = { OptSub1,         "OptSub1",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptSub2                = { OptSub2,         "OptSub2",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptTest1               = { OptTest1,        "OptTest1",        100, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers           = { OptTransfers,    "OptTransfers",      0, 0, 0, 0, 0, 0 };
+static OptFunc DOptUnusedLoads         = { OptUnusedLoads,  "OptUnusedLoads",    0, 0, 0, 0, 0, 0 };
+static OptFunc DOptUnusedStores        = { OptUnusedStores, "OptUnusedStores",   0, 0, 0, 0, 0, 0 };
 
 
 /* Table containing all the steps in alphabetical order */
 static OptFunc* OptFuncs[] = {
+    &DOpt65C02Ind,
     &DOptAdd1,
     &DOptAdd2,
     &DOptAdd3,
@@ -1433,8 +1440,10 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrLoad6,
     &DOptPtrStore1,
     &DOptPtrStore2,
+    &DOptPush1,
     &DOptRTS,
-    &DOptRTSJumps,
+    &DOptRTSJumps1,
+    &DOptRTSJumps2,
     &DOptShift1,
     &DOptShift2,
     /*&DOptSize1,*/
@@ -1578,7 +1587,7 @@ static void ReadOptStats (const char* Name)
 
        /* Parse the line */
                if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
-           /* Syntax error */
+           /* Syntax error */
            continue;
        }
 
@@ -1620,7 +1629,7 @@ static void WriteOptStats (const char* Name)
                         "%-20s %6lu %6lu %6lu %6lu\n",
                 O->Name,
                 O->TotalRuns,
-                O->LastRuns,
+                O->LastRuns,
                 O->TotalChanges,
                 O->LastChanges);
     }
@@ -1636,8 +1645,10 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 {
     unsigned Changes, C;
 
-    /* Don't run the function if it is disabled */
-    if (F->Disabled) {
+    /* Don't run the function if it is disabled or if it is prohibited by the
+     * code size factor
+     */
+    if (F->Disabled || CodeSizeFactor < F->CodeSizeFactor) {
        return 0;
     }
 
@@ -1663,107 +1674,174 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 
 
 
-static void RunOptGroup1 (CodeSeg* S)
+static unsigned RunOptGroup1 (CodeSeg* S)
 /* Run the first group of optimization steps. These steps translate known
  * patterns emitted by the code generator into more optimal patterns. Order
  * of the steps is important, because some of the steps done earlier cover
  * the same patterns as later steps as subpatterns.
  */
 {
-    RunOptFunc (S, &DOptPtrStore1, 1);
-    RunOptFunc (S, &DOptPtrStore2, 1);
-    RunOptFunc (S, &DOptPtrLoad1, 1);
-    RunOptFunc (S, &DOptPtrLoad2, 1);
-    RunOptFunc (S, &DOptPtrLoad3, 1);
-    RunOptFunc (S, &DOptPtrLoad4, 1);
-    RunOptFunc (S, &DOptPtrLoad5, 1);
-    RunOptFunc (S, &DOptNegAX1, 1);
-    RunOptFunc (S, &DOptNegAX2, 1);
-    RunOptFunc (S, &DOptNegAX3, 1);
-    RunOptFunc (S, &DOptNegAX4, 1);
-    RunOptFunc (S, &DOptAdd1, 1);
-    RunOptFunc (S, &DOptAdd2, 1);
-    RunOptFunc (S, &DOptShift1, 1);
-    RunOptFunc (S, &DOptShift2, 1);
+    unsigned Changes = 0;
+
+    Changes += RunOptFunc (S, &DOptPtrStore1, 1);
+    Changes += RunOptFunc (S, &DOptPtrStore2, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad3, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
+    Changes += RunOptFunc (S, &DOptNegAX1, 1);
+    Changes += RunOptFunc (S, &DOptNegAX2, 1);
+    Changes += RunOptFunc (S, &DOptNegAX3, 1);
+    Changes += RunOptFunc (S, &DOptNegAX4, 1);
+    Changes += RunOptFunc (S, &DOptAdd1, 1);
+    Changes += RunOptFunc (S, &DOptAdd2, 1);
+    Changes += RunOptFunc (S, &DOptShift1, 1);
+    Changes += RunOptFunc (S, &DOptShift2, 1);
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
 
-static void RunOptGroup2 (CodeSeg* S)
+static unsigned RunOptGroup2 (CodeSeg* S)
 /* Run one group of optimization steps. This step involves just decoupling
  * instructions by replacing them by instructions that do not depend on
  * previous instructions. This makes it easier to find instructions that
  * aren't used.
  */
 {
-    RunOptFunc (S, &DOptDecouple, 1);
-}
+    unsigned Changes = 0;
+
+    Changes += RunOptFunc (S, &DOptDecouple, 1);
 
+    /* Return the number of changes */
+    return Changes;
+}
 
 
 
-static void RunOptGroup3 (CodeSeg* S)
+static unsigned RunOptGroup3 (CodeSeg* S)
 /* Run one group of optimization steps. These steps depend on each other,
  * that means that one step may allow another step to do additional work,
  * so we will repeat the steps as long as we see any changes.
  */
 {
-    unsigned Changes;
+    unsigned Changes, C;
 
+    Changes = 0;
     do {
-       Changes = 0;
-
-       Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
-               Changes += RunOptFunc (S, &DOptNegA1, 1);
-               Changes += RunOptFunc (S, &DOptNegA2, 1);
-               Changes += RunOptFunc (S, &DOptSub1, 1);
-               Changes += RunOptFunc (S, &DOptSub2, 1);
-               Changes += RunOptFunc (S, &DOptAdd3, 1);
-       Changes += RunOptFunc (S, &DOptStackOps, 1);
-               Changes += RunOptFunc (S, &DOptJumpCascades, 1);
-               Changes += RunOptFunc (S, &DOptDeadJumps, 1);
-               Changes += RunOptFunc (S, &DOptRTS, 1);
-               Changes += RunOptFunc (S, &DOptDeadCode, 1);
-               Changes += RunOptFunc (S, &DOptJumpTarget, 1);
-       Changes += RunOptFunc (S, &DOptCondBranches, 1);
-       Changes += RunOptFunc (S, &DOptRTSJumps, 1);
-       Changes += RunOptFunc (S, &DOptBoolTrans, 1);
-       Changes += RunOptFunc (S, &DOptCmp1, 1);
-       Changes += RunOptFunc (S, &DOptCmp2, 1);
-       Changes += RunOptFunc (S, &DOptCmp3, 1);
-       Changes += RunOptFunc (S, &DOptCmp4, 1);
-       Changes += RunOptFunc (S, &DOptCmp5, 1);
-       Changes += RunOptFunc (S, &DOptCmp6, 1);
-       Changes += RunOptFunc (S, &DOptCmp7, 1);
-       Changes += RunOptFunc (S, &DOptTest1, 1);
-       Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
-       Changes += RunOptFunc (S, &DOptUnusedStores, 1);
-       Changes += RunOptFunc (S, &DOptDupLoads, 1);
-       Changes += RunOptFunc (S, &DOptStoreLoad, 1);
-       Changes += RunOptFunc (S, &DOptTransfers, 1);
-
-    } while (Changes);
+               C = 0;
+
+               C += RunOptFunc (S, &DOptPtrLoad6, 1);
+               C += RunOptFunc (S, &DOptNegA1, 1);
+               C += RunOptFunc (S, &DOptNegA2, 1);
+               C += RunOptFunc (S, &DOptSub1, 1);
+               C += RunOptFunc (S, &DOptSub2, 1);
+               C += RunOptFunc (S, &DOptAdd3, 1);
+               C += RunOptFunc (S, &DOptStackOps, 1);
+               C += RunOptFunc (S, &DOptJumpCascades, 1);
+               C += RunOptFunc (S, &DOptDeadJumps, 1);
+               C += RunOptFunc (S, &DOptRTS, 1);
+               C += RunOptFunc (S, &DOptDeadCode, 1);
+               C += RunOptFunc (S, &DOptJumpTarget, 1);
+               C += RunOptFunc (S, &DOptCondBranches, 1);
+               C += RunOptFunc (S, &DOptRTSJumps1, 1);
+               C += RunOptFunc (S, &DOptBoolTrans, 1);
+               C += RunOptFunc (S, &DOptCmp1, 1);
+               C += RunOptFunc (S, &DOptCmp2, 1);
+               C += RunOptFunc (S, &DOptCmp3, 1);
+               C += RunOptFunc (S, &DOptCmp4, 1);
+               C += RunOptFunc (S, &DOptCmp5, 1);
+               C += RunOptFunc (S, &DOptCmp6, 1);
+               C += RunOptFunc (S, &DOptCmp7, 1);
+               C += RunOptFunc (S, &DOptTest1, 1);
+               C += RunOptFunc (S, &DOptUnusedLoads, 1);
+               C += RunOptFunc (S, &DOptUnusedStores, 1);
+               C += RunOptFunc (S, &DOptDupLoads, 1);
+               C += RunOptFunc (S, &DOptStoreLoad, 1);
+               C += RunOptFunc (S, &DOptTransfers, 1);
+
+       Changes += C;
+
+    } while (C);
+
+    /* Return the number of changes */
+    return Changes;
 }
 
 
 
-static void RunOptGroup4 (CodeSeg* S)
-/* The last group of optimization steps. Adjust branches.
+static unsigned RunOptGroup4 (CodeSeg* S)
+/* 65C02 specific optimizations. */
+{
+    unsigned Changes = 0;
+
+    if (CPU >= CPU_65C02) {
+       /* Replace (zp),y by (zp) if Y is zero. If we have changes, run register
+        * load optimization again, since loads of Y may have become unnecessary.
+        */
+       unsigned C = RunOptFunc (S, &DOpt65C02Ind, 1);
+       Changes += C;
+       if (C) {
+           Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+       }
+    }
+
+    /* Return the number of changes */
+    return Changes;
+}
+
+
+
+static unsigned RunOptGroup5 (CodeSeg* S)
+/* Run another round of pattern replacements. These are done late, since there
+ * may be better replacements before.
  */
 {
+    unsigned Changes = 0;
+
+    Changes += RunOptFunc (S, &DOptPush1, 1);
+
+    /* Return the number of changes */
+    return Changes;
+}
+
+
+
+static unsigned RunOptGroup6 (CodeSeg* S)
+/* The last group of optimization steps. Adjust branches, do size optimizations.
+ */
+{
+    unsigned Changes = 0;
+    unsigned C;
+
     /* Optimize for size, that is replace operations by shorter ones, even
      * if this does hinder further optimizations (no problem since we're
      * done soon).
      */
-    RunOptFunc (S, &DOptSize2, 1);
+    Changes += RunOptFunc (S, &DOptSize2, 1);
 
     /* Run the jump target optimization again, since the size optimization
      * above may have opened new oportunities.
      */
-    RunOptFunc (S, &DOptJumpTarget, 5);
+    Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+
+    /* Adjust branch distances */
+    Changes += RunOptFunc (S, &DOptBranchDist, 3);
+
+    /* Replace conditional branches to RTS. If we had changes, we must run dead
+     * code elimination again, since the change may have introduced dead code.
+     */
+    C = RunOptFunc (S, &DOptRTSJumps2, 1);
+    Changes += C;
+    if (C) {
+       Changes += RunOptFunc (S, &DOptDeadCode, 1);
+    }
 
-    /* Finally, adjust branch distances */
-    RunOptFunc (S, &DOptBranchDist, 3);
+    /* Return the number of changes */
+    return Changes;
 }
 
 
@@ -1775,7 +1853,7 @@ void RunOpt (CodeSeg* S)
 
     /* If we shouldn't run the optimizer, bail out */
     if (!Optimize) {
-       return;
+       return;
     }
 
     /* Check if we are requested to write optimizer statistics */
@@ -1796,6 +1874,8 @@ void RunOpt (CodeSeg* S)
     RunOptGroup2 (S);
     RunOptGroup3 (S);
     RunOptGroup4 (S);
+    RunOptGroup5 (S);
+    RunOptGroup6 (S);
 
     /* Write statistics */
     if (StatFileName) {