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,6 +162,9 @@ 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);

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,6 +384,15 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
S->LabelHash[I] = 0;
}
/* 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

@@ -78,6 +78,7 @@ struct CodeSeg {
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);
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

@@ -86,16 +86,16 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
{ 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_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 },
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA },
{ 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 },

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