New optimization
git-svn-id: svn://svn.cc65.org/cc65/trunk@2436 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
6028eaac0c
commit
3499efea8f
3 changed files with 93 additions and 12 deletions
|
@ -1542,7 +1542,8 @@ static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0,
|
||||||
static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptTest1 = { OptTest1, "OptTest1", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptTest1 = { OptTest1, "OptTest1", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptTransfers = { OptTransfers, "OptTransfers", 0, 0, 0, 0, 0, 0 };
|
static OptFunc DOptTransfers1 = { OptTransfers1, "OptTransfers1", 0, 0, 0, 0, 0, 0 };
|
||||||
|
static OptFunc DOptTransfers2 = { OptTransfers2, "OptTransfers2", 60, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptUnusedLoads = { OptUnusedLoads, "OptUnusedLoads", 0, 0, 0, 0, 0, 0 };
|
static OptFunc DOptUnusedLoads = { OptUnusedLoads, "OptUnusedLoads", 0, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0, 0 };
|
static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
@ -1610,7 +1611,8 @@ static OptFunc* OptFuncs[] = {
|
||||||
&DOptSub1,
|
&DOptSub1,
|
||||||
&DOptSub2,
|
&DOptSub2,
|
||||||
&DOptTest1,
|
&DOptTest1,
|
||||||
&DOptTransfers,
|
&DOptTransfers1,
|
||||||
|
&DOptTransfers2,
|
||||||
&DOptUnusedLoads,
|
&DOptUnusedLoads,
|
||||||
&DOptUnusedStores,
|
&DOptUnusedStores,
|
||||||
};
|
};
|
||||||
|
@ -1789,7 +1791,7 @@ static void WriteOptStats (const char* Name)
|
||||||
for (I = 0; I < OPTFUNC_COUNT; ++I) {
|
for (I = 0; I < OPTFUNC_COUNT; ++I) {
|
||||||
const OptFunc* O = OptFuncs[I];
|
const OptFunc* O = OptFuncs[I];
|
||||||
fprintf (F,
|
fprintf (F,
|
||||||
"%-20s %6lu %6lu %6lu %6lu\n",
|
"%-20s %10lu %10lu %10lu %10lu\n",
|
||||||
O->Name,
|
O->Name,
|
||||||
O->TotalRuns,
|
O->TotalRuns,
|
||||||
O->LastRuns,
|
O->LastRuns,
|
||||||
|
@ -1934,7 +1936,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
|
||||||
C += RunOptFunc (S, &DOptUnusedStores, 1);
|
C += RunOptFunc (S, &DOptUnusedStores, 1);
|
||||||
C += RunOptFunc (S, &DOptDupLoads, 1);
|
C += RunOptFunc (S, &DOptDupLoads, 1);
|
||||||
C += RunOptFunc (S, &DOptStoreLoad, 1);
|
C += RunOptFunc (S, &DOptStoreLoad, 1);
|
||||||
C += RunOptFunc (S, &DOptTransfers, 1);
|
C += RunOptFunc (S, &DOptTransfers1, 1);
|
||||||
C += RunOptFunc (S, &DOptPushPop, 1);
|
C += RunOptFunc (S, &DOptPushPop, 1);
|
||||||
|
|
||||||
Changes += C;
|
Changes += C;
|
||||||
|
@ -1981,6 +1983,7 @@ static unsigned RunOptGroup5 (CodeSeg* S)
|
||||||
Changes += RunOptFunc (S, &DOptPush1, 1);
|
Changes += RunOptFunc (S, &DOptPush1, 1);
|
||||||
Changes += RunOptFunc (S, &DOptPush2, 1);
|
Changes += RunOptFunc (S, &DOptPush2, 1);
|
||||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||||
|
Changes += RunOptFunc (S, &DOptTransfers2, 1);
|
||||||
|
|
||||||
/* Return the number of changes */
|
/* Return the number of changes */
|
||||||
return Changes;
|
return Changes;
|
||||||
|
|
|
@ -1065,7 +1065,7 @@ unsigned OptStoreLoad (CodeSeg* S)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned OptTransfers (CodeSeg* S)
|
unsigned OptTransfers1 (CodeSeg* S)
|
||||||
/* Remove transfers from one register to another and back */
|
/* Remove transfers from one register to another and back */
|
||||||
{
|
{
|
||||||
unsigned Changes = 0;
|
unsigned Changes = 0;
|
||||||
|
@ -1081,9 +1081,7 @@ unsigned OptTransfers (CodeSeg* S)
|
||||||
/* Get next entry */
|
/* Get next entry */
|
||||||
CodeEntry* E = CS_GetEntry (S, I);
|
CodeEntry* E = CS_GetEntry (S, I);
|
||||||
|
|
||||||
/* Check if it is a store instruction followed by a load from the
|
/* Check if we have two transfer instructions */
|
||||||
* same address which is itself not followed by a conditional branch.
|
|
||||||
*/
|
|
||||||
if ((E->Info & OF_XFR) != 0 &&
|
if ((E->Info & OF_XFR) != 0 &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
!CE_HasLabel (N) &&
|
!CE_HasLabel (N) &&
|
||||||
|
@ -1135,6 +1133,82 @@ NextEntry:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptTransfers2 (CodeSeg* S)
|
||||||
|
/* Replace loads followed by a register transfer by a load with the second
|
||||||
|
* register if possible.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
unsigned I = 0;
|
||||||
|
while (I < CS_GetEntryCount (S)) {
|
||||||
|
|
||||||
|
CodeEntry* N;
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = CS_GetEntry (S, I);
|
||||||
|
|
||||||
|
/* Check if we have a load followed by a transfer where the loaded
|
||||||
|
* register is not used later.
|
||||||
|
*/
|
||||||
|
if ((E->Info & OF_LOAD) != 0 &&
|
||||||
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
|
!CE_HasLabel (N) &&
|
||||||
|
(N->Info & OF_XFR) != 0 &&
|
||||||
|
GetRegInfo (S, I+2, E->Chg) != E->Chg) {
|
||||||
|
|
||||||
|
CodeEntry* X = 0;
|
||||||
|
|
||||||
|
if (E->OPC == OP65_LDA && N->OPC == OP65_TAX) {
|
||||||
|
/* LDA/TAX - check for the right addressing modes */
|
||||||
|
if (E->AM == AM65_IMM ||
|
||||||
|
E->AM == AM65_ZP ||
|
||||||
|
E->AM == AM65_ABS ||
|
||||||
|
E->AM == AM65_ABSY) {
|
||||||
|
/* Replace */
|
||||||
|
X = NewCodeEntry (OP65_LDX, E->AM, E->Arg, 0, N->LI);
|
||||||
|
}
|
||||||
|
} else if (E->OPC == OP65_LDA && N->OPC == OP65_TAY) {
|
||||||
|
/* LDA/TAY - check for the right addressing modes */
|
||||||
|
if (E->AM == AM65_IMM ||
|
||||||
|
E->AM == AM65_ZP ||
|
||||||
|
E->AM == AM65_ZPX ||
|
||||||
|
E->AM == AM65_ABS ||
|
||||||
|
E->AM == AM65_ABSX) {
|
||||||
|
/* Replace */
|
||||||
|
X = NewCodeEntry (OP65_LDY, E->AM, E->Arg, 0, N->LI);
|
||||||
|
}
|
||||||
|
} else if (E->OPC == OP65_LDY && N->OPC == OP65_TYA) {
|
||||||
|
/* LDY/TYA. LDA supports all addressing modes LDY does */
|
||||||
|
X = NewCodeEntry (OP65_LDA, E->AM, E->Arg, 0, N->LI);
|
||||||
|
} else if (E->OPC == OP65_LDX && N->OPC == OP65_TXA) {
|
||||||
|
/* LDX/TXA. LDA doesn't support zp,y, so we must map it to
|
||||||
|
* abs,y instead.
|
||||||
|
*/
|
||||||
|
am_t AM = (E->AM == AM65_ZPY)? AM65_ABSY : E->AM;
|
||||||
|
X = NewCodeEntry (OP65_LDA, AM, E->Arg, 0, N->LI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a load entry, add it and remove the old stuff */
|
||||||
|
if (X) {
|
||||||
|
CS_InsertEntry (S, X, I+2);
|
||||||
|
CS_DelEntries (S, I, 2);
|
||||||
|
++Changes;
|
||||||
|
--I; /* Correct for one entry less */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned OptPushPop (CodeSeg* S)
|
unsigned OptPushPop (CodeSeg* S)
|
||||||
/* Remove a PHA/PLA sequence were A is not used later */
|
/* Remove a PHA/PLA sequence were A is not used later */
|
||||||
{
|
{
|
||||||
|
@ -1264,7 +1338,6 @@ unsigned OptPrecalc (CodeSeg* S)
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
int R = ZPRegVal (E->Use, In);
|
int R = ZPRegVal (E->Use, In);
|
||||||
if (RegValIsKnown (R)) {
|
if (RegValIsKnown (R)) {
|
||||||
printf ("A: %02X tmp1: %02X\n", In->RegA, R);
|
|
||||||
/* Accu EOR zp with known contents */
|
/* Accu EOR zp with known contents */
|
||||||
Arg = MakeHexArg (In->RegA ^ R);
|
Arg = MakeHexArg (In->RegA ^ R);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,14 @@ unsigned OptDupLoads (CodeSeg* S);
|
||||||
unsigned OptStoreLoad (CodeSeg* S);
|
unsigned OptStoreLoad (CodeSeg* S);
|
||||||
/* Remove a store followed by a load from the same location. */
|
/* Remove a store followed by a load from the same location. */
|
||||||
|
|
||||||
unsigned OptTransfers (CodeSeg* S);
|
unsigned OptTransfers1 (CodeSeg* S);
|
||||||
/* Remove transfers from one register to another and back */
|
/* Remove transfers from one register to another and back */
|
||||||
|
|
||||||
|
unsigned OptTransfers2 (CodeSeg* S);
|
||||||
|
/* Replace loads followed by a register transfer by a load with the second
|
||||||
|
* register if possible.
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned OptPushPop (CodeSeg* S);
|
unsigned OptPushPop (CodeSeg* S);
|
||||||
/* Remove a PHA/PLA sequence were A is not used later */
|
/* Remove a PHA/PLA sequence were A is not used later */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue