mirror of
https://github.com/cc65/cc65.git
synced 2025-04-06 04:41:08 +00:00
Added more optimizations
git-svn-id: svn://svn.cc65.org/cc65/trunk@804 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
e370e447f6
commit
cbdc651884
@ -67,6 +67,9 @@ struct FuncInfo {
|
||||
|
||||
static const FuncInfo FuncInfoTable[] = {
|
||||
{ "addysp", REG_Y, REG_NONE },
|
||||
{ "bnega", REG_A, REG_AX },
|
||||
{ "bnegax", REG_AX, REG_AX },
|
||||
{ "bnegeax", REG_AX, REG_AX },
|
||||
{ "booleq", REG_NONE, REG_AX },
|
||||
{ "boolge", REG_NONE, REG_AX },
|
||||
{ "boolgt", REG_NONE, REG_AX },
|
||||
@ -77,6 +80,7 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
{ "boolugt", REG_NONE, REG_AX },
|
||||
{ "boolule", REG_NONE, REG_AX },
|
||||
{ "boolult", REG_NONE, REG_AX },
|
||||
{ "complax", REG_AX, REG_AX },
|
||||
{ "decax1", REG_AX, REG_AX },
|
||||
{ "decax2", REG_AX, REG_AX },
|
||||
{ "decax3", REG_AX, REG_AX },
|
||||
@ -94,6 +98,8 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
{ "decsp6", REG_NONE, REG_A },
|
||||
{ "decsp7", REG_NONE, REG_A },
|
||||
{ "decsp8", REG_NONE, REG_A },
|
||||
{ "incax1", REG_AX, REG_AX },
|
||||
{ "incax2", REG_AX, REG_AX },
|
||||
{ "incsp1", REG_NONE, REG_NONE },
|
||||
{ "incsp2", REG_NONE, REG_Y },
|
||||
{ "incsp3", REG_NONE, REG_Y },
|
||||
@ -109,12 +115,22 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
{ "ldaxidx", REG_AXY, REG_AX },
|
||||
{ "ldaxysp", REG_Y, REG_AX },
|
||||
{ "leaasp", REG_A, REG_AX },
|
||||
{ "negax", REG_AX, REG_AX },
|
||||
{ "pusha", REG_A, REG_Y },
|
||||
{ "pusha0", REG_A, REG_XY },
|
||||
{ "pushax", REG_AX, REG_Y },
|
||||
{ "pusheax", REG_AX, REG_Y },
|
||||
{ "pushw0sp", REG_NONE, REG_AXY },
|
||||
{ "pushwysp", REG_Y, REG_AXY },
|
||||
{ "shrax1", REG_AX, REG_AX },
|
||||
{ "shrax2", REG_AX, REG_AX },
|
||||
{ "shrax3", REG_AX, REG_AX },
|
||||
{ "shreax1", REG_AX, REG_AX },
|
||||
{ "shreax2", REG_AX, REG_AX },
|
||||
{ "shreax3", REG_AX, REG_AX },
|
||||
{ "staspidx", REG_A | REG_Y, REG_Y },
|
||||
{ "tosicmp", REG_AX, REG_AXY },
|
||||
{ "tosshreax", REG_AX, REG_AXY },
|
||||
};
|
||||
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
||||
|
||||
|
@ -1297,6 +1297,7 @@ static OptFunc OptFuncs [] = {
|
||||
/* Remove unused loads */
|
||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
||||
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },
|
||||
{ OptStoreLoad, "OptStoreLoad", 0 },
|
||||
/* Optimize branch distance */
|
||||
{ OptBranchDist, "OptBranchDist", 0 },
|
||||
};
|
||||
|
@ -682,7 +682,7 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
||||
|
||||
unsigned char Use, Chg;
|
||||
CodeEntry* N;
|
||||
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
@ -797,7 +797,7 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
||||
RegA ^= (int) E->Num;
|
||||
} else {
|
||||
RegA = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -994,10 +994,16 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
||||
/* 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.
|
||||
* later. If replacement by A is not possible try a
|
||||
* replacement by X, but check for invalid addressing modes
|
||||
* in this case.
|
||||
*/
|
||||
if (RegY >= 0 && RegY == RegA) {
|
||||
CE_ReplaceOPC (E, OP65_STA);
|
||||
if (RegY >= 0) {
|
||||
if (RegY == RegA) {
|
||||
CE_ReplaceOPC (E, OP65_STA);
|
||||
} else if (RegY == RegX && E->AM != AM65_ABSX && E->AM != AM65_ZPX) {
|
||||
CE_ReplaceOPC (E, OP65_STX);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1012,7 +1018,7 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
||||
break;
|
||||
|
||||
case OP65_TAY:
|
||||
N = CS_GetNextEntry (S, I);
|
||||
N = CS_GetNextEntry (S, I);
|
||||
if (RegA >= 0 && RegA == RegY && N && (N->Info & OF_FBRA) == 0) {
|
||||
/* Value is identical and not followed by a branch */
|
||||
Delete = 1;
|
||||
@ -1083,6 +1089,50 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
||||
|
||||
|
||||
|
||||
unsigned OptStoreLoad (CodeSeg* S)
|
||||
/* Remove a store followed by a load from the same location. */
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* N;
|
||||
CodeEntry* X;
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if it is a store instruction followed by a load from the
|
||||
* same address which is itself not followed by a conditional branch.
|
||||
*/
|
||||
if ((E->Info & OF_STORE) != 0 &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||
(N->Info & OF_LOAD) != 0 &&
|
||||
strcmp (E->Arg, N->Arg) == 0 &&
|
||||
(X = CS_GetNextEntry (S, I+1)) != 0 &&
|
||||
(X->Info & OF_FBRA) == 0) {
|
||||
|
||||
/* Register value is not used, remove the load */
|
||||
CS_DelEntry (S, I+1);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimize branch types */
|
||||
/*****************************************************************************/
|
||||
|
@ -92,6 +92,9 @@ unsigned OptUnusedLoads (CodeSeg* S);
|
||||
unsigned OptDuplicateLoads (CodeSeg* S);
|
||||
/* Remove loads of registers where the value loaded is already in the register. */
|
||||
|
||||
unsigned OptStoreLoad (CodeSeg* S);
|
||||
/* Remove a store followed by a load from the same location. */
|
||||
|
||||
unsigned OptBranchDist (CodeSeg* S);
|
||||
/* Change branches for the distance needed. */
|
||||
|
||||
|
@ -611,21 +611,21 @@ const OPCDesc OPCTable[OPCODE_COUNT] = {
|
||||
0, /* size */
|
||||
REG_A, /* use */
|
||||
REG_NONE, /* chg */
|
||||
OF_NONE /* flags */
|
||||
OF_STORE /* flags */
|
||||
},
|
||||
{ OP65_STX, /* opcode */
|
||||
"stx", /* mnemonic */
|
||||
0, /* size */
|
||||
REG_X, /* use */
|
||||
REG_NONE, /* chg */
|
||||
OF_NONE /* flags */
|
||||
OF_STORE /* flags */
|
||||
},
|
||||
{ OP65_STY, /* opcode */
|
||||
"sty", /* mnemonic */
|
||||
0, /* size */
|
||||
REG_Y, /* use */
|
||||
REG_NONE, /* chg */
|
||||
OF_NONE /* flags */
|
||||
OF_STORE /* flags */
|
||||
},
|
||||
{ OP65_TAX, /* opcode */
|
||||
"tax", /* mnemonic */
|
||||
|
@ -203,8 +203,9 @@ typedef enum {
|
||||
#define OF_LBRA 0x0100U /* Jump/branch is long */
|
||||
#define OF_RET 0x0200U /* Return from function */
|
||||
#define OF_LOAD 0x0400U /* Register load */
|
||||
#define OF_XFR 0x0800U /* Transfer instruction */
|
||||
#define OF_CALL 0x1000U /* A subroutine call */
|
||||
#define OF_STORE 0x0800U /* Register store */
|
||||
#define OF_XFR 0x1000U /* Transfer instruction */
|
||||
#define OF_CALL 0x2000U /* A subroutine call */
|
||||
|
||||
/* Combined infos */
|
||||
#define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */
|
||||
|
Loading…
x
Reference in New Issue
Block a user