]> git.sur5r.net Git - cc65/commitdiff
Added 65C02 specific optimizations.
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 13 Oct 2001 12:21:46 +0000 (12:21 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 13 Oct 2001 12:21:46 +0000 (12:21 +0000)
Make two runs over the code when generating register info to get info for
backward jumps right.

git-svn-id: svn://svn.cc65.org/cc65/trunk@1049 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeopt.c
src/cc65/codeseg.c
src/cc65/coptc02.c [new file with mode: 0644]
src/cc65/coptc02.h [new file with mode: 0644]
src/cc65/make/gcc.mak
src/cc65/make/watcom.mak

index 57cb394e60077d82973c99252d3fba0b0aa07aa3..77bf2c55cda0beb8315940a07c8a8ac3f64e33d2 100644 (file)
@@ -48,6 +48,7 @@
 #include "codeent.h"
 #include "codeinfo.h"
 #include "coptadd.h"
+#include "coptc02.h"
 #include "coptcmp.h"
 #include "coptind.h"
 #include "coptneg.h"
@@ -1349,6 +1350,7 @@ struct OptFunc {
 #define OptFuncEntry(func) static OptFuncDesc D##func = { func, #func, 0 }
 
 /* A list of all the function descriptions */
+static OptFunc DOpt65C02Ind            = { Opt65C02Ind,     "Opt65C02Ind",     0, 0, 0, 0, 0 };
 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 };
@@ -1401,6 +1403,7 @@ static OptFunc DOptUnusedStores   = { OptUnusedStores, "OptUnusedStores", 0, 0, 0,
 
 /* Table containing all the steps in alphabetical order */
 static OptFunc* OptFuncs[] = {
+    &DOpt65C02Ind,
     &DOptAdd1,
     &DOptAdd2,
     &DOptAdd3,
@@ -1750,7 +1753,24 @@ static void RunOptGroup3 (CodeSeg* S)
 
 
 static void RunOptGroup4 (CodeSeg* S)
-/* The last group of optimization steps. Adjust branches.
+/* 65C02 specific optimizations. */
+{
+    if (CPU < CPU_65C02) {
+       return;
+    }
+
+    /* 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.
+     */
+    if (RunOptFunc (S, &DOpt65C02Ind, 1) > 0) {
+       RunOptFunc (S, &DOptUnusedLoads, 1);
+    }
+}
+
+
+
+static void RunOptGroup5 (CodeSeg* S)
+/* The last group of optimization steps. Adjust branches, do size optimizations.
  */
 {
     /* Optimize for size, that is replace operations by shorter ones, even
@@ -1805,6 +1825,7 @@ void RunOpt (CodeSeg* S)
     RunOptGroup2 (S);
     RunOptGroup3 (S);
     RunOptGroup4 (S);
+    RunOptGroup5 (S);
 
     /* Write statistics */
     if (StatFileName) {
index 0ba5e0466d0c6982a5447ada808afc530eb79ec7..bbc21337a4170e0328a1d9317c96e9db108ffb43 100644 (file)
@@ -160,7 +160,7 @@ static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
 
 
 
-static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name, 
+static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name,
                                       void (*ErrorFunc) (const char*, ...))
 /* Add a code label for the next instruction to follow */
 {
@@ -1109,217 +1109,232 @@ void CS_GenRegInfo (CodeSeg* S)
     RegContents Regs;          /* Initial register contents */
     RegContents* CurrentRegs;   /* Current register contents */
     int WasJump;                /* True if last insn was a jump */
+    int Done;                   /* All runs done flag */
 
     /* Be sure to delete all register infos */
     CS_FreeRegInfo (S);
 
-    /* On entry, the register contents are unknown */
-    RC_Invalidate (&Regs);
-    CurrentRegs = &Regs;
+    /* We may need two runs to get back references right */
+    do {
 
-    /* First pass. Walk over all insns and note just the changes from one
-     * insn to the next one.
-     */
-    WasJump = 0;
-    for (I = 0; I < CS_GetEntryCount (S); ++I) {
-
-       CodeEntry* P;
-
-       /* Get the next instruction */
-       CodeEntry* E = CollAtUnchecked (&S->Entries, I);
+       /* Assume we're done after this run */
+       Done = 1;
+    
+       /* On entry, the register contents are unknown */
+       RC_Invalidate (&Regs);
+       CurrentRegs = &Regs;
 
-       /* If the instruction has a label, we need some special handling */
-       unsigned LabelCount = CE_GetLabelCount (E);
-       if (LabelCount > 0) {
-
-           /* Loop over all entry points that jump here. If these entry
-            * points already have register info, check if all values are
-            * known and identical. If all values are identical, and the
-            * preceeding instruction was not an unconditional branch, check
-            * if the register value on exit of the preceeding instruction
-            * is also identical. If all these values are identical, the
-            * value of a register is known, otherwise it is unknown.
-            */
-           CodeLabel* Label = CE_GetLabel (E, 0);
-           unsigned Entry;
-           if (WasJump) {
-               /* Preceeding insn was an unconditional branch */
-               CodeEntry* J = CL_GetRef(Label, 0);
-               if (J->RI) {
-                   Regs = J->RI->Out2;
+       /* Walk over all insns and note just the changes from one insn to the
+        * next one.
+        */
+       WasJump = 0;
+       for (I = 0; I < CS_GetEntryCount (S); ++I) {
+
+           CodeEntry* P;
+
+           /* Get the next instruction */
+           CodeEntry* E = CollAtUnchecked (&S->Entries, I);
+
+           /* If the instruction has a label, we need some special handling */
+           unsigned LabelCount = CE_GetLabelCount (E);
+           if (LabelCount > 0) {
+
+               /* Loop over all entry points that jump here. If these entry
+                * points already have register info, check if all values are
+                * known and identical. If all values are identical, and the
+                * preceeding instruction was not an unconditional branch, check
+                * if the register value on exit of the preceeding instruction
+                * is also identical. If all these values are identical, the
+                * value of a register is known, otherwise it is unknown.
+                */
+               CodeLabel* Label = CE_GetLabel (E, 0);
+               unsigned Entry;
+               if (WasJump) {
+                   /* Preceeding insn was an unconditional branch */
+                   CodeEntry* J = CL_GetRef(Label, 0);
+                   if (J->RI) {
+                       Regs = J->RI->Out2;
+                   } else {
+                       RC_Invalidate (&Regs);
+                   }
+                   Entry = 1;
                } else {
-                   RC_Invalidate (&Regs);
-               }
-               Entry = 1;
-           } else {
-               Regs = *CurrentRegs;
-               Entry = 0;
-           }
-
-           while (Entry < CL_GetRefCount (Label)) {
-               /* Get this entry */
-               CodeEntry* J = CL_GetRef (Label, Entry);
-               if (J->RI == 0) {
-                   /* No register info for this entry, bail out */
-                   RC_Invalidate (&Regs);
-                   break;
-               }
-               if (J->RI->Out2.RegA != Regs.RegA) {
-                   Regs.RegA = -1;
+                   Regs = *CurrentRegs;
+                   Entry = 0;
                }
-               if (J->RI->Out2.RegX != Regs.RegX) {
-                   Regs.RegX = -1;
-               }
-               if (J->RI->Out2.RegY != Regs.RegY) {
-                   Regs.RegY = -1;
-               }
-               if (J->RI->Out2.SRegLo != Regs.SRegLo) {
-                   Regs.SRegLo = -1;
-               }
-               if (J->RI->Out2.SRegHi != Regs.SRegHi) {
-                   Regs.SRegHi = -1;
-               }
-               ++Entry;
-           }
-
-           /* Use this register info */
-           CurrentRegs = &Regs;
 
-       }
-
-       /* Generate register info for this instruction */
-        CE_GenRegInfo (E, CurrentRegs);
-
-       /* Remember for the next insn if this insn was an uncondition branch */
-       WasJump = (E->Info & OF_UBRA) != 0;
-
-       /* Output registers for this insn are input for the next */
-       CurrentRegs = &E->RI->Out;
-
-       /* If this insn is a branch on zero flag, we may have more info on
-        * register contents for one of both flow directions, but only if
-        * there is a previous instruction.
-        */
-       if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
-
-           /* Get the branch condition */
-           bc_t BC = GetBranchCond (E->OPC);
-
-           /* Check the previous instruction */
-           switch (P->OPC) {
-
-               case OP65_ADC:
-               case OP65_AND:
-               case OP65_DEA:
-               case OP65_EOR:
-               case OP65_INA:
-               case OP65_LDA:
-               case OP65_ORA:
-               case OP65_PLA:
-               case OP65_SBC:
-                   /* A is zero in one execution flow direction */
-                   if (BC == BC_EQ) {
-                               E->RI->Out2.RegA = 0;
-                   } else {
-                       E->RI->Out.RegA = 0;
+               while (Entry < CL_GetRefCount (Label)) {
+                   /* Get this entry */
+                   CodeEntry* J = CL_GetRef (Label, Entry);
+                   if (J->RI == 0) {
+                       /* No register info for this entry. This means that the
+                        * instruction that jumps here is at higher addresses and
+                        * the jump is a backward jump. We need a second run to
+                        * get the register info right in this case. Until then,
+                        * assume unknown register contents.
+                        */
+                       Done = 0;
+                       RC_Invalidate (&Regs);
+                       break;
                    }
-                   break;
-
-               case OP65_CMP:
-                   /* If this is an immidiate compare, the A register has
-                    * the value of the compare later.
-                    */
-                   if (CE_KnownImm (P)) {
-                       if (BC == BC_EQ) {
-                           E->RI->Out2.RegA = (unsigned char)P->Num;
-                       } else {
-                           E->RI->Out.RegA = (unsigned char)P->Num;
-                       }
-                   }
-                   break;
-
-               case OP65_CPX:
-                   /* If this is an immidiate compare, the X register has
-                    * the value of the compare later.
-                    */
-                   if (CE_KnownImm (P)) {
-                       if (BC == BC_EQ) {
-                           E->RI->Out2.RegX = (unsigned char)P->Num;
-                       } else {
-                           E->RI->Out.RegX = (unsigned char)P->Num;
-                       }
-                   }
-                   break;
-
-               case OP65_CPY:
-                   /* If this is an immidiate compare, the Y register has
-                    * the value of the compare later.
-                    */
-                   if (CE_KnownImm (P)) {
-                       if (BC == BC_EQ) {
-                           E->RI->Out2.RegY = (unsigned char)P->Num;
-                       } else {
-                           E->RI->Out.RegY = (unsigned char)P->Num;
-                       }
-                   }
-                   break;
-
-               case OP65_DEX:
-               case OP65_INX:
-               case OP65_LDX:
-               case OP65_PLX:
-                   /* X is zero in one execution flow direction */
-                   if (BC == BC_EQ) {
-                               E->RI->Out2.RegX = 0;
-                   } else {
-                       E->RI->Out.RegX = 0;
+                   if (J->RI->Out2.RegA != Regs.RegA) {
+                       Regs.RegA = -1;
                    }
-                   break;
-
-               case OP65_DEY:
-               case OP65_INY:
-               case OP65_LDY:
-               case OP65_PLY:
-                   /* X is zero in one execution flow direction */
-                   if (BC == BC_EQ) {
-                               E->RI->Out2.RegY = 0;
-                   } else {
-                       E->RI->Out.RegY = 0;
+                   if (J->RI->Out2.RegX != Regs.RegX) {
+                       Regs.RegX = -1;
                    }
-                   break;
-
-               case OP65_TAX:
-               case OP65_TXA:
-                   /* If the branch is a beq, both A and X are zero at the
-                    * branch target, otherwise they are zero at the next
-                    * insn.
-                    */
-                   if (BC == BC_EQ) {
-                       E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
-                   } else {
-                       E->RI->Out.RegA = E->RI->Out.RegX = 0;
+                   if (J->RI->Out2.RegY != Regs.RegY) {
+                       Regs.RegY = -1;
                    }
-                   break;
-
-               case OP65_TAY:
-               case OP65_TYA:
-                   /* If the branch is a beq, both A and Y are zero at the
-                    * branch target, otherwise they are zero at the next
-                    * insn.
-                    */
-                   if (BC == BC_EQ) {
-                       E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
-                   } else {
-                       E->RI->Out.RegA = E->RI->Out.RegY = 0;
+                   if (J->RI->Out2.SRegLo != Regs.SRegLo) {
+                       Regs.SRegLo = -1;
                    }
-                   break;
-
-               default:
-                   break;
-
+                   if (J->RI->Out2.SRegHi != Regs.SRegHi) {
+                       Regs.SRegHi = -1;
+                   }
+                   ++Entry;
+               }
+    
+               /* Use this register info */
+               CurrentRegs = &Regs;
+    
+           }
+    
+           /* Generate register info for this instruction */
+           CE_GenRegInfo (E, CurrentRegs);
+    
+           /* Remember for the next insn if this insn was an uncondition branch */
+           WasJump = (E->Info & OF_UBRA) != 0;
+
+           /* Output registers for this insn are input for the next */
+           CurrentRegs = &E->RI->Out;
+    
+           /* If this insn is a branch on zero flag, we may have more info on
+            * register contents for one of both flow directions, but only if
+            * there is a previous instruction.
+            */
+           if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
+    
+               /* Get the branch condition */
+               bc_t BC = GetBranchCond (E->OPC);
+    
+               /* Check the previous instruction */
+               switch (P->OPC) {
+    
+                   case OP65_ADC:
+                   case OP65_AND:
+                   case OP65_DEA:
+                   case OP65_EOR:
+                   case OP65_INA:
+                   case OP65_LDA:
+                   case OP65_ORA:
+                   case OP65_PLA:
+                   case OP65_SBC:
+                       /* A is zero in one execution flow direction */
+                       if (BC == BC_EQ) {
+                           E->RI->Out2.RegA = 0;
+                       } else {
+                           E->RI->Out.RegA = 0;
+                       }
+                       break;
+    
+                   case OP65_CMP:
+                       /* If this is an immidiate compare, the A register has
+                        * the value of the compare later.
+                        */
+                       if (CE_KnownImm (P)) {
+                           if (BC == BC_EQ) {
+                               E->RI->Out2.RegA = (unsigned char)P->Num;
+                           } else {
+                               E->RI->Out.RegA = (unsigned char)P->Num;
+                           }
+                       }
+                       break;
+    
+                   case OP65_CPX:
+                       /* If this is an immidiate compare, the X register has
+                        * the value of the compare later.
+                        */
+                       if (CE_KnownImm (P)) {
+                           if (BC == BC_EQ) {
+                               E->RI->Out2.RegX = (unsigned char)P->Num;
+                           } else {
+                               E->RI->Out.RegX = (unsigned char)P->Num;
+                           }
+                       }
+                       break;
+    
+                   case OP65_CPY:
+                       /* If this is an immidiate compare, the Y register has
+                        * the value of the compare later.
+                        */
+                       if (CE_KnownImm (P)) {
+                           if (BC == BC_EQ) {
+                               E->RI->Out2.RegY = (unsigned char)P->Num;
+                           } else {
+                               E->RI->Out.RegY = (unsigned char)P->Num;
+                           }
+                       }
+                       break;
+    
+                   case OP65_DEX:
+                   case OP65_INX:
+                   case OP65_LDX:
+                   case OP65_PLX:
+                       /* X is zero in one execution flow direction */
+                       if (BC == BC_EQ) {
+                           E->RI->Out2.RegX = 0;
+                       } else {
+                           E->RI->Out.RegX = 0;
+                       }
+                       break;
+    
+                   case OP65_DEY:
+                   case OP65_INY:
+                   case OP65_LDY:
+                   case OP65_PLY:
+                       /* X is zero in one execution flow direction */
+                       if (BC == BC_EQ) {
+                           E->RI->Out2.RegY = 0;
+                       } else {
+                           E->RI->Out.RegY = 0;
+                       }
+                       break;
+    
+                   case OP65_TAX:
+                   case OP65_TXA:
+                       /* If the branch is a beq, both A and X are zero at the
+                        * branch target, otherwise they are zero at the next
+                        * insn.
+                        */
+                       if (BC == BC_EQ) {
+                           E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
+                       } else {
+                           E->RI->Out.RegA = E->RI->Out.RegX = 0;
+                       }
+                       break;
+    
+                   case OP65_TAY:
+                   case OP65_TYA:
+                       /* If the branch is a beq, both A and Y are zero at the
+                        * branch target, otherwise they are zero at the next
+                        * insn.
+                        */
+                       if (BC == BC_EQ) {
+                           E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
+                       } else {
+                           E->RI->Out.RegA = E->RI->Out.RegY = 0;
+                       }
+                       break;
+    
+                   default:
+                       break;
+    
+               }
            }
        }
-    }
+    } while (!Done);
+
 }
 
 
diff --git a/src/cc65/coptc02.c b/src/cc65/coptc02.c
new file mode 100644 (file)
index 0000000..61ab10d
--- /dev/null
@@ -0,0 +1,110 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptc02.h                                 */
+/*                                                                           */
+/*                      65C02 specific 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 "error.h"
+#include "coptc02.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned Opt65C02Ind (CodeSeg* S)
+/* Try to use the indirect addressing mode where possible */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Generate register info for this step */
+    CS_GenRegInfo (S);
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       /* Get next entry */
+               CodeEntry* E = CS_GetEntry (S, I);
+
+               /* Check for addressing mode indirect indexed Y where Y is zero. 
+        * Note: All opcodes that are available as (zp),y are also available
+        * as (zp), so we can ignore the actual opcode here.
+        */
+       if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) {
+
+           /* Replace it by indirect addressing mode */
+           CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_IND, E->Arg, 0, E->LI);
+           CS_InsertEntry (S, X, I+1);
+           CS_DelEntry (S, I);
+
+           /* We had changes */
+           ++Changes;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Free register info */
+    CS_FreeRegInfo (S);
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+
diff --git a/src/cc65/coptc02.h b/src/cc65/coptc02.h
new file mode 100644 (file)
index 0000000..4ad4704
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                coptc02.h                                 */
+/*                                                                           */
+/*                      65C02 specific 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 COPTC02_H
+#define COPTC02_H
+
+
+
+/* cc65 */
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned Opt65C02Ind (CodeSeg* S);
+/* Try to use the indirect addressing mode where possible */
+
+
+
+/* End of coptc02.h */
+#endif
+
+
+
index 9fa674dc42df3465d9d77abcb1532b1a33bb3776..34ab9af3a9b357cdc51b66278f0ae64e579f2810 100644 (file)
@@ -35,6 +35,7 @@ OBJS =        anonname.o      \
        codeseg.o       \
        compile.o       \
        coptadd.o       \
+       coptc02.o       \
        coptcmp.o       \
        coptind.o       \
        coptneg.o       \
index 80527dd400c759fcb2cc6ed9870c0df645069648..2fcc6431b5afd1a9f9705847cad027632915c80a 100644 (file)
@@ -80,6 +80,7 @@ OBJS =        anonname.obj    \
        codeseg.obj     \
        compile.obj     \
        coptadd.obj     \
+       coptc02.obj     \
        coptcmp.obj     \
        coptind.obj     \
        coptneg.obj     \
@@ -157,6 +158,7 @@ FILE codeopt.obj
 FILE codeseg.obj
 FILE compile.obj
 FILE coptadd.obj
+FILE coptc02.obj
 FILE coptcmp.obj
 FILE coptind.obj
 FILE coptneg.obj