Added more optimizations
git-svn-id: svn://svn.cc65.org/cc65/trunk@804 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -67,6 +67,9 @@ struct FuncInfo {
|
|||||||
|
|
||||||
static const FuncInfo FuncInfoTable[] = {
|
static const FuncInfo FuncInfoTable[] = {
|
||||||
{ "addysp", REG_Y, REG_NONE },
|
{ "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 },
|
{ "booleq", REG_NONE, REG_AX },
|
||||||
{ "boolge", REG_NONE, REG_AX },
|
{ "boolge", REG_NONE, REG_AX },
|
||||||
{ "boolgt", REG_NONE, REG_AX },
|
{ "boolgt", REG_NONE, REG_AX },
|
||||||
@@ -77,6 +80,7 @@ static const FuncInfo FuncInfoTable[] = {
|
|||||||
{ "boolugt", REG_NONE, REG_AX },
|
{ "boolugt", REG_NONE, REG_AX },
|
||||||
{ "boolule", REG_NONE, REG_AX },
|
{ "boolule", REG_NONE, REG_AX },
|
||||||
{ "boolult", REG_NONE, REG_AX },
|
{ "boolult", REG_NONE, REG_AX },
|
||||||
|
{ "complax", REG_AX, REG_AX },
|
||||||
{ "decax1", REG_AX, REG_AX },
|
{ "decax1", REG_AX, REG_AX },
|
||||||
{ "decax2", REG_AX, REG_AX },
|
{ "decax2", REG_AX, REG_AX },
|
||||||
{ "decax3", REG_AX, REG_AX },
|
{ "decax3", REG_AX, REG_AX },
|
||||||
@@ -94,6 +98,8 @@ static const FuncInfo FuncInfoTable[] = {
|
|||||||
{ "decsp6", REG_NONE, REG_A },
|
{ "decsp6", REG_NONE, REG_A },
|
||||||
{ "decsp7", REG_NONE, REG_A },
|
{ "decsp7", REG_NONE, REG_A },
|
||||||
{ "decsp8", REG_NONE, REG_A },
|
{ "decsp8", REG_NONE, REG_A },
|
||||||
|
{ "incax1", REG_AX, REG_AX },
|
||||||
|
{ "incax2", REG_AX, REG_AX },
|
||||||
{ "incsp1", REG_NONE, REG_NONE },
|
{ "incsp1", REG_NONE, REG_NONE },
|
||||||
{ "incsp2", REG_NONE, REG_Y },
|
{ "incsp2", REG_NONE, REG_Y },
|
||||||
{ "incsp3", REG_NONE, REG_Y },
|
{ "incsp3", REG_NONE, REG_Y },
|
||||||
@@ -109,12 +115,22 @@ static const FuncInfo FuncInfoTable[] = {
|
|||||||
{ "ldaxidx", REG_AXY, REG_AX },
|
{ "ldaxidx", REG_AXY, REG_AX },
|
||||||
{ "ldaxysp", REG_Y, REG_AX },
|
{ "ldaxysp", REG_Y, REG_AX },
|
||||||
{ "leaasp", REG_A, REG_AX },
|
{ "leaasp", REG_A, REG_AX },
|
||||||
|
{ "negax", REG_AX, REG_AX },
|
||||||
{ "pusha", REG_A, REG_Y },
|
{ "pusha", REG_A, REG_Y },
|
||||||
{ "pusha0", REG_A, REG_XY },
|
{ "pusha0", REG_A, REG_XY },
|
||||||
{ "pushax", REG_AX, REG_Y },
|
{ "pushax", REG_AX, REG_Y },
|
||||||
|
{ "pusheax", REG_AX, REG_Y },
|
||||||
{ "pushw0sp", REG_NONE, REG_AXY },
|
{ "pushw0sp", REG_NONE, REG_AXY },
|
||||||
{ "pushwysp", REG_Y, 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 },
|
{ "tosicmp", REG_AX, REG_AXY },
|
||||||
|
{ "tosshreax", REG_AX, REG_AXY },
|
||||||
};
|
};
|
||||||
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
||||||
|
|
||||||
|
|||||||
@@ -1297,6 +1297,7 @@ static OptFunc OptFuncs [] = {
|
|||||||
/* Remove unused loads */
|
/* Remove unused loads */
|
||||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
||||||
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },
|
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },
|
||||||
|
{ OptStoreLoad, "OptStoreLoad", 0 },
|
||||||
/* Optimize branch distance */
|
/* Optimize branch distance */
|
||||||
{ OptBranchDist, "OptBranchDist", 0 },
|
{ OptBranchDist, "OptBranchDist", 0 },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -797,7 +797,7 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
RegA ^= (int) E->Num;
|
RegA ^= (int) E->Num;
|
||||||
} else {
|
} else {
|
||||||
RegA = -1;
|
RegA = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -994,10 +994,16 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
/* If the value in the Y register is known and the same as
|
/* 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
|
* that in the A register, replace the store by a STA. The
|
||||||
* optimizer will then remove the load instruction for Y
|
* 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) {
|
if (RegY >= 0) {
|
||||||
CE_ReplaceOPC (E, OP65_STA);
|
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;
|
break;
|
||||||
|
|
||||||
@@ -1012,7 +1018,7 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TAY:
|
case OP65_TAY:
|
||||||
N = CS_GetNextEntry (S, I);
|
N = CS_GetNextEntry (S, I);
|
||||||
if (RegA >= 0 && RegA == RegY && N && (N->Info & OF_FBRA) == 0) {
|
if (RegA >= 0 && RegA == RegY && N && (N->Info & OF_FBRA) == 0) {
|
||||||
/* Value is identical and not followed by a branch */
|
/* Value is identical and not followed by a branch */
|
||||||
Delete = 1;
|
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 */
|
/* Optimize branch types */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ unsigned OptUnusedLoads (CodeSeg* S);
|
|||||||
unsigned OptDuplicateLoads (CodeSeg* S);
|
unsigned OptDuplicateLoads (CodeSeg* S);
|
||||||
/* Remove loads of registers where the value loaded is already in the register. */
|
/* 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);
|
unsigned OptBranchDist (CodeSeg* S);
|
||||||
/* Change branches for the distance needed. */
|
/* Change branches for the distance needed. */
|
||||||
|
|
||||||
|
|||||||
@@ -611,21 +611,21 @@ const OPCDesc OPCTable[OPCODE_COUNT] = {
|
|||||||
0, /* size */
|
0, /* size */
|
||||||
REG_A, /* use */
|
REG_A, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_NONE /* flags */
|
OF_STORE /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_STX, /* opcode */
|
{ OP65_STX, /* opcode */
|
||||||
"stx", /* mnemonic */
|
"stx", /* mnemonic */
|
||||||
0, /* size */
|
0, /* size */
|
||||||
REG_X, /* use */
|
REG_X, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_NONE /* flags */
|
OF_STORE /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_STY, /* opcode */
|
{ OP65_STY, /* opcode */
|
||||||
"sty", /* mnemonic */
|
"sty", /* mnemonic */
|
||||||
0, /* size */
|
0, /* size */
|
||||||
REG_Y, /* use */
|
REG_Y, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_NONE /* flags */
|
OF_STORE /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_TAX, /* opcode */
|
{ OP65_TAX, /* opcode */
|
||||||
"tax", /* mnemonic */
|
"tax", /* mnemonic */
|
||||||
|
|||||||
@@ -203,8 +203,9 @@ typedef enum {
|
|||||||
#define OF_LBRA 0x0100U /* Jump/branch is long */
|
#define OF_LBRA 0x0100U /* Jump/branch is long */
|
||||||
#define OF_RET 0x0200U /* Return from function */
|
#define OF_RET 0x0200U /* Return from function */
|
||||||
#define OF_LOAD 0x0400U /* Register load */
|
#define OF_LOAD 0x0400U /* Register load */
|
||||||
#define OF_XFR 0x0800U /* Transfer instruction */
|
#define OF_STORE 0x0800U /* Register store */
|
||||||
#define OF_CALL 0x1000U /* A subroutine call */
|
#define OF_XFR 0x1000U /* Transfer instruction */
|
||||||
|
#define OF_CALL 0x2000U /* A subroutine call */
|
||||||
|
|
||||||
/* Combined infos */
|
/* Combined infos */
|
||||||
#define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */
|
#define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */
|
||||||
|
|||||||
Reference in New Issue
Block a user