]> git.sur5r.net Git - cc65/commitdiff
Working on the backend
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 15 May 2001 22:35:38 +0000 (22:35 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 15 May 2001 22:35:38 +0000 (22:35 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@725 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/cc65/codeent.c
src/cc65/codeinfo.c
src/cc65/codeopt.c
src/cc65/codeseg.c
src/cc65/codeseg.h
src/cc65/coptind.c
src/cc65/coptind.h
src/cc65/opcodes.c
src/cc65/opcodes.h

index 14e9a539d4a9e1b1b3eec54b29a5a13be28a40f3..e77041cd659d1ce9926f1f49fc7cea782c3caaeb 100644 (file)
@@ -162,11 +162,14 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
     if (E->OPC == OPC_JSR) {
        /* A subroutine call */
        GetFuncInfo (E->Arg, &E->Use, &E->Chg);
+    } else if ((E->Info & OF_BRA) != 0 && JumpTo == 0) {
+       /* Jump to external symbol (function exit) */
+       GetFuncInfo (E->Arg, &E->Use, &E->Chg);
     } else {
        /* Some other instruction */
        E->Use |= GetAMUseInfo (E->AM);
     }
-    E->JumpTo  = JumpTo;
+    E->JumpTo = JumpTo;
     InitCollection (&E->Labels);
 
     /* If we have a label given, add this entry to the label */
index 84309174b54dad0ca41e2c578792c5d740e05912..34905af669313a35906b9ff94dc08caf672e5819 100644 (file)
@@ -176,7 +176,13 @@ static unsigned char GetRegInfo2 (CodeSeg* S,
        CollAppend (Visited, E);
 
        /* Evaluate the used registers */
-       if ((R = E->Use) != REG_NONE) {
+       R = E->Use;
+       if (E->OPC == OPC_RTS ||
+           ((E->Info & OF_BRA) != 0 && E->JumpTo == 0)) {
+           /* This instruction will leave the function */
+           R |= S->ExitRegs;
+       }
+               if (R != REG_NONE) {
            /* We are not interested in the use of any register that has been
             * used before.
             */
index a422c48f690c5bfe7c3d745022d2eb304249de0c..f6fc0c38e9e965ae2565b9c4d9786b7bb3fa26bf 100644 (file)
@@ -276,6 +276,8 @@ static OptFunc OptFuncs [] = {
     { OptBoolTransforms,    "OptBoolTransforms",       0       },
     /* Remove unused loads */
     { OptUnusedLoads,      "OptUnusedLoads",           0       },
+    /* Optimize branch distance */
+    { OptBranchDist,               "OptBranchDist",            0       },
 };
 
 
index 75cc471de5a09ebdd261c2a9c9ddf2715db0f010..cb9664aebcabb6f91c0a847bd976b052a34fa816 100644 (file)
@@ -48,7 +48,9 @@
 #include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
+#include "datatype.h"
 #include "error.h"
+#include "symentry.h"
 #include "codeseg.h"
 
 
@@ -382,7 +384,16 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
        S->LabelHash[I] = 0;
     }
 
-    /* Return the new struct */
+    /* If we have a function given, get the return type of the function.
+     * Assume ANY return type besides void will use the A and X registers.
+     */
+    if (S->Func && !IsTypeVoid (GetFuncReturn (Func->Type))) {
+       S->ExitRegs = REG_AX;
+    } else {
+       S->ExitRegs = REG_NONE;
+    }
+
+    /* Return the new struct */             
     return S;
 }
 
index 0f8bc4d3c00d0c7777bf6812ac29c9709d4f71bc..7904baa15aeab4b920d23dcb327c5a25bbef1d66 100644 (file)
@@ -73,11 +73,12 @@ struct CodeEntry;
 /* Code segment structure */
 typedef struct CodeSeg CodeSeg;
 struct CodeSeg {
-    char*      SegName;                        /* Segment name */
-    SymEntry*  Func;                           /* Owner function */
-    Collection Entries;                        /* List of code entries */
-    Collection Labels;                         /* Labels for next insn */
-    CodeLabel*         LabelHash [CS_LABEL_HASH_SIZE]; /* Label hash table */
+    char*          SegName;                    /* Segment name */
+    SymEntry*      Func;                       /* Owner function */
+    Collection     Entries;                    /* List of code entries */
+    Collection     Labels;                     /* Labels for next insn */
+    CodeLabel*             LabelHash [CS_LABEL_HASH_SIZE]; /* Label hash table */
+    unsigned char   ExitRegs;                  /* Register use on exit */
 };
 
 
index 9a76c186623fef8576d5946469d3ff6d00afb915..7843967dbe30ad6da07342f5a3cc22699f5d2989 100644 (file)
@@ -321,16 +321,19 @@ unsigned OptRTS (CodeSeg* S)
     I = 0;
     while (I < Count-1) {
 
+       CodeEntry* N;
+
        /* Get this entry */
        CodeEntry* E = GetCodeEntry (S, I);
 
        /* Check if it's a subroutine call and if the following insn is RTS */
-       if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
+       if (E->OPC == OPC_JSR                   &&
+           (N = GetNextCodeEntry (S, I)) != 0  &&
+           N->OPC == OPC_RTS) {
 
            /* Change the jsr to a jmp and use the additional info for a jump */
-           E->OPC  = OPC_JMP;
-           E->AM   = AM_BRA;
-           E->Info = GetOPCInfo (OPC_JMP);
+                   E->AM = AM_BRA;
+           ReplaceOPC (E, OPC_JMP);
 
                    /* Remember, we had changes */
            ++Changes;
@@ -620,3 +623,87 @@ NextEntry:
 
 
 
+/*****************************************************************************/
+/*                          Optimize branch types                           */
+/*****************************************************************************/
+
+
+
+unsigned OptBranchDist (CodeSeg* S)
+/* Change branches for the distance needed. */
+{
+    unsigned Changes = 0;
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have not enough */
+    unsigned Count = GetCodeEntryCount (S);
+
+    /* Walk over the entries */
+    I = 0;
+    while (I < Count) {
+
+       /* Get next entry */
+               CodeEntry* E = GetCodeEntry (S, I);
+
+       /* Check if it's a conditional branch to a local label. */
+               if ((E->Info & OF_CBRA) != 0) {
+
+           /* Is this a branch to a local symbol? */
+           if (E->JumpTo != 0) {
+
+               /* Get the index of the branch target */
+               unsigned TI = GetCodeEntryIndex (S, E->JumpTo->Owner);
+
+               /* Determine the branch distance */
+               int Distance = 0;
+               if (TI >= I) {
+                   /* Forward branch */
+                   unsigned J = I;
+                   while (J < TI) {
+                       CodeEntry* N = GetCodeEntry (S, J++);
+                       Distance += N->Size;
+                   }
+               } else {
+                   /* Backward branch */
+                   unsigned J = TI;
+                   while (J < I) {
+                       CodeEntry* N = GetCodeEntry (S, J++);
+                       Distance += N->Size;
+                   }
+               }
+
+               /* Make the branch short/long according to distance */
+               if ((E->Info & OF_LBRA) == 0 && Distance > 120) {
+                   /* Short branch but long distance */
+                   ReplaceOPC (E, MakeLongBranch (E->OPC));
+                   ++Changes;
+               } else if ((E->Info & OF_LBRA) != 0 && Distance < 120) {
+                   /* Long branch but short distance */
+                   ReplaceOPC (E, MakeShortBranch (E->OPC));
+                   ++Changes;
+               }
+
+           } else if ((E->Info & OF_LBRA) == 0) {
+
+               /* Short branch to external symbol - make it long */
+               ReplaceOPC (E, MakeLongBranch (E->OPC));
+               ++Changes;
+
+           }
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+
+    /* Return the number of changes made */
+    return Changes;
+}
+
+
+
+
+
+
+
index 7ade6eeff39a30757536c9108ffb3a080f661427..bf67a20eb4bcd17859959d22753d321ba84e1cdd 100644 (file)
@@ -86,6 +86,9 @@ unsigned OptCondBranches (CodeSeg* S);
 unsigned OptUnusedLoads (CodeSeg* S);
 /* Remove loads of registers where the value loaded is not used later. */
 
+unsigned OptBranchDist (CodeSeg* S);
+/* Change branches for the distance needed. */
+
 
 
 /* End of coptind.h */
index fb765c296005af7560d6df76d0dbf0a5dda3f75d..476f674f49b8733ad7838f51d77173c27b108de6 100644 (file)
 
 /* Mapper table, mnemonic --> opcode */
 static const OPCDesc OPCTable[OPC_COUNT] = {
-    { OPC_ADC, "adc", 0, REG_A,           REG_A,    OF_NONE    },
-    { OPC_AND, "and", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_ASL, "asl", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BIT, "bit", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA   },
-    { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_CMP, "cmp", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_CPX, "cpx", 0, REG_X,    REG_NONE, OF_NONE   },
-    { OPC_CPY, "cpy", 0, REG_Y,    REG_NONE, OF_NONE   },
-    { OPC_DEA, "dea", 1, REG_A,    REG_A,    OF_NONE   },
-    { OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_DEX, "dex", 1, REG_X,    REG_X,    OF_NONE   },
-    { OPC_DEY, "dey", 1, REG_Y,    REG_Y,    OF_NONE   },
-    { OPC_EOR, "eor", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_INA, "ina", 1, REG_A,    REG_A,    OF_NONE   },
-    { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_INX, "inx", 1, REG_X,    REG_X,    OF_NONE   },
-    { OPC_INY, "iny", 1, REG_Y,    REG_Y,    OF_NONE   },
-    { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA           },
-    { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA   },
-    { OPC_LDA, "lda", 0, REG_NONE, REG_A,    OF_LOAD           },
-    { OPC_LDX, "ldx", 0, REG_NONE, REG_X,    OF_LOAD   },
-    { OPC_LDY, "ldy", 0, REG_NONE, REG_Y,    OF_LOAD   },
-    { OPC_LSR, "lsr", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_ORA, "ora", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_PHA, "pha", 1, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_PHX, "phx", 1, REG_X,    REG_NONE, OF_NONE   },
-    { OPC_PHY, "phy", 1, REG_Y,    REG_NONE, OF_NONE   },
-    { OPC_PLA, "pla", 1, REG_NONE, REG_A,    OF_NONE   },
-    { OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_PLX, "plx", 1, REG_NONE, REG_X,    OF_NONE   },
-    { OPC_PLY, "ply", 1, REG_NONE, REG_Y,    OF_NONE   },
-    { OPC_ROL, "rol", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_ROR, "ror", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET    },
-    { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET    },
-    { OPC_SBC, "sbc", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_STA, "sta", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_STX, "stx", 0, REG_X,    REG_NONE, OF_NONE   },
-    { OPC_STY, "sty", 0, REG_Y,    REG_NONE, OF_NONE   },
-    { OPC_TAX, "tax", 1, REG_A,    REG_X,    OF_NONE   },
-    { OPC_TAY, "tay", 1, REG_A,    REG_Y,    OF_NONE   },
-    { OPC_TRB, "trb", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_TSB, "tsb", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_TSX, "tsx", 1, REG_NONE, REG_X,    OF_NONE   },
-    { OPC_TXA, "txa", 1, REG_X,    REG_A,    OF_NONE   },
-    { OPC_TXS, "txs", 1, REG_X,    REG_NONE, OF_NONE   },
-    { OPC_TYA, "tya", 1, REG_A,    REG_A,    OF_NONE   },
+    { OPC_ADC, "adc", 0, REG_A,           REG_A,    OF_NONE            },
+    { OPC_AND, "and", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_ASL, "asl", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BIT, "bit", 0, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA           },
+    { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA           },
+    { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_CMP, "cmp", 0, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_CPX, "cpx", 0, REG_X,    REG_NONE, OF_NONE           },
+    { OPC_CPY, "cpy", 0, REG_Y,    REG_NONE, OF_NONE           },
+    { OPC_DEA, "dea", 1, REG_A,    REG_A,    OF_NONE           },
+    { OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_DEX, "dex", 1, REG_X,    REG_X,    OF_NONE           },
+    { OPC_DEY, "dey", 1, REG_Y,    REG_Y,    OF_NONE           },
+    { OPC_EOR, "eor", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_INA, "ina", 1, REG_A,    REG_A,    OF_NONE           },
+    { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_INX, "inx", 1, REG_X,    REG_X,    OF_NONE           },
+    { OPC_INY, "iny", 1, REG_Y,    REG_Y,    OF_NONE           },
+    { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA  },
+    { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA  },
+    { OPC_LDA, "lda", 0, REG_NONE, REG_A,    OF_LOAD                   },
+    { OPC_LDX, "ldx", 0, REG_NONE, REG_X,    OF_LOAD           },
+    { OPC_LDY, "ldy", 0, REG_NONE, REG_Y,    OF_LOAD           },
+    { OPC_LSR, "lsr", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_ORA, "ora", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_PHA, "pha", 1, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_PHX, "phx", 1, REG_X,    REG_NONE, OF_NONE           },
+    { OPC_PHY, "phy", 1, REG_Y,    REG_NONE, OF_NONE           },
+    { OPC_PLA, "pla", 1, REG_NONE, REG_A,    OF_NONE           },
+    { OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_PLX, "plx", 1, REG_NONE, REG_X,    OF_NONE           },
+    { OPC_PLY, "ply", 1, REG_NONE, REG_Y,    OF_NONE           },
+    { OPC_ROL, "rol", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_ROR, "ror", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET            },
+    { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET            },
+    { OPC_SBC, "sbc", 0, REG_A,    REG_A,    OF_NONE           },
+    { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE           },
+    { OPC_STA, "sta", 0, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_STX, "stx", 0, REG_X,    REG_NONE, OF_NONE           },
+    { OPC_STY, "sty", 0, REG_Y,    REG_NONE, OF_NONE           },
+    { OPC_TAX, "tax", 1, REG_A,    REG_X,    OF_NONE           },
+    { OPC_TAY, "tay", 1, REG_A,    REG_Y,    OF_NONE           },
+    { OPC_TRB, "trb", 0, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_TSB, "tsb", 0, REG_A,    REG_NONE, OF_NONE           },
+    { OPC_TSX, "tsx", 1, REG_NONE, REG_X,    OF_NONE           },
+    { OPC_TXA, "txa", 1, REG_X,    REG_A,    OF_NONE           },
+    { OPC_TXS, "txs", 1, REG_X,    REG_NONE, OF_NONE           },
+    { OPC_TYA, "tya", 1, REG_A,    REG_A,    OF_NONE           },
 };
 
 
index fcd4aa4444f5365026e678fe3e13924a81de11d6..c4898b09122d18b99ab0000fd4422e284bbf35f3 100644 (file)
@@ -155,8 +155,9 @@ typedef enum {
 #define OF_NONE        0x0000U                 /* No additional information */
 #define OF_UBRA        0x0001U                 /* Unconditional branch */
 #define OF_CBRA        0x0002U                 /* Conditional branch */
-#define OF_RET         0x0004U                 /* Return from function */
-#define OF_LOAD 0x0008U                        /* Register load */
+#define OF_LBRA 0x0004U                        /* Jump/branch is long */
+#define OF_RET         0x0010U                 /* Return from function */
+#define OF_LOAD 0x0020U                        /* Register load */
 #define OF_BRA         (OF_UBRA|OF_CBRA)       /* Operation is a jump/branch */
 #define OF_DEAD        (OF_UBRA|OF_RET)        /* Dead end - no exec behind this point */