From f78237a6a67eae319b50df6cd34c32ed1f05b4d8 Mon Sep 17 00:00:00 2001 From: cuz Date: Tue, 15 May 2001 22:35:38 +0000 Subject: [PATCH] Working on the backend git-svn-id: svn://svn.cc65.org/cc65/trunk@725 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeent.c | 5 +- src/cc65/codeinfo.c | 8 ++- src/cc65/codeopt.c | 2 + src/cc65/codeseg.c | 13 +++- src/cc65/codeseg.h | 11 ++-- src/cc65/coptind.c | 95 ++++++++++++++++++++++++++-- src/cc65/coptind.h | 3 + src/cc65/opcodes.c | 146 ++++++++++++++++++++++---------------------- src/cc65/opcodes.h | 5 +- 9 files changed, 201 insertions(+), 87 deletions(-) diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index 14e9a539d..e77041cd6 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -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 */ diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 84309174b..34905af66 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -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. */ diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index a422c48f6..f6fc0c38e 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -276,6 +276,8 @@ static OptFunc OptFuncs [] = { { OptBoolTransforms, "OptBoolTransforms", 0 }, /* Remove unused loads */ { OptUnusedLoads, "OptUnusedLoads", 0 }, + /* Optimize branch distance */ + { OptBranchDist, "OptBranchDist", 0 }, }; diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 75cc471de..cb9664aeb 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -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; } diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index 0f8bc4d3c..7904baa15 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -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 */ }; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 9a76c1866..7843967db 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -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; +} + + + + + + + diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index 7ade6eeff..bf67a20eb 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -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 */ diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index fb765c296..476f674f4 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -56,79 +56,79 @@ /* 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 }, }; diff --git a/src/cc65/opcodes.h b/src/cc65/opcodes.h index fcd4aa444..c4898b091 100644 --- a/src/cc65/opcodes.h +++ b/src/cc65/opcodes.h @@ -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 */