1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 19:29:37 +00:00

Working on the backend

git-svn-id: svn://svn.cc65.org/cc65/trunk@725 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-05-15 22:35:38 +00:00
parent 21d41040c9
commit f78237a6a6
9 changed files with 201 additions and 87 deletions

View 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 */

View 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.
*/

View File

@ -276,6 +276,8 @@ static OptFunc OptFuncs [] = {
{ OptBoolTransforms, "OptBoolTransforms", 0 },
/* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 },
/* Optimize branch distance */
{ OptBranchDist, "OptBranchDist", 0 },
};

View 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;
}

View 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 */
};

View 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;
}

View 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 */

View File

@ -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 },
};

View 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 */