]> git.sur5r.net Git - cc65/commitdiff
Trace register usage, remove duplicate loads
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Mon, 16 Jul 2001 16:32:14 +0000 (16:32 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Mon, 16 Jul 2001 16:32:14 +0000 (16:32 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@793 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeopt.c
src/cc65/coptind.c
src/cc65/coptind.h
src/cc65/opcodes.h

index c91e15ace151874452cea83822c4113601a4c55a..470836942a82b92d81e25670a3e8a82d38e7217a 100644 (file)
@@ -1296,6 +1296,7 @@ static OptFunc OptFuncs [] = {
     { OptCmp5,              "OptCmp5",                  0       },
     /* Remove unused loads */
     { OptUnusedLoads,      "OptUnusedLoads",           0       },
+    { OptDuplicateLoads,    "OptDuplicateLoads",        0       },
     /* Optimize branch distance */
     { OptBranchDist,               "OptBranchDist",            0       },
 };
index 83311684744ccb587618ac676c6321ab3d9549b6..4fbad2bbcc8628791da27e805e2a149e25919a20 100644 (file)
 
 
 
+/*****************************************************************************/
+/*                                 Macros                                   */
+/*****************************************************************************/
+
+
+
+/* Macro to increment and decrement register contents if they're valid */
+#define INC(reg,val)    if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
+#define DEC(reg,val)           if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
+
+
+
+/*****************************************************************************/
+/*                                 Helpers                                  */
+/*****************************************************************************/
+
+
+
+static int IsKnownImm (const CodeEntry* E)
+/* Return true if the argument of E is a known immediate value */
+{
+    return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
+}
+
+
+
 /*****************************************************************************/
 /*                       Replace jumps to RTS by RTS                        */
 /*****************************************************************************/
@@ -606,20 +632,20 @@ unsigned OptUnusedLoads (CodeSeg* S)
            /* Check which sort of load or transfer it is */
            unsigned R;
            switch (E->OPC) {
-               case OP65_TXA:
-               case OP65_TYA:
-               case OP65_LDA:  R = REG_A;      break;
-               case OP65_TAX:
+               case OP65_TXA:
+               case OP65_TYA:
+               case OP65_LDA:  R = REG_A;      break;
+               case OP65_TAX:
                        case OP65_LDX:  R = REG_X;      break;
-               case OP65_TAY:
-               case OP65_LDY:  R = REG_Y;      break;
-               default:        goto NextEntry;         /* OOPS */
+               case OP65_TAY:
+               case OP65_LDY:  R = REG_Y;      break;
+               default:        goto NextEntry;         /* OOPS */
            }
 
            /* Get register usage and check if the register value is used later */
            if ((GetRegInfo (S, I+1) & R) == 0) {
 
-               /* Register value is not used, remove the load */
+               /* Register value is not used, remove the load */
                CS_DelEntry (S, I);
 
                /* Remember, we had changes */
@@ -629,8 +655,400 @@ unsigned OptUnusedLoads (CodeSeg* S)
        }
 
 NextEntry:
-       /* Next entry */
-       ++I;
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+unsigned OptDuplicateLoads (CodeSeg* S)
+/* Remove loads of registers where the value loaded is already in the register. */
+{
+    unsigned Changes = 0;
+
+    /* Remember the last load instructions for all registers */
+    int RegA = -1;
+    int RegX = -1;
+    int RegY = -1;
+
+    /* Walk over the entries */
+    unsigned I = 0;
+    while (I < CS_GetEntryCount (S)) {
+
+       unsigned char Use, Chg;
+
+       /* Get next entry */
+               CodeEntry* E = CS_GetEntry (S, I);
+
+       /* Assume we won't delete the entry */
+       int Delete = 0;
+
+       /* If this entry has a label attached, remove all knownledge about the
+                * register contents. This may be improved but for now it's ok.
+        */
+       if (CE_HasLabel (E)) {
+           RegA = RegX = RegY = -1;
+       }
+
+       /* Handle the different instructions */
+       switch (E->OPC) {
+
+           case OP65_ADC:
+               /* We don't know the value of the carry, so the result is
+                * always unknown.
+                */
+               RegA = -1;
+               break;
+
+           case OP65_AND:
+               if (RegA >= 0) {
+                           if (IsKnownImm (E)) {
+                       RegA &= (int) E->Num;
+                   } else {
+                       RegA = -1;
+                   }
+               }
+               break;
+
+           case OP65_ASL:
+               if (RegA >= 0) {
+                   RegA = (RegA << 1) & 0xFF;
+               }
+               break;
+
+           case OP65_BCC:
+               break;
+
+           case OP65_BCS:
+               break;
+
+           case OP65_BEQ:
+               break;
+
+           case OP65_BIT:
+               break;
+
+           case OP65_BMI:
+               break;
+
+           case OP65_BNE:
+               break;
+
+           case OP65_BPL:
+               break;
+
+           case OP65_BRA:
+               break;
+
+           case OP65_BRK:
+               break;
+
+           case OP65_BVC:
+               break;
+
+           case OP65_BVS:
+               break;
+
+           case OP65_CLC:
+               break;
+
+           case OP65_CLD:
+               break;
+
+           case OP65_CLI:
+               break;
+
+           case OP65_CLV:
+               break;
+
+           case OP65_CMP:
+               break;
+
+           case OP65_CPX:
+               break;
+
+           case OP65_CPY:
+               break;
+
+           case OP65_DEA:
+               DEC (RegA, 1);
+               break;
+
+           case OP65_DEC:
+               break;
+
+           case OP65_DEX:
+               DEC (RegX, 1);
+               break;
+
+           case OP65_DEY:
+               DEC (RegY, 1);
+               break;
+
+           case OP65_EOR:
+               if (RegA >= 0) {
+                           if (IsKnownImm (E)) {
+                               RegA ^= (int) E->Num;
+                   } else {
+                       RegA = -1;
+                   }
+               }
+               break;
+
+           case OP65_INA:
+               INC (RegA, 1);
+               break;
+
+           case OP65_INC:
+               break;
+
+           case OP65_INX:
+               INC (RegX, 1);
+               break;
+
+           case OP65_INY:
+               INC (RegY, 1);
+               break;
+
+           case OP65_JCC:
+               break;
+
+           case OP65_JCS:
+               break;
+
+           case OP65_JEQ:
+               break;
+
+           case OP65_JMI:
+               break;
+
+           case OP65_JMP:
+               break;
+
+           case OP65_JNE:
+               break;
+
+           case OP65_JPL:
+               break;
+
+           case OP65_JSR:
+               /* Get the code info for the function */
+               GetFuncInfo (E->Arg, &Use, &Chg);
+               if (Chg & REG_A) {
+                   RegA = -1;
+               }
+               if (Chg & REG_X) {
+                   RegX = -1;
+               }
+               if (Chg & REG_Y) {
+                   RegY = -1;
+               }
+               break;
+
+           case OP65_JVC:
+               break;
+
+           case OP65_JVS:
+               break;
+
+           case OP65_LDA:
+               if (IsKnownImm (E)) {
+                   CodeEntry* N = CS_GetNextEntry (S, I);
+                   if (RegA >= 0 && RegA == E->Num && N && (N->Info & OF_FBRA) == 0) {
+                       Delete = 1;
+                   } else {
+                       RegA = (unsigned char) E->Num;
+                   }
+               } else {
+                   /* A is now unknown */
+                   RegA = -1;
+               }
+               break;
+
+           case OP65_LDX:
+               if (IsKnownImm (E)) {
+                   CodeEntry* N = CS_GetNextEntry (S, I);
+                           if (RegX >= 0 && RegX == E->Num && N && (N->Info & OF_FBRA) == 0) {
+                       Delete = 1;
+                   } else {
+                       RegX = (unsigned char) E->Num;
+                   }
+               } else {
+                   /* X is now unknown */
+                   RegX = -1;
+               }
+               break;
+
+           case OP65_LDY:
+               if (IsKnownImm (E)) {
+                   CodeEntry* N = CS_GetNextEntry (S, I);
+                           if (RegY >= 0 && RegY == E->Num && N && (N->Info & OF_FBRA) == 0) {
+                       Delete = 1;
+                   } else {
+                       RegY = (unsigned char) E->Num;
+                   }
+               } else {
+                   /* Y is now unknown */
+                   RegY = -1;
+               }
+               break;
+
+           case OP65_LSR:
+               if (RegA >= 0) {
+                   RegA = (RegA >> 1) & 0xFF;
+               }
+               break;
+
+           case OP65_NOP:
+               break;
+
+           case OP65_ORA:
+               if (RegA >= 0) {
+                   if (IsKnownImm (E)) {
+                       RegA |= (unsigned char) E->Num;
+                   } else {
+                       /* A is now unknown */
+                       RegA = -1;
+                   }
+               }
+               break;
+
+           case OP65_PHA:
+               break;
+
+           case OP65_PHP:
+               break;
+
+           case OP65_PHX:
+               break;
+
+           case OP65_PHY:
+               break;
+
+           case OP65_PLA:
+               RegA = -1;
+               break;
+
+           case OP65_PLP:
+               break;
+
+           case OP65_PLX:
+               RegX = -1;
+               break;
+
+           case OP65_PLY:
+               RegY = -1;
+               break;
+
+           case OP65_ROL:
+               RegA = -1;
+               break;
+
+           case OP65_ROR:
+               RegA = -1;
+               break;
+
+           case OP65_RTI:
+               break;
+
+           case OP65_RTS:
+               break;
+
+           case OP65_SBC:
+               RegA = -1;
+               break;
+
+           case OP65_SEC:
+               break;
+
+           case OP65_SED:
+               break;
+
+           case OP65_SEI:
+               break;
+
+           case OP65_STA:
+               break;
+
+           case OP65_STX:
+               /* If the value in the X register is known and the same as
+                * that in the A register, replace the store by a STA. The
+                * optimizer will then remove the load instruction for X
+                * later. STX does support the zeropage,y addressing mode,
+                * so be sure to check for that.
+                */
+               if (RegX >= 0 && RegX == RegA &&
+                   E->AM != AM65_ABSY && E->AM != AM65_ZPY) {
+                   /* Use the A register instead */
+                   CE_ReplaceOPC (E, OP65_STA);
+               }
+               break;
+
+           case OP65_STY:
+               /* If the value in the Y register is known and the same as
+                * that in the A register, replace the store by a STA. The
+                * optimizer will then remove the load instruction for Y
+                * later.
+                */
+                       if (RegY >= 0 && RegY == RegA) {
+                   CE_ReplaceOPC (E, OP65_STA);
+               }
+               break;
+
+           case OP65_TAX:
+               RegX = RegA;
+               break;
+
+           case OP65_TAY:
+               RegY = RegA;
+               break;
+
+           case OP65_TRB:
+               break;
+
+           case OP65_TSB:
+               break;
+
+           case OP65_TSX:
+               RegX = -1;
+               break;
+
+           case OP65_TXA:
+               RegA = RegX;
+               break;
+
+           case OP65_TXS:
+               break;
+
+           case OP65_TYA:
+               RegA = RegY;
+               break;
+
+           default:
+               break;
+
+       }
+
+       /* Delete the entry if requested */
+       if (Delete) {
+
+           /* Register value is not used, remove the load */
+           CS_DelEntry (S, I);
+
+           /* Remember, we had changes */
+           ++Changes;
+
+       } else {
+
+           /* Next entry */
+           ++I;
+
+       }
 
     }
 
@@ -678,7 +1096,7 @@ unsigned OptBranchDist (CodeSeg* S)
                    unsigned J = I;
                    while (J < TI) {
                        CodeEntry* N = CS_GetEntry (S, J++);
-                       Distance += N->Size;
+                       Distance += N->Size;
                    }
                } else {
                    /* Backward branch */
index d0afc5c0f7fe2f06407bb48ce649c2acd7c291e0..a5bb5635b8c6cbc34392db819a3d5acdc4da5a31 100644 (file)
@@ -51,7 +51,7 @@
 unsigned OptRTSJumps (CodeSeg* S);
 /* Replace jumps to RTS by RTS */
 
-unsigned OptDeadJumps (CodeSeg* S); 
+unsigned OptDeadJumps (CodeSeg* S);
 /* Remove dead jumps (jumps to the next instruction) */
 
 unsigned OptDeadCode (CodeSeg* S);
@@ -89,6 +89,9 @@ unsigned OptCondBranches (CodeSeg* S);
 unsigned OptUnusedLoads (CodeSeg* S);
 /* Remove loads of registers where the value loaded is not used later. */
 
+unsigned OptDuplicateLoads (CodeSeg* S);
+/* Remove loads of registers where the value loaded is already in the register. */
+
 unsigned OptBranchDist (CodeSeg* S);
 /* Change branches for the distance needed. */
 
index c81c978f510347f1ccde9e9b1f1b59ac1539c54f..e2369aa19da90761bd17d9c2b2c4726e5e43625d 100644 (file)
@@ -169,6 +169,7 @@ typedef enum {
     AM65_IMM,                  /* immidiate */
     AM65_ZP,                   /* zeropage */
     AM65_ZPX,                  /* zeropage,X */
+    AM65_ZPY,                   /* zeropage,Y */
     AM65_ABS,                  /* absolute */
     AM65_ABSX,                 /* absolute,X */
     AM65_ABSY,                 /* absolute,Y */