Added optimizations for commutative arithmetic ops
git-svn-id: svn://svn.cc65.org/cc65/trunk@469 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -177,6 +177,8 @@ static const struct {
|
|||||||
{ "\tstz\t", 0, REG_NONE, REG_NONE },
|
{ "\tstz\t", 0, REG_NONE, REG_NONE },
|
||||||
{ "\ttax", 1, REG_A, REG_X },
|
{ "\ttax", 1, REG_A, REG_X },
|
||||||
{ "\ttay", 1, REG_A, REG_Y },
|
{ "\ttay", 1, REG_A, REG_Y },
|
||||||
|
{ "\ttrb\t", 0, REG_A, REG_NONE },
|
||||||
|
{ "\ttsb\t", 0, REG_A, REG_NONE },
|
||||||
{ "\ttsx", 1, REG_NONE, REG_X },
|
{ "\ttsx", 1, REG_NONE, REG_X },
|
||||||
{ "\ttxa", 1, REG_X, REG_A },
|
{ "\ttxa", 1, REG_X, REG_A },
|
||||||
{ "\ttya", 1, REG_Y, REG_A },
|
{ "\ttya", 1, REG_Y, REG_A },
|
||||||
@@ -3304,7 +3306,7 @@ static void OptTests (void)
|
|||||||
{
|
{
|
||||||
Line* L2 [2];
|
Line* L2 [2];
|
||||||
|
|
||||||
const char* BitOps [] = {
|
static const char* BitOps [] = {
|
||||||
"\tand\t",
|
"\tand\t",
|
||||||
"\tora\t",
|
"\tora\t",
|
||||||
"\teor\t",
|
"\teor\t",
|
||||||
@@ -3401,6 +3403,127 @@ static void OptTests (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OptBitOps (void)
|
||||||
|
/* Optimize bit oeprations */
|
||||||
|
{
|
||||||
|
Line* L2 [2];
|
||||||
|
|
||||||
|
/* Walk over the code */
|
||||||
|
Line* L = FirstCode;
|
||||||
|
while (L) {
|
||||||
|
|
||||||
|
/* Search for
|
||||||
|
*
|
||||||
|
* lda xxx
|
||||||
|
* and #$yy ; adc/eor/ora
|
||||||
|
* sta xxx
|
||||||
|
*
|
||||||
|
* and replace it by
|
||||||
|
*
|
||||||
|
* lda #$yy
|
||||||
|
* and xxx
|
||||||
|
* sta xxx
|
||||||
|
*
|
||||||
|
* While this saves nothing here, it transforms the code to contain an
|
||||||
|
* explicit register load that may be removed by the basic block
|
||||||
|
* optimization later. As a special optimization for the 65C02, the
|
||||||
|
* "ora" and "and" ops may be replaced by "trb" and "tsb" resp. if the
|
||||||
|
* value in A is not used later.
|
||||||
|
*/
|
||||||
|
if (LineMatch (L, "\tlda\t") &&
|
||||||
|
L->Line[5] != '#' &&
|
||||||
|
GetNextCodeLines (L, L2, 2) &&
|
||||||
|
LineMatch (L2[1], "\tsta\t") &&
|
||||||
|
strcmp (L->Line+5, L2[1]->Line+5) == 0) {
|
||||||
|
|
||||||
|
if (LineMatch (L2[0], "\tand\t#$")) {
|
||||||
|
|
||||||
|
unsigned Val = GetHexNum (L2[0]->Line+7);
|
||||||
|
if (Val == 0x00) {
|
||||||
|
|
||||||
|
/* AND with 0x00, remove the mem access */
|
||||||
|
FreeLine (L);
|
||||||
|
FreeLine (L2[1]);
|
||||||
|
|
||||||
|
/* Replace the AND by a load */
|
||||||
|
L = ReplaceLine (L2[0], "\tlda\t#$%02X", Val);
|
||||||
|
|
||||||
|
} else if (Val == 0xFF) {
|
||||||
|
|
||||||
|
/* AND with 0xFF, just load the value from memory */
|
||||||
|
FreeLines (L2[0], L2[1]);
|
||||||
|
|
||||||
|
} else if (CPU == CPU_65C02 &&
|
||||||
|
!IsXAddrMode (L) &&
|
||||||
|
!IsYAddrMode (L) &&
|
||||||
|
!RegAUsed (L2[1])) {
|
||||||
|
|
||||||
|
/* Replace by trb */
|
||||||
|
ReplaceLine (L, "\tlda\t#$%02X", (~Val) & 0xFF);
|
||||||
|
ReplaceLine (L2[0], "\ttrb\t%s", L2[1]->Line+5);
|
||||||
|
FreeLine (L2[1]);
|
||||||
|
L = L2[0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Just reorder */
|
||||||
|
L = ReplaceLine (L, "\tlda\t#$%02X", Val);
|
||||||
|
ReplaceLine (L2[0], "\tand\t%s", L2[1]->Line+5);
|
||||||
|
L = L2[1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (LineMatch (L2[0], "\tora\t#$")) {
|
||||||
|
|
||||||
|
unsigned Val = GetHexNum (L2[0]->Line+7);
|
||||||
|
if (Val == 0x00) {
|
||||||
|
|
||||||
|
/* ORA with 0x00, just load the value from memory */
|
||||||
|
FreeLines (L2[0], L2[1]);
|
||||||
|
|
||||||
|
} else if (Val == 0xFF) {
|
||||||
|
|
||||||
|
/* ORA with 0xFF, replace by a store of $FF */
|
||||||
|
FreeLine (L);
|
||||||
|
ReplaceLine (L2[0], "\tlda\t#$FF");
|
||||||
|
|
||||||
|
} else if (CPU == CPU_65C02 &&
|
||||||
|
!IsXAddrMode (L) &&
|
||||||
|
!IsYAddrMode (L) &&
|
||||||
|
!RegAUsed (L2[1])) {
|
||||||
|
|
||||||
|
/* Replace by trb */
|
||||||
|
ReplaceLine (L, "\tlda\t#$%02X", Val);
|
||||||
|
ReplaceLine (L2[0], "\ttsb\t%s", L2[1]->Line+5);
|
||||||
|
FreeLine (L2[1]);
|
||||||
|
L = L2[0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Just reorder */
|
||||||
|
L = ReplaceLine (L, "\tlda\t#$%02X", Val);
|
||||||
|
ReplaceLine (L2[0], "\tora\t%s", L2[1]->Line+5);
|
||||||
|
L = L2[1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (LineMatch (L2[0], "\teor\t#$") ||
|
||||||
|
LineMatch (L2[0], "\tadc\t#$")) {
|
||||||
|
|
||||||
|
/* Just reorder */
|
||||||
|
L = ReplaceLine (L, "\tlda\t%s", L2[0]->Line+5);
|
||||||
|
ReplaceLine (L2[0], "\t%.3s\t%s", L2[0]->Line+1, L2[1]->Line+5);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next line */
|
||||||
|
L = NextCodeLine (L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptNeg (void)
|
static void OptNeg (void)
|
||||||
/* Optimize the "bnegax/jeq" and "bnegax/jne" sequences */
|
/* Optimize the "bnegax/jeq" and "bnegax/jne" sequences */
|
||||||
{
|
{
|
||||||
@@ -4268,21 +4391,37 @@ static void OptRTS (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptOnePass (unsigned long Flag, void (*F) (void))
|
|
||||||
/* Call one optimizer pass if enabled */
|
|
||||||
{
|
|
||||||
if ((OptDisable & Flag) == 0) {
|
|
||||||
F ();
|
|
||||||
} else if (Verbose || Debug) {
|
|
||||||
printf ("Optimizer pass %04lX skipped\n", Flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OptDoOpt (void)
|
void OptDoOpt (void)
|
||||||
/* Run the optimizer over the collected stuff */
|
/* Run the optimizer over the collected stuff */
|
||||||
{
|
{
|
||||||
|
typedef void (*OptFunc)(void);
|
||||||
|
|
||||||
|
/* Table with optimizer steps - are called in this order */
|
||||||
|
static const OptFunc OptFuncs [] = {
|
||||||
|
OptCompares1, /* Optimize compares - first step */
|
||||||
|
OptDeadJumps, /* Remove dead jumps */
|
||||||
|
OptLoads, /* Remove unnecessary loads */
|
||||||
|
OptRegLoads, /* Remove unnecessary register loads */
|
||||||
|
OptPtrOps, /* Optimize stores through pointers */
|
||||||
|
OptRegVars, /* Optimize use of register variables */
|
||||||
|
OptDoubleJumps, /* Remove jump cascades - must be used before OptNeg */
|
||||||
|
OptNeg, /* Remove unnecessary boolean negates */
|
||||||
|
OptJumpRTS, /* Replace jumps to an RTS by an RTS */
|
||||||
|
OptBoolTransforms, /* Optimize boolean transforms */
|
||||||
|
OptCompares2, /* Optimize compares */
|
||||||
|
OptTests, /* Remove unnecessary tests */
|
||||||
|
OptBitOps, /* Optimize bit operations */
|
||||||
|
OptTriples, /* Optimize several triples */
|
||||||
|
OptBlocks, /* Optimize basic blocks */
|
||||||
|
OptRegLoads, /* Remove unnecessary register loads (another pass) */
|
||||||
|
OptBlocks, /* Optimize basic blocks */
|
||||||
|
OptJumps, /* Optimize jumps */
|
||||||
|
OptRTS, /* Optimize jsr/rts sequences */
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long Flags;
|
||||||
|
unsigned I;
|
||||||
|
|
||||||
/* Find and remember the first line of code */
|
/* Find and remember the first line of code */
|
||||||
FindCodeStart ();
|
FindCodeStart ();
|
||||||
|
|
||||||
@@ -4293,57 +4432,14 @@ void OptDoOpt (void)
|
|||||||
CreateLabelList ();
|
CreateLabelList ();
|
||||||
|
|
||||||
/* Ok, now start the real optimizations */
|
/* Ok, now start the real optimizations */
|
||||||
|
Flags = 1UL;
|
||||||
/* Optimize compares - first step */
|
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||||
OptOnePass (0x0001, OptCompares1);
|
if ((OptDisable & Flags) == 0) {
|
||||||
|
OptFuncs[I] ();
|
||||||
/* Remove dead jumps */
|
} else if (Verbose || Debug) {
|
||||||
OptOnePass (0x0002, OptDeadJumps);
|
printf ("Optimizer pass %u skipped\n", I);
|
||||||
|
}
|
||||||
/* Remove unnecessary loads */
|
}
|
||||||
OptOnePass (0x0004, OptLoads);
|
|
||||||
|
|
||||||
/* Remove unnecessary register loads */
|
|
||||||
OptOnePass (0x0008, OptRegLoads);
|
|
||||||
|
|
||||||
/* Optimize stores through pointers */
|
|
||||||
OptOnePass (0x0010, OptPtrOps);
|
|
||||||
|
|
||||||
/* Optimize use of register variables */
|
|
||||||
OptOnePass (0x0020, OptRegVars);
|
|
||||||
|
|
||||||
/* Remove jump cascades - must be used before OptNeg */
|
|
||||||
OptOnePass (0x0040, OptDoubleJumps);
|
|
||||||
|
|
||||||
/* Remove unnecessary boolean negates */
|
|
||||||
OptOnePass (0x0080, OptNeg);
|
|
||||||
|
|
||||||
/* Replace jumps to an RTS by an RTS */
|
|
||||||
OptOnePass (0x0100, OptJumpRTS);
|
|
||||||
|
|
||||||
/* Optimize boolean transforms */
|
|
||||||
OptOnePass (0x0200, OptBoolTransforms);
|
|
||||||
|
|
||||||
/* Optimize compares */
|
|
||||||
OptOnePass (0x0400, OptCompares2);
|
|
||||||
|
|
||||||
/* Remove unnecessary tests */
|
|
||||||
OptOnePass (0x0800, OptTests);
|
|
||||||
|
|
||||||
/* Optimize several triples */
|
|
||||||
OptOnePass (0x1000, OptTriples);
|
|
||||||
|
|
||||||
/* Optimize basic blocks */
|
|
||||||
OptOnePass (0x2000, OptBlocks);
|
|
||||||
|
|
||||||
/* Remove unnecessary register loads (another pass) */
|
|
||||||
OptOnePass (0x0008, OptRegLoads);
|
|
||||||
|
|
||||||
/* Optimize jumps */
|
|
||||||
OptOnePass (0x4000, OptJumps);
|
|
||||||
|
|
||||||
/* Optimize jsr/rts sequences */
|
|
||||||
OptOnePass (0x8000, OptRTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user