]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeopt.c
added optimization for indexed 16-bit array load of form (array[i & 0x7f])
[cc65] / src / cc65 / codeopt.c
index aaa047d9c79253b9b9ec7b081cf0ed0602b0042e..d920f001a6134488cad838e84aa3302a56e45db3 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                codeopt.c                                 */
+/*                                 codeopt.c                                 */
 /*                                                                           */
-/*                          Optimizer subroutines                           */
+/*                           Optimizer subroutines                           */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
@@ -35,6 +35,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 
 /* common */
 #include "abend.h"
@@ -42,6 +43,7 @@
 #include "cpu.h"
 #include "debugflag.h"
 #include "print.h"
+#include "strbuf.h"
 #include "xmalloc.h"
 #include "xsprintf.h"
 
@@ -49,6 +51,7 @@
 #include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
+#include "codeopt.h"
 #include "coptadd.h"
 #include "coptc02.h"
 #include "coptcmp.h"
@@ -65,8 +68,8 @@
 #include "copttest.h"
 #include "error.h"
 #include "global.h"
-#include "codeopt.h"
-
+#include "output.h"
+#include "symtab.h"
 
 
 /*****************************************************************************/
@@ -77,8 +80,8 @@
 
 static unsigned OptLoad1 (CodeSeg* S)
 /* Search for a call to ldaxysp where X is not used later and replace it by
- * a load of just the A register.
- */
+** a load of just the A register.
+*/
 {
     unsigned I;
     unsigned Changes = 0;
@@ -87,13 +90,13 @@ static unsigned OptLoad1 (CodeSeg* S)
     I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       CodeEntry* E;
+        CodeEntry* E;
 
-       /* Get next entry */
-               E = CS_GetEntry (S, I);
+        /* Get next entry */
+        E = CS_GetEntry (S, I);
 
-       /* Check for the sequence */
-               if (CE_IsCallTo (E, "ldaxysp")          &&
+        /* Check for the sequence */
+        if (CE_IsCallTo (E, "ldaxysp")          &&
             RegValIsKnown (E->RI->In.RegY)      &&
             !RegXUsed (S, I+1)) {
 
@@ -109,15 +112,15 @@ static unsigned OptLoad1 (CodeSeg* S)
             CS_InsertEntry (S, X, I+2);
 
             /* Now remove the call to the subroutine */
-           CS_DelEntry (S, I);
+            CS_DelEntry (S, I);
 
-           /* Remember, we had changes */
+            /* Remember, we had changes */
             ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
 
     }
 
@@ -137,13 +140,13 @@ static unsigned OptLoad2 (CodeSeg* S)
     I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       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 (CE_IsCallTo (L[0], "ldaxysp")) {
+        /* Check for the sequence */
+        if (CE_IsCallTo (L[0], "ldaxysp")) {
 
             CodeEntry* X;
 
@@ -158,8 +161,8 @@ static unsigned OptLoad2 (CodeSeg* S)
                 !RegXUsed (S, I+3)) {
 
                 /* A/X are stored into memory somewhere and X is not used
-                 * later
-                 */
+                ** later
+                */
 
                 /* lda (sp),y */
                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
@@ -209,13 +212,77 @@ static unsigned OptLoad2 (CodeSeg* S)
 
             }
 
-           /* Remember, we had changes */
+            /* Remember, we had changes */
             ++Changes;
 
-       }
+        }
 
-       /* Next entry */
-       ++I;
+        /* Next entry */
+        ++I;
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+static unsigned OptLoad3 (CodeSeg* S)
+/* Remove repeated loads from one and the same memory location */
+{
+    unsigned Changes = 0;
+    CodeEntry* Load = 0;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        /* Get next entry */
+        CodeEntry* E = CS_GetEntry (S, I);
+
+        /* Forget a preceeding load if we have a label */
+        if (Load && CE_HasLabel (E)) {
+            Load = 0;
+        }
+
+        /* Check if this insn is a load */
+        if (E->Info & OF_LOAD) {
+
+            CodeEntry* N;
+
+            /* If we had a preceeding load that is identical, remove this one.
+            ** If it is not identical, or we didn't have one, remember it.
+            */
+            if (Load != 0                               &&
+                E->OPC == Load->OPC                     &&
+                E->AM == Load->AM                       &&
+                ((E->Arg == 0 && Load->Arg == 0) ||
+                 strcmp (E->Arg, Load->Arg) == 0)       &&
+                (N = CS_GetNextEntry (S, I)) != 0       &&
+                (N->Info & OF_CBRA) == 0) {
+
+                /* Now remove the call to the subroutine */
+                CS_DelEntry (S, I);
+
+                /* Remember, we had changes */
+                ++Changes;
+
+                /* Next insn */
+                continue;
+
+            } else {
+
+                Load = E;
+
+            }
+
+        } else if ((E->Info & OF_CMP) == 0 && (E->Info & OF_CBRA) == 0) {
+            /* Forget the first load on occurance of any insn we don't like */
+            Load = 0;
+        }
+
+        /* Next entry */
+        ++I;
     }
 
     /* Return the number of changes made */
@@ -225,28 +292,28 @@ static unsigned OptLoad2 (CodeSeg* S)
 
 
 /*****************************************************************************/
-/*                           Decouple operations                            */
+/*                            Decouple operations                            */
 /*****************************************************************************/
 
 
 
 static unsigned OptDecouple (CodeSeg* S)
 /* Decouple operations, that is, do the following replacements:
- *
- *   dex        -> ldx #imm
- *   inx        -> ldx #imm
- *   dey        -> ldy #imm
- *   iny        -> ldy #imm
- *   tax        -> ldx #imm
- *   txa        -> lda #imm
- *   tay        -> ldy #imm
- *   tya        -> lda #imm
- *   lda zp     -> lda #imm
- *   ldx zp     -> ldx #imm
- *   ldy zp    -> ldy #imm
- *
- * Provided that the register values are known of course.
- */
+**
+**   dex        -> ldx #imm
+**   inx        -> ldx #imm
+**   dey        -> ldy #imm
+**   iny        -> ldy #imm
+**   tax        -> ldx #imm
+**   txa        -> lda #imm
+**   tay        -> ldy #imm
+**   tya        -> lda #imm
+**   lda zp     -> lda #imm
+**   ldx zp     -> ldx #imm
+**   ldy zp     -> ldy #imm
+**
+** Provided that the register values are known of course.
+*/
 {
     unsigned Changes = 0;
     unsigned I;
@@ -255,196 +322,196 @@ static unsigned OptDecouple (CodeSeg* S)
     I = 0;
     while (I < CS_GetEntryCount (S)) {
 
-       const char* Arg;
-
-       /* Get next entry and it's input register values */
-               CodeEntry* E = CS_GetEntry (S, I);
-       const RegContents* In = &E->RI->In;
-
-       /* Assume we have no replacement */
-       CodeEntry* X = 0;
-
-       /* Check the instruction */
-       switch (E->OPC) {
-
-           case OP65_DEA:
-               if (RegValIsKnown (In->RegA)) {
-                   Arg = MakeHexArg ((In->RegA - 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_DEX:
-               if (RegValIsKnown (In->RegX)) {
-                   Arg = MakeHexArg ((In->RegX - 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_DEY:
-               if (RegValIsKnown (In->RegY)) {
-                   Arg = MakeHexArg ((In->RegY - 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_INA:
-               if (RegValIsKnown (In->RegA)) {
-                   Arg = MakeHexArg ((In->RegA + 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_INX:
-               if (RegValIsKnown (In->RegX)) {
-                   Arg = MakeHexArg ((In->RegX + 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_INY:
-               if (RegValIsKnown (In->RegY)) {
-                   Arg = MakeHexArg ((In->RegY + 1) & 0xFF);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_LDA:
-               if (E->AM == AM65_ZP) {
-                   switch (GetKnownReg (E->Use & REG_ZP, In)) {
-                       case REG_TMP1:
-                           Arg = MakeHexArg (In->Tmp1);
-                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_LO:
-                           Arg = MakeHexArg (In->Ptr1Lo);
-                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_HI:
-                           Arg = MakeHexArg (In->Ptr1Hi);
-                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_LO:
-                           Arg = MakeHexArg (In->SRegLo);
-                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_HI:
-                           Arg = MakeHexArg (In->SRegHi);
-                           X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-                           break;
-                   }
-               }
-               break;
-
-           case OP65_LDX:
-               if (E->AM == AM65_ZP) {
-                   switch (GetKnownReg (E->Use & REG_ZP, In)) {
-                       case REG_TMP1:
-                           Arg = MakeHexArg (In->Tmp1);
-                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_LO:
-                           Arg = MakeHexArg (In->Ptr1Lo);
-                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_HI:
-                           Arg = MakeHexArg (In->Ptr1Hi);
-                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_LO:
-                           Arg = MakeHexArg (In->SRegLo);
-                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_HI:
-                           Arg = MakeHexArg (In->SRegHi);
-                           X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-                           break;
-                   }
-               }
-               break;
-
-           case OP65_LDY:
-               if (E->AM == AM65_ZP) {
-                   switch (GetKnownReg (E->Use, In)) {
-                       case REG_TMP1:
-                           Arg = MakeHexArg (In->Tmp1);
-                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_LO:
-                           Arg = MakeHexArg (In->Ptr1Lo);
-                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_PTR1_HI:
-                           Arg = MakeHexArg (In->Ptr1Hi);
-                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_LO:
-                           Arg = MakeHexArg (In->SRegLo);
-                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-                           break;
-
-                       case REG_SREG_HI:
-                           Arg = MakeHexArg (In->SRegHi);
-                           X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-                           break;
-                   }
-               }
-               break;
-
-           case OP65_TAX:
-               if (E->RI->In.RegA >= 0) {
-                   Arg = MakeHexArg (In->RegA);
-                   X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_TAY:
-               if (E->RI->In.RegA >= 0) {
-                   Arg = MakeHexArg (In->RegA);
-                   X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_TXA:
-               if (E->RI->In.RegX >= 0) {
-                   Arg = MakeHexArg (In->RegX);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           case OP65_TYA:
-               if (E->RI->In.RegY >= 0) {
-                   Arg = MakeHexArg (In->RegY);
-                   X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
-               }
-               break;
-
-           default:
-               /* Avoid gcc warnings */
-               break;
-
-       }
-
-       /* Insert the replacement if we have one */
-       if (X) {
-                   CS_InsertEntry (S, X, I+1);
-           CS_DelEntry (S, I);
-           ++Changes;
-       }
-
-       /* Next entry */
-       ++I;
+        const char* Arg;
+
+        /* Get next entry and it's input register values */
+        CodeEntry* E = CS_GetEntry (S, I);
+        const RegContents* In = &E->RI->In;
+
+        /* Assume we have no replacement */
+        CodeEntry* X = 0;
+
+        /* Check the instruction */
+        switch (E->OPC) {
+
+            case OP65_DEA:
+                if (RegValIsKnown (In->RegA)) {
+                    Arg = MakeHexArg ((In->RegA - 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_DEX:
+                if (RegValIsKnown (In->RegX)) {
+                    Arg = MakeHexArg ((In->RegX - 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_DEY:
+                if (RegValIsKnown (In->RegY)) {
+                    Arg = MakeHexArg ((In->RegY - 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_INA:
+                if (RegValIsKnown (In->RegA)) {
+                    Arg = MakeHexArg ((In->RegA + 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_INX:
+                if (RegValIsKnown (In->RegX)) {
+                    Arg = MakeHexArg ((In->RegX + 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_INY:
+                if (RegValIsKnown (In->RegY)) {
+                    Arg = MakeHexArg ((In->RegY + 1) & 0xFF);
+                    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_LDA:
+                if (E->AM == AM65_ZP) {
+                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
+                        case REG_TMP1:
+                            Arg = MakeHexArg (In->Tmp1);
+                            X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_LO:
+                            Arg = MakeHexArg (In->Ptr1Lo);
+                            X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_HI:
+                            Arg = MakeHexArg (In->Ptr1Hi);
+                            X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_LO:
+                            Arg = MakeHexArg (In->SRegLo);
+                            X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_HI:
+                            Arg = MakeHexArg (In->SRegHi);
+                            X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                            break;
+                    }
+                }
+                break;
+
+            case OP65_LDX:
+                if (E->AM == AM65_ZP) {
+                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
+                        case REG_TMP1:
+                            Arg = MakeHexArg (In->Tmp1);
+                            X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_LO:
+                            Arg = MakeHexArg (In->Ptr1Lo);
+                            X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_HI:
+                            Arg = MakeHexArg (In->Ptr1Hi);
+                            X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_LO:
+                            Arg = MakeHexArg (In->SRegLo);
+                            X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_HI:
+                            Arg = MakeHexArg (In->SRegHi);
+                            X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                            break;
+                    }
+                }
+                break;
+
+            case OP65_LDY:
+                if (E->AM == AM65_ZP) {
+                    switch (GetKnownReg (E->Use, In)) {
+                        case REG_TMP1:
+                            Arg = MakeHexArg (In->Tmp1);
+                            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_LO:
+                            Arg = MakeHexArg (In->Ptr1Lo);
+                            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_PTR1_HI:
+                            Arg = MakeHexArg (In->Ptr1Hi);
+                            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_LO:
+                            Arg = MakeHexArg (In->SRegLo);
+                            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                            break;
+
+                        case REG_SREG_HI:
+                            Arg = MakeHexArg (In->SRegHi);
+                            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                            break;
+                    }
+                }
+                break;
+
+            case OP65_TAX:
+                if (E->RI->In.RegA >= 0) {
+                    Arg = MakeHexArg (In->RegA);
+                    X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_TAY:
+                if (E->RI->In.RegA >= 0) {
+                    Arg = MakeHexArg (In->RegA);
+                    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_TXA:
+                if (E->RI->In.RegX >= 0) {
+                    Arg = MakeHexArg (In->RegX);
+                    X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            case OP65_TYA:
+                if (E->RI->In.RegY >= 0) {
+                    Arg = MakeHexArg (In->RegY);
+                    X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
+                }
+                break;
+
+            default:
+                /* Avoid gcc warnings */
+                break;
+
+        }
+
+        /* Insert the replacement if we have one */
+        if (X) {
+            CS_InsertEntry (S, X, I+1);
+            CS_DelEntry (S, I);
+            ++Changes;
+        }
+
+        /* Next entry */
+        ++I;
 
     }
 
@@ -462,9 +529,9 @@ static unsigned OptDecouple (CodeSeg* S)
 
 static unsigned IsDecSP (const CodeEntry* E)
 /* Check if this is an insn that decrements the stack pointer. If so, return
- * the decrement. If not, return zero.
- * The function expects E to be a subroutine call.
- */
+** the decrement. If not, return zero.
+** The function expects E to be a subroutine call.
+*/
 {
     if (strncmp (E->Arg, "decsp", 5) == 0) {
         if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
@@ -482,8 +549,8 @@ static unsigned IsDecSP (const CodeEntry* E)
 
 static unsigned OptStackPtrOps (CodeSeg* S)
 /* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
- * known cases!
- */
+** known cases!
+*/
 {
     unsigned Changes = 0;
     unsigned I;
@@ -532,12 +599,12 @@ static unsigned OptStackPtrOps (CodeSeg* S)
             CS_GenRegInfo (S);
 
             /* Remember we had changes */
-           ++Changes;
+            ++Changes;
 
-       } else {
+        } else {
 
             /* Next entry */
-           ++I;
+            ++I;
         }
 
     }
@@ -546,10 +613,119 @@ static unsigned OptStackPtrOps (CodeSeg* S)
     return Changes;
 }
 
+static unsigned OptGotoSPAdj (CodeSeg* S)
+/* Optimize SP adjustment for forward 'goto' */
+{
+    unsigned Changes = 0;
+    unsigned I;
 
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+        CodeEntry* L[10], *X;
+        unsigned short adjustment;
+        const char* Arg;
+
+        /* Get next entry */
+        L[0] = CS_GetEntry (S, I);
+
+        /* Check for the sequence generated by g_lateadjustSP */
+        if (L[0]->OPC == OP65_PHA            &&
+            CS_GetEntries (S, L+1, I+1, 9)   &&
+            L[1]->OPC == OP65_LDA            &&
+            L[1]->AM == AM65_ABS             &&
+            L[2]->OPC == OP65_CLC            &&
+            L[3]->OPC == OP65_ADC            &&
+            strcmp (L[3]->Arg, "sp") == 0    &&
+            L[6]->OPC == OP65_ADC            &&
+            strcmp (L[6]->Arg, "sp+1") == 0  &&
+            L[9]->OPC == OP65_JMP) {
+            adjustment = FindSPAdjustment (L[1]->Arg);
+
+            if (adjustment == 0) {
+                /* No SP adjustment needed, remove the whole sequence */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment >= 65536 - 8) {
+                /* If adjustment is in range [-8, 0) we use decsp* calls */
+                char Buf[20];
+                adjustment = 65536 - adjustment;
+                xsprintf (Buf, sizeof (Buf), "decsp%u", adjustment);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment >= 65536 - 255) {
+                /* For range [-255, -8) we have ldy #, jsr subysp */
+                adjustment = 65536 - adjustment;
+                Arg = MakeHexArg (adjustment);
+                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 10);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else if (adjustment > 255) {
+                /* For ranges [-32768, 255) and (255, 32767) the only modification
+                ** is to replace the absolute with immediate addressing
+                */
+                Arg = MakeHexArg (adjustment & 0xff);
+                X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 1);
+                Arg = MakeHexArg (adjustment >> 8);
+                X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, L[5]->LI);
+                CS_InsertEntry (S, X, I + 6);
+
+                /* Delete the old code */
+                CS_DelEntry (S, I + 2);
+                CS_DelEntry (S, I + 6);
+            }
+            else if (adjustment > 8) {
+                /* For range (8, 255] we have ldy #, jsr addysp */
+                Arg = MakeHexArg (adjustment & 0xff);
+                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, "addysp", 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 10);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            else {
+                /* If adjustment is in range (0, 8] we use incsp* calls */
+                char Buf[20];
+                xsprintf (Buf, sizeof (Buf), "incsp%u", adjustment);
+                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, L[1]->LI);
+                CS_InsertEntry (S, X, I + 9);
+
+                /* Delete the old code */
+                CS_DelEntries (S, I, 9);
+            }
+            /* Regenerate register info */
+            CS_GenRegInfo (S);
+
+            /* Remember we had changes */
+            Changes++;
+
+        } else {
+
+            /* Next entry */
+            ++I;
+        }
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
 
 /*****************************************************************************/
-/*                             struct OptFunc                               */
+/*                              struct OptFunc                               */
 /*****************************************************************************/
 
 
@@ -559,7 +735,7 @@ 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  TotalRuns;           /* Total number of runs */
     unsigned long  LastRuns;            /* Last number of runs */
     unsigned long  TotalChanges;        /* Total number of changes */
     unsigned long  LastChanges;         /* Last number of changes */
@@ -569,21 +745,21 @@ struct OptFunc {
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
 
 /* A list of all the function descriptions */
 static OptFunc DOpt65C02BitOps  = { Opt65C02BitOps,  "Opt65C02BitOps",   66, 0, 0, 0, 0, 0 };
-static OptFunc DOpt65C02Ind            = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
+static OptFunc DOpt65C02Ind     = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOpt65C02Stores  = { Opt65C02Stores,  "Opt65C02Stores",  100, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd1                = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd2                = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd3                = { OptAdd3,         "OptAdd3",          65, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd4                = { OptAdd4,         "OptAdd4",          90, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd5                = { OptAdd5,         "OptAdd5",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptAdd6                = { OptAdd6,         "OptAdd6",          40, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd1         = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd2         = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd3         = { OptAdd3,         "OptAdd3",          65, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd4         = { OptAdd4,         "OptAdd4",          90, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd5         = { OptAdd5,         "OptAdd5",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptAdd6         = { OptAdd6,         "OptAdd6",          40, 0, 0, 0, 0, 0 };
 static OptFunc DOptBNegA1       = { OptBNegA1,       "OptBNegA1",       100, 0, 0, 0, 0, 0 };
 static OptFunc DOptBNegA2       = { OptBNegA2,       "OptBNegA2",       100, 0, 0, 0, 0, 0 };
 static OptFunc DOptBNegAX1      = { OptBNegAX1,      "OptBNegAX1",      100, 0, 0, 0, 0, 0 };
@@ -591,83 +767,88 @@ static OptFunc DOptBNegAX2      = { OptBNegAX2,      "OptBNegAX2",      100, 0,
 static OptFunc DOptBNegAX3      = { OptBNegAX3,      "OptBNegAX3",      100, 0, 0, 0, 0, 0 };
 static OptFunc DOptBNegAX4      = { OptBNegAX4,      "OptBNegAX4",      100, 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",          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",          75, 0, 0, 0, 0, 0 };
-static OptFunc DOptCmp5                = { OptCmp5,         "OptCmp5",         100, 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 DOptCmp9                = { OptCmp9,         "OptCmp9",          85, 0, 0, 0, 0, 0 };
+static OptFunc DOptBranchDist   = { OptBranchDist,   "OptBranchDist",     0, 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",          75, 0, 0, 0, 0, 0 };
+static OptFunc DOptCmp5         = { OptCmp5,         "OptCmp5",         100, 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 DOptCmp9         = { OptCmp9,         "OptCmp9",          85, 0, 0, 0, 0, 0 };
+static OptFunc DOptComplAX1     = { OptComplAX1,     "OptComplAX1",      65, 0, 0, 0, 0, 0 };
 static OptFunc DOptCondBranches1= { OptCondBranches1,"OptCondBranches1", 80, 0, 0, 0, 0, 0 };
 static OptFunc DOptCondBranches2= { OptCondBranches2,"OptCondBranches2",  0, 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 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 DOptGotoSPAdj    = { OptGotoSPAdj,    "OptGotoSPAdj",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptIndLoads1    = { OptIndLoads1,    "OptIndLoads1",      0, 0, 0, 0, 0, 0 };
 static OptFunc DOptIndLoads2    = { OptIndLoads2,    "OptIndLoads2",      0, 0, 0, 0, 0, 0 };
-static OptFunc DOptJumpCascades        = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
+static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget1  = { OptJumpTarget1,  "OptJumpTarget1",  100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget2  = { OptJumpTarget2,  "OptJumpTarget2",  100, 0, 0, 0, 0, 0 };
 static OptFunc DOptJumpTarget3  = { OptJumpTarget3,  "OptJumpTarget3",  100, 0, 0, 0, 0, 0 };
 static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
 static OptFunc DOptLoad2        = { OptLoad2,        "OptLoad2",        200, 0, 0, 0, 0, 0 };
+static OptFunc DOptLoad3        = { OptLoad3,        "OptLoad3",          0, 0, 0, 0, 0, 0 };
 static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       165, 0, 0, 0, 0, 0 };
 static OptFunc DOptNegAX2       = { OptNegAX2,       "OptNegAX2",       200, 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 DOptPrecalc      = { OptPrecalc,      "OptPrecalc",             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",      50, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad6            = { OptPtrLoad6,     "OptPtrLoad6",      60, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad7            = { OptPtrLoad7,     "OptPtrLoad7",     140, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad11           = { OptPtrLoad11,    "OptPtrLoad11",     92, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad12           = { OptPtrLoad12,    "OptPtrLoad12",     50, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad13           = { OptPtrLoad13,    "OptPtrLoad13",     65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad14           = { OptPtrLoad14,    "OptPtrLoad14",    108, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad15           = { OptPtrLoad15,    "OptPtrLoad15",     86, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad16           = { OptPtrLoad16,    "OptPtrLoad16",    100, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrLoad17           = { OptPtrLoad17,    "OptPtrLoad17",    190, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore1           = { OptPtrStore1,    "OptPtrStore1",     65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore2           = { OptPtrStore2,    "OptPtrStore2",     65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPtrStore3           = { OptPtrStore3,    "OptPtrStore3",    100, 0, 0, 0, 0, 0 };
-static OptFunc DOptPush1               = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
-static OptFunc DOptPush2               = { OptPush2,        "OptPush2",         50, 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 DOptPrecalc      = { OptPrecalc,      "OptPrecalc",      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",      50, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad6     = { OptPtrLoad6,     "OptPtrLoad6",      60, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad7     = { OptPtrLoad7,     "OptPtrLoad7",     140, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad11    = { OptPtrLoad11,    "OptPtrLoad11",     92, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad12    = { OptPtrLoad12,    "OptPtrLoad12",     50, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad13    = { OptPtrLoad13,    "OptPtrLoad13",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad14    = { OptPtrLoad14,    "OptPtrLoad14",    108, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad15    = { OptPtrLoad15,    "OptPtrLoad15",     86, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad16    = { OptPtrLoad16,    "OptPtrLoad16",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad17    = { OptPtrLoad17,    "OptPtrLoad17",    190, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad18    = { OptPtrLoad18,    "OptPtrLoad18",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrLoad19    = { OptPtrLoad19,    "OptPtrLoad19",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore1    = { OptPtrStore1,    "OptPtrStore1",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore2    = { OptPtrStore2,    "OptPtrStore2",     65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPtrStore3    = { OptPtrStore3,    "OptPtrStore3",    100, 0, 0, 0, 0, 0 };
+static OptFunc DOptPush1        = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
+static OptFunc DOptPush2        = { OptPush2,        "OptPush2",         50, 0, 0, 0, 0, 0 };
 static OptFunc DOptPushPop      = { OptPushPop,      "OptPushPop",        0, 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 DOptShift3              = { OptShift3,       "OptShift3",        17, 0, 0, 0, 0, 0 };
-static OptFunc DOptShift4              = { OptShift4,       "OptShift4",       100, 0, 0, 0, 0, 0 };
-static OptFunc DOptShift5              = { OptShift5,       "OptShift5",       110, 0, 0, 0, 0, 0 };
-static OptFunc DOptShift6              = { OptShift6,       "OptShift6",       200, 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 DOptShift3       = { OptShift3,       "OptShift3",        17, 0, 0, 0, 0, 0 };
+static OptFunc DOptShift4       = { OptShift4,       "OptShift4",       100, 0, 0, 0, 0, 0 };
+static OptFunc DOptShift5       = { OptShift5,       "OptShift5",       110, 0, 0, 0, 0, 0 };
+static OptFunc DOptShift6       = { OptShift6,       "OptShift6",       200, 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 DOptStackOps     = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
 static OptFunc DOptStackPtrOps  = { OptStackPtrOps,  "OptStackPtrOps",   50, 0, 0, 0, 0, 0 };
 static OptFunc DOptStore1       = { OptStore1,       "OptStore1",        70, 0, 0, 0, 0, 0 };
 static OptFunc DOptStore2       = { OptStore2,       "OptStore2",       115, 0, 0, 0, 0, 0 };
 static OptFunc DOptStore3       = { OptStore3,       "OptStore3",       120, 0, 0, 0, 0, 0 };
 static OptFunc DOptStore4       = { OptStore4,       "OptStore4",        50, 0, 0, 0, 0, 0 };
 static OptFunc DOptStore5       = { OptStore5,       "OptStore5",       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 DOptSub3                = { OptSub3,         "OptSub3",         100, 0, 0, 0, 0, 0 };
-static OptFunc DOptTest1               = { OptTest1,        "OptTest1",         65, 0, 0, 0, 0, 0 };
-static OptFunc DOptTest2               = { OptTest2,        "OptTest2",         50, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers1          = { OptTransfers1,   "OptTransfers1",     0, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers2          = { OptTransfers2,   "OptTransfers2",    60, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers3          = { OptTransfers3,   "OptTransfers3",    65, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers4          = { OptTransfers4,   "OptTransfers4",    65, 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 };
+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 DOptSub3         = { OptSub3,         "OptSub3",         100, 0, 0, 0, 0, 0 };
+static OptFunc DOptTest1        = { OptTest1,        "OptTest1",         65, 0, 0, 0, 0, 0 };
+static OptFunc DOptTest2        = { OptTest2,        "OptTest2",         50, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers1   = { OptTransfers1,   "OptTransfers1",     0, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers2   = { OptTransfers2,   "OptTransfers2",    60, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers3   = { OptTransfers3,   "OptTransfers3",    65, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers4   = { OptTransfers4,   "OptTransfers4",    65, 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 */
@@ -698,12 +879,14 @@ static OptFunc* OptFuncs[] = {
     &DOptCmp7,
     &DOptCmp8,
     &DOptCmp9,
+    &DOptComplAX1,
     &DOptCondBranches1,
     &DOptCondBranches2,
     &DOptDeadCode,
     &DOptDeadJumps,
     &DOptDecouple,
     &DOptDupLoads,
+    &DOptGotoSPAdj,
     &DOptIndLoads1,
     &DOptIndLoads2,
     &DOptJumpCascades,
@@ -712,6 +895,7 @@ static OptFunc* OptFuncs[] = {
     &DOptJumpTarget3,
     &DOptLoad1,
     &DOptLoad2,
+    &DOptLoad3,
     &DOptNegAX1,
     &DOptNegAX2,
     &DOptPrecalc,
@@ -723,6 +907,8 @@ static OptFunc* OptFuncs[] = {
     &DOptPtrLoad15,
     &DOptPtrLoad16,
     &DOptPtrLoad17,
+    &DOptPtrLoad18,
+    &DOptPtrLoad19,
     &DOptPtrLoad2,
     &DOptPtrLoad3,
     &DOptPtrLoad4,
@@ -780,8 +966,8 @@ static int CmpOptStep (const void* Key, const void* Func)
 
 static OptFunc* FindOptFunc (const char* Name)
 /* Find an optimizer step by name in the table and return a pointer. Return
- * NULL if no such step is found.
- */
+** NULL if no such step is found.
+*/
 {
     /* Search for the function in the list */
     OptFunc** O = bsearch (Name, OptFuncs, OPTFUNC_COUNT, sizeof (OptFuncs[0]), CmpOptStep);
@@ -792,14 +978,14 @@ static OptFunc* FindOptFunc (const char* Name)
 
 static OptFunc* GetOptFunc (const char* Name)
 /* Find an optimizer step by name in the table and return a pointer. Print an
- * error and call AbEnd if not found.
- */
+** error and call AbEnd if not found.
+*/
 {
     /* Search for the function in the list */
     OptFunc* F = FindOptFunc (Name);
     if (F == 0) {
-       /* Not found */
-       AbEnd ("Optimization step `%s' not found", Name);
+        /* Not found */
+        AbEnd ("Optimization step '%s' not found", Name);
     }
     return F;
 }
@@ -810,12 +996,12 @@ void DisableOpt (const char* Name)
 /* Disable the optimization with the given name */
 {
     if (strcmp (Name, "any") == 0) {
-       unsigned I;
-               for (I = 0; I < OPTFUNC_COUNT; ++I) {
-                   OptFuncs[I]->Disabled = 1;
-       }
+        unsigned I;
+        for (I = 0; I < OPTFUNC_COUNT; ++I) {
+            OptFuncs[I]->Disabled = 1;
+        }
     } else {
-       GetOptFunc(Name)->Disabled = 1;
+        GetOptFunc(Name)->Disabled = 1;
     }
 }
 
@@ -825,12 +1011,12 @@ void EnableOpt (const char* Name)
 /* Enable the optimization with the given name */
 {
     if (strcmp (Name, "any") == 0) {
-       unsigned I;
-               for (I = 0; I < OPTFUNC_COUNT; ++I) {
-                   OptFuncs[I]->Disabled = 0;
-       }
+        unsigned I;
+        for (I = 0; I < OPTFUNC_COUNT; ++I) {
+            OptFuncs[I]->Disabled = 0;
+        }
     } else {
-       GetOptFunc(Name)->Disabled = 0;
+        GetOptFunc(Name)->Disabled = 0;
     }
 }
 
@@ -840,8 +1026,10 @@ void ListOptSteps (FILE* F)
 /* List all optimization steps */
 {
     unsigned I;
+    
+    fprintf (F, "any\n");
     for (I = 0; I < OPTFUNC_COUNT; ++I) {
-       fprintf (F, "%s\n", OptFuncs[I]->Name);
+        fprintf (F, "%s\n", OptFuncs[I]->Name);
     }
 }
 
@@ -856,60 +1044,60 @@ static void ReadOptStats (const char* Name)
     /* Try to open the file */
     FILE* F = fopen (Name, "r");
     if (F == 0) {
-       /* Ignore the error */
-       return;
+        /* Ignore the error */
+        return;
     }
 
     /* Read and parse the lines */
     Lines = 0;
     while (fgets (Buf, sizeof (Buf), F) != 0) {
 
-       char* B;
-       unsigned Len;
-       OptFunc* Func;
-
-       /* Fields */
-       char Name[32];
-               unsigned long  TotalRuns;
-       unsigned long  TotalChanges;
-
-       /* Count lines */
-       ++Lines;
-
-       /* Remove trailing white space including the line terminator */
-       B = Buf;
-       Len = strlen (B);
-       while (Len > 0 && IsSpace (B[Len-1])) {
-           --Len;
-       }
-       B[Len] = '\0';
-
-       /* Remove leading whitespace */
-       while (IsSpace (*B)) {
-           ++B;
-       }
-
-       /* Check for empty and comment lines */
-       if (*B == '\0' || *B == ';' || *B == '#') {
-           continue;
-       }
-
-       /* Parse the line */
-               if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
-           /* Syntax error */
-           continue;
-       }
-
-       /* Search for the optimizer step. */
-       Func = FindOptFunc (Name);
-       if (Func == 0) {
-           /* Not found */
-           continue;
-       }
-
-       /* Found the step, set the fields */
-       Func->TotalRuns    = TotalRuns;
-       Func->TotalChanges = TotalChanges;
+        char* B;
+        unsigned Len;
+        OptFunc* Func;
+
+        /* Fields */
+        char Name[32];
+        unsigned long  TotalRuns;
+        unsigned long  TotalChanges;
+
+        /* Count lines */
+        ++Lines;
+
+        /* Remove trailing white space including the line terminator */
+        B = Buf;
+        Len = strlen (B);
+        while (Len > 0 && IsSpace (B[Len-1])) {
+            --Len;
+        }
+        B[Len] = '\0';
+
+        /* Remove leading whitespace */
+        while (IsSpace (*B)) {
+            ++B;
+        }
+
+        /* Check for empty and comment lines */
+        if (*B == '\0' || *B == ';' || *B == '#') {
+            continue;
+        }
+
+        /* Parse the line */
+        if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
+            /* Syntax error */
+            continue;
+        }
+
+        /* Search for the optimizer step. */
+        Func = FindOptFunc (Name);
+        if (Func == 0) {
+            /* Not found */
+            continue;
+        }
+
+        /* Found the step, set the fields */
+        Func->TotalRuns    = TotalRuns;
+        Func->TotalChanges = TotalChanges;
 
     }
 
@@ -927,26 +1115,26 @@ static void WriteOptStats (const char* Name)
     /* Try to open the file */
     FILE* F = fopen (Name, "w");
     if (F == 0) {
-       /* Ignore the error */
-       return;
+        /* Ignore the error */
+        return;
     }
 
     /* Write a header */
     fprintf (F,
-            "; Optimizer               Total      Last       Total      Last\n"
-                    ";   Step                  Runs       Runs        Chg       Chg\n");
+             "; Optimizer               Total      Last       Total      Last\n"
+             ";   Step                  Runs       Runs        Chg       Chg\n");
 
 
     /* Write the data */
     for (I = 0; I < OPTFUNC_COUNT; ++I) {
-       const OptFunc* O = OptFuncs[I];
-       fprintf (F,
-                        "%-20s %10lu %10lu %10lu %10lu\n",
-                O->Name,
-                O->TotalRuns,
-                O->LastRuns,
-                O->TotalChanges,
-                O->LastChanges);
+        const OptFunc* O = OptFuncs[I];
+        fprintf (F,
+                 "%-20s %10lu %10lu %10lu %10lu\n",
+                 O->Name,
+                 O->TotalRuns,
+                 O->LastRuns,
+                 O->TotalChanges,
+                 O->LastChanges);
     }
 
     /* Close the file, ignore errors here. */
@@ -955,37 +1143,80 @@ static void WriteOptStats (const char* Name)
 
 
 
+static void OpenDebugFile (const CodeSeg* S)
+/* Open the debug file for the given segment if the flag is on */
+{
+    if (DebugOptOutput) {
+        StrBuf Name = AUTO_STRBUF_INITIALIZER;
+        if (S->Func) {
+            SB_CopyStr (&Name, S->Func->Name);
+        } else {
+            SB_CopyStr (&Name, "global");
+        }
+        SB_AppendStr (&Name, ".opt");
+        SB_Terminate (&Name);
+        OpenDebugOutputFile (SB_GetConstBuf (&Name));
+        SB_Done (&Name);
+    }
+}
+
+
+
+static void WriteDebugOutput (CodeSeg* S, const char* Step)
+/* Write a separator line into the debug file if the flag is on */
+{
+    if (DebugOptOutput) {
+        /* Output a separator */
+        WriteOutput ("=========================================================================\n");
+
+        /* Output a header line */
+        if (Step == 0) {
+            /* Initial output */
+            WriteOutput ("Initial code for function '%s':\n",
+                         S->Func? S->Func->Name : "<global>");
+        } else {
+            WriteOutput ("Code after applying '%s':\n", Step);
+        }
+
+        /* Output the code segment */
+        CS_Output (S);
+    }
+}
+
+
+
 static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 /* Run one optimizer function Max times or until there are no more changes */
 {
     unsigned Changes, C;
 
     /* Don't run the function if it is disabled or if it is prohibited by the
-     * code size factor
-     */
+    ** code size factor
+    */
     if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
-       return 0;
+        return 0;
     }
 
     /* Run this until there are no more changes */
     Changes = 0;
     do {
 
-       /* Run the function */
-       C = F->Func (S);
-        if (Debug && C > 0) {
-            printf ("Applied %s: %u changes\n", F->Name, C);
-        }
-       Changes += C;
+        /* Run the function */
+        C = F->Func (S);
+        Changes += C;
 
-       /* Do statistics */
-       ++F->TotalRuns;
-       ++F->LastRuns;
-       F->TotalChanges += C;
-       F->LastChanges  += C;
+        /* Do statistics */
+        ++F->TotalRuns;
+        ++F->LastRuns;
+        F->TotalChanges += C;
+        F->LastChanges  += C;
 
-        /* If we had changes, regenerate register info */
+        /* If we had changes, output stuff and regenerate register info */
         if (C) {
+            if (Debug) {
+                printf ("Applied %s: %u changes\n", F->Name, C);
+            }
+            WriteDebugOutput (S, F->Name);
             CS_GenRegInfo (S);
         }
 
@@ -999,13 +1230,14 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
 
 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.
- */
+** 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.
+*/
 {
     unsigned Changes = 0;
 
+    Changes += RunOptFunc (S, &DOptGotoSPAdj, 1);
     Changes += RunOptFunc (S, &DOptStackPtrOps, 5);
     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
     Changes += RunOptFunc (S, &DOptPtrStore2, 1);
@@ -1018,6 +1250,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad7, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad18, 1); /* Before OptPtrLoad11 */
     Changes += RunOptFunc (S, &DOptPtrLoad11, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad12, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad13, 1);
@@ -1025,6 +1258,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptPtrLoad15, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad16, 1);
     Changes += RunOptFunc (S, &DOptPtrLoad17, 1);
+    Changes += RunOptFunc (S, &DOptPtrLoad19, 1);
     Changes += RunOptFunc (S, &DOptBNegAX1, 1);
     Changes += RunOptFunc (S, &DOptBNegAX2, 1);
     Changes += RunOptFunc (S, &DOptBNegAX3, 1);
@@ -1054,10 +1288,10 @@ static unsigned RunOptGroup1 (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.
- */
+** instructions by replacing them by instructions that do not depend on
+** previous instructions. This makes it easier to find instructions that
+** aren't used.
+*/
 {
     unsigned Changes = 0;
 
@@ -1071,62 +1305,64 @@ static unsigned RunOptGroup2 (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.
- */
+** 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, C;
 
     Changes = 0;
     do {
-               C = 0;
+        C = 0;
 
-               C += RunOptFunc (S, &DOptBNegA1, 1);
-               C += RunOptFunc (S, &DOptBNegA2, 1);
+        C += RunOptFunc (S, &DOptBNegA1, 1);
+        C += RunOptFunc (S, &DOptBNegA2, 1);
         C += RunOptFunc (S, &DOptNegAX1, 1);
         C += RunOptFunc (S, &DOptNegAX2, 1);
-               C += RunOptFunc (S, &DOptStackOps, 3);
+        C += RunOptFunc (S, &DOptStackOps, 3);
+        C += RunOptFunc (S, &DOptShift1, 1);
         C += RunOptFunc (S, &DOptShift4, 1);
-               C += RunOptFunc (S, &DOptSub1, 1);
-               C += RunOptFunc (S, &DOptSub2, 1);
-               C += RunOptFunc (S, &DOptSub3, 1);
-               C += RunOptFunc (S, &DOptAdd5, 1);
-               C += RunOptFunc (S, &DOptAdd6, 1);
-               C += RunOptFunc (S, &DOptJumpCascades, 1);
-               C += RunOptFunc (S, &DOptDeadJumps, 1);
-               C += RunOptFunc (S, &DOptRTS, 1);
-               C += RunOptFunc (S, &DOptDeadCode, 1);
-               C += RunOptFunc (S, &DOptBoolTrans, 1);
-               C += RunOptFunc (S, &DOptJumpTarget1, 1);
-               C += RunOptFunc (S, &DOptJumpTarget2, 1);
-               C += RunOptFunc (S, &DOptCondBranches1, 1);
-               C += RunOptFunc (S, &DOptCondBranches2, 1);
-               C += RunOptFunc (S, &DOptRTSJumps1, 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, &DOptCmp8, 1);
-               C += RunOptFunc (S, &DOptCmp9, 1);
-               C += RunOptFunc (S, &DOptTest1, 1);
+        C += RunOptFunc (S, &DOptComplAX1, 1);
+        C += RunOptFunc (S, &DOptSub1, 1);
+        C += RunOptFunc (S, &DOptSub2, 1);
+        C += RunOptFunc (S, &DOptSub3, 1);
+        C += RunOptFunc (S, &DOptAdd5, 1);
+        C += RunOptFunc (S, &DOptAdd6, 1);
+        C += RunOptFunc (S, &DOptJumpCascades, 1);
+        C += RunOptFunc (S, &DOptDeadJumps, 1);
+        C += RunOptFunc (S, &DOptRTS, 1);
+        C += RunOptFunc (S, &DOptDeadCode, 1);
+        C += RunOptFunc (S, &DOptBoolTrans, 1);
+        C += RunOptFunc (S, &DOptJumpTarget1, 1);
+        C += RunOptFunc (S, &DOptJumpTarget2, 1);
+        C += RunOptFunc (S, &DOptCondBranches1, 1);
+        C += RunOptFunc (S, &DOptCondBranches2, 1);
+        C += RunOptFunc (S, &DOptRTSJumps1, 1);
+        C += RunOptFunc (S, &DOptCmp1, 1);
+        C += RunOptFunc (S, &DOptCmp2, 1);
+        C += RunOptFunc (S, &DOptCmp8, 1);      /* Must run before OptCmp3 */
+        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, &DOptCmp9, 1);
+        C += RunOptFunc (S, &DOptTest1, 1);
         C += RunOptFunc (S, &DOptLoad1, 1);
-               C += RunOptFunc (S, &DOptJumpTarget3, 1);       /* After OptCondBranches2 */
-               C += RunOptFunc (S, &DOptUnusedLoads, 1);
-               C += RunOptFunc (S, &DOptUnusedStores, 1);
-               C += RunOptFunc (S, &DOptDupLoads, 1);
-               C += RunOptFunc (S, &DOptStoreLoad, 1);
-               C += RunOptFunc (S, &DOptTransfers1, 1);
-               C += RunOptFunc (S, &DOptTransfers3, 1);
-               C += RunOptFunc (S, &DOptTransfers4, 1);
-               C += RunOptFunc (S, &DOptStore1, 1);
-               C += RunOptFunc (S, &DOptStore5, 1);
+        C += RunOptFunc (S, &DOptJumpTarget3, 1);       /* After OptCondBranches2 */
+        C += RunOptFunc (S, &DOptUnusedLoads, 1);
+        C += RunOptFunc (S, &DOptUnusedStores, 1);
+        C += RunOptFunc (S, &DOptDupLoads, 1);
+        C += RunOptFunc (S, &DOptStoreLoad, 1);
+        C += RunOptFunc (S, &DOptTransfers1, 1);
+        C += RunOptFunc (S, &DOptTransfers3, 1);
+        C += RunOptFunc (S, &DOptTransfers4, 1);
+        C += RunOptFunc (S, &DOptStore1, 1);
+        C += RunOptFunc (S, &DOptStore5, 1);
         C += RunOptFunc (S, &DOptPushPop, 1);
         C += RunOptFunc (S, &DOptPrecalc, 1);
 
-       Changes += C;
+        Changes += C;
 
     } while (C);
 
@@ -1138,8 +1374,8 @@ static unsigned RunOptGroup3 (CodeSeg* S)
 
 static unsigned RunOptGroup4 (CodeSeg* S)
 /* Run another round of pattern replacements. These are done late, since there
- * may be better replacements before.
- */
+** may be better replacements before.
+*/
 {
     unsigned Changes = 0;
 
@@ -1151,6 +1387,8 @@ static unsigned RunOptGroup4 (CodeSeg* S)
     Changes += RunOptFunc (S, &DOptTest2, 1);
     Changes += RunOptFunc (S, &DOptTransfers2, 1);
     Changes += RunOptFunc (S, &DOptLoad2, 1);
+    Changes += RunOptFunc (S, &DOptLoad3, 1);
+    Changes += RunOptFunc (S, &DOptDupLoads, 1);
 
     /* Return the number of changes */
     return Changes;
@@ -1165,15 +1403,15 @@ static unsigned RunOptGroup5 (CodeSeg* S)
 
     if (CPUIsets[CPU] & CPU_ISET_65SC02) {
         Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
-       Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
+        Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
         Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
-               if (Changes) {
+        if (Changes) {
             /* The 65C02 replacement codes do often make the use of a register
-             * value unnecessary, so if we have changes, run another load
-             * removal pass.
-             */
-           Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
-       }
+            ** value unnecessary, so if we have changes, run another load
+            ** removal pass.
+            */
+            Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+        }
     }
 
     /* Return the number of changes */
@@ -1184,18 +1422,18 @@ static unsigned RunOptGroup5 (CodeSeg* S)
 
 static unsigned RunOptGroup6 (CodeSeg* S)
 /* This one is quite special. It tries to replace "lda (sp),y" by "lda (sp,x)".
- * The latter is ony cycle slower, but if we're able to remove the necessary
- * load of the Y register, because X is zero anyway, we gain 1 cycle and
- * shorten the code by one (transfer) or two bytes (load). So what we do is
- * to replace the insns, remove unused loads, and then change back all insns
- * where Y is still zero (meaning that the load has not been removed).
- */
+** The latter is ony cycle slower, but if we're able to remove the necessary
+** load of the Y register, because X is zero anyway, we gain 1 cycle and
+** shorten the code by one (transfer) or two bytes (load). So what we do is
+** to replace the insns, remove unused loads, and then change back all insns
+** where Y is still zero (meaning that the load has not been removed).
+*/
 {
     unsigned Changes = 0;
 
     /* This group will only run for a standard 6502, because the 65C02 has a
-     * better addressing mode that covers this case.
-     */
+    ** better addressing mode that covers this case.
+    */
     if ((CPUIsets[CPU] & CPU_ISET_65SC02) == 0) {
         Changes += RunOptFunc (S, &DOptIndLoads1, 1);
         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
@@ -1210,21 +1448,21 @@ static unsigned RunOptGroup6 (CodeSeg* S)
 
 static unsigned RunOptGroup7 (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).
-     */
+    ** if this does hinder further optimizations (no problem since we're
+    ** done soon).
+    */
     C = RunOptFunc (S, &DOptSize1, 1);
     if (C) {
         Changes += C;
         /* Run some optimization passes again, since the size optimizations
-         * may have opened new oportunities.
-         */
+        ** may have opened new oportunities.
+        */
         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
         Changes += RunOptFunc (S, &DOptUnusedStores, 1);
         Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
@@ -1235,8 +1473,8 @@ static unsigned RunOptGroup7 (CodeSeg* S)
     if (C) {
         Changes += C;
         /* Run some optimization passes again, since the size optimizations
-         * may have opened new oportunities.
-         */
+        ** may have opened new oportunities.
+        */
         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
         Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
         Changes += RunOptFunc (S, &DOptStore5, 1);
@@ -1248,12 +1486,12 @@ static unsigned RunOptGroup7 (CodeSeg* S)
     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.
-     */
+    ** 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);
+        Changes += RunOptFunc (S, &DOptDeadCode, 1);
     }
 
     /* Return the number of changes */
@@ -1269,22 +1507,26 @@ void RunOpt (CodeSeg* S)
 
     /* If we shouldn't run the optimizer, bail out */
     if (!S->Optimize) {
-       return;
+        return;
     }
 
     /* Check if we are requested to write optimizer statistics */
     StatFileName = getenv ("CC65_OPTSTATS");
     if (StatFileName) {
-       ReadOptStats (StatFileName);
+        ReadOptStats (StatFileName);
     }
 
     /* Print the name of the function we are working on */
     if (S->Func) {
-       Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
+        Print (stdout, 1, "Running optimizer for function '%s'\n", S->Func->Name);
     } else {
-       Print (stdout, 1, "Running optimizer for global code segment\n");
+        Print (stdout, 1, "Running optimizer for global code segment\n");
     }
 
+    /* If requested, open an output file */
+    OpenDebugFile (S);
+    WriteDebugOutput (S, 0);
+
     /* Generate register info for all instructions */
     CS_GenRegInfo (S);
 
@@ -1300,11 +1542,13 @@ void RunOpt (CodeSeg* S)
     /* Free register info */
     CS_FreeRegInfo (S);
 
+    /* Close output file if necessary */
+    if (DebugOptOutput) {
+        CloseOutputFile ();
+    }
+
     /* Write statistics */
     if (StatFileName) {
-       WriteOptStats (StatFileName);
+        WriteOptStats (StatFileName);
     }
 }
-
-
-