Transform tosshlax and friends into a sequence that doesn't use the stack if
possible. git-svn-id: svn://svn.cc65.org/cc65/trunk@5764 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -1606,7 +1606,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
|
|||||||
C += RunOptFunc (S, &DOptBNegA2, 1);
|
C += RunOptFunc (S, &DOptBNegA2, 1);
|
||||||
C += RunOptFunc (S, &DOptNegAX1, 1);
|
C += RunOptFunc (S, &DOptNegAX1, 1);
|
||||||
C += RunOptFunc (S, &DOptNegAX2, 1);
|
C += RunOptFunc (S, &DOptNegAX2, 1);
|
||||||
C += RunOptFunc (S, &DOptStackOps, 1);
|
C += RunOptFunc (S, &DOptStackOps, 3);
|
||||||
C += RunOptFunc (S, &DOptSub1, 1);
|
C += RunOptFunc (S, &DOptSub1, 1);
|
||||||
C += RunOptFunc (S, &DOptSub2, 1);
|
C += RunOptFunc (S, &DOptSub2, 1);
|
||||||
C += RunOptFunc (S, &DOptSub3, 1);
|
C += RunOptFunc (S, &DOptSub3, 1);
|
||||||
|
|||||||
@@ -832,6 +832,71 @@ static unsigned Opt_toseqax_tosneax (StackOpData* D, const char* BoolTransformer
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Opt_tosshift (StackOpData* D, const char* Name)
|
||||||
|
/* Optimize shift sequences. */
|
||||||
|
{
|
||||||
|
CodeEntry* X;
|
||||||
|
|
||||||
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
|
/* Inline the compare */
|
||||||
|
D->IP = D->OpIndex+1;
|
||||||
|
|
||||||
|
/* tay */
|
||||||
|
X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
/* If the lhs is direct (but not stack relative), we can just reload the
|
||||||
|
* data later.
|
||||||
|
*/
|
||||||
|
if ((D->Lhs.A.Flags & (LI_DIRECT | LI_RELOAD_Y)) == LI_DIRECT &&
|
||||||
|
(D->Lhs.X.Flags & (LI_DIRECT | LI_RELOAD_Y)) == LI_DIRECT) {
|
||||||
|
|
||||||
|
CodeEntry* LoadX = D->Lhs.X.LoadEntry;
|
||||||
|
CodeEntry* LoadA = D->Lhs.A.LoadEntry;
|
||||||
|
|
||||||
|
/* lda */
|
||||||
|
X = NewCodeEntry (OP65_LDA, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
/* ldx */
|
||||||
|
X = NewCodeEntry (OP65_LDX, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
/* Lhs load entries can be removed */
|
||||||
|
D->Lhs.X.Flags |= LI_REMOVE;
|
||||||
|
D->Lhs.A.Flags |= LI_REMOVE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Save lhs into zeropage and reload later */
|
||||||
|
AddStoreX (D);
|
||||||
|
AddStoreA (D);
|
||||||
|
|
||||||
|
/* lda zp */
|
||||||
|
X = NewCodeEntry (OP65_LDA, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
/* ldx zp+1 */
|
||||||
|
X = NewCodeEntry (OP65_LDX, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* jsr shlaxy/aslaxy/whatever */
|
||||||
|
X = NewCodeEntry (OP65_JSR, AM65_ABS, Name, 0, D->OpEntry->LI);
|
||||||
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
|
/* Remove the push and the call to the tossubax function */
|
||||||
|
RemoveRemainders (D);
|
||||||
|
|
||||||
|
/* We changed the sequence */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned Opt___bzero (StackOpData* D)
|
static unsigned Opt___bzero (StackOpData* D)
|
||||||
/* Optimize the __bzero sequence */
|
/* Optimize the __bzero sequence */
|
||||||
{
|
{
|
||||||
@@ -1169,6 +1234,22 @@ static unsigned Opt_tosandax (StackOpData* D)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Opt_tosaslax (StackOpData* D)
|
||||||
|
/* Optimize the tosaslax sequence */
|
||||||
|
{
|
||||||
|
return Opt_tosshift (D, "aslaxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Opt_tosasrax (StackOpData* D)
|
||||||
|
/* Optimize the tosasrax sequence */
|
||||||
|
{
|
||||||
|
return Opt_tosshift (D, "asraxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned Opt_toseqax (StackOpData* D)
|
static unsigned Opt_toseqax (StackOpData* D)
|
||||||
/* Optimize the toseqax sequence */
|
/* Optimize the toseqax sequence */
|
||||||
{
|
{
|
||||||
@@ -1237,7 +1318,7 @@ static unsigned Opt_tosltax (StackOpData* D)
|
|||||||
CodeLabel* L;
|
CodeLabel* L;
|
||||||
|
|
||||||
|
|
||||||
/* Inline the sbc */
|
/* Inline the compare */
|
||||||
D->IP = D->OpIndex+1;
|
D->IP = D->OpIndex+1;
|
||||||
|
|
||||||
/* Must be true because of OP_RHS_LOAD */
|
/* Must be true because of OP_RHS_LOAD */
|
||||||
@@ -1314,6 +1395,22 @@ static unsigned Opt_tosorax (StackOpData* D)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Opt_tosshlax (StackOpData* D)
|
||||||
|
/* Optimize the tosshlax sequence */
|
||||||
|
{
|
||||||
|
return Opt_tosshift (D, "shlaxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned Opt_tosshrax (StackOpData* D)
|
||||||
|
/* Optimize the tosshrax sequence */
|
||||||
|
{
|
||||||
|
return Opt_tosshift (D, "shraxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned Opt_tossubax (StackOpData* D)
|
static unsigned Opt_tossubax (StackOpData* D)
|
||||||
/* Optimize the tossubax sequence. Note: subtraction is not commutative! */
|
/* Optimize the tossubax sequence. Note: subtraction is not commutative! */
|
||||||
{
|
{
|
||||||
@@ -1547,11 +1644,18 @@ static const OptFuncDesc FuncTable[] = {
|
|||||||
{ "staxspidx", Opt_staxspidx, REG_AX, OP_NONE },
|
{ "staxspidx", Opt_staxspidx, REG_AX, OP_NONE },
|
||||||
{ "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE },
|
{ "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE },
|
||||||
{ "tosandax", Opt_tosandax, REG_NONE, OP_NONE },
|
{ "tosandax", Opt_tosandax, REG_NONE, OP_NONE },
|
||||||
|
{ "tosaslax", Opt_tosaslax, REG_NONE, OP_NONE },
|
||||||
|
#if 0
|
||||||
|
/* Library routine missing */
|
||||||
|
{ "tosasrax", Opt_tosasrax, REG_NONE, OP_NONE },
|
||||||
|
#endif
|
||||||
{ "toseqax", Opt_toseqax, REG_NONE, OP_NONE },
|
{ "toseqax", Opt_toseqax, REG_NONE, OP_NONE },
|
||||||
{ "tosgeax", Opt_tosgeax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
{ "tosgeax", Opt_tosgeax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
{ "tosltax", Opt_tosltax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
{ "tosltax", Opt_tosltax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
{ "tosneax", Opt_tosneax, REG_NONE, OP_NONE },
|
{ "tosneax", Opt_tosneax, REG_NONE, OP_NONE },
|
||||||
{ "tosorax", Opt_tosorax, REG_NONE, OP_NONE },
|
{ "tosorax", Opt_tosorax, REG_NONE, OP_NONE },
|
||||||
|
{ "tosshlax", Opt_tosshlax, REG_NONE, OP_NONE },
|
||||||
|
{ "tosshrax", Opt_tosshrax, REG_NONE, OP_NONE },
|
||||||
{ "tossubax", Opt_tossubax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
{ "tossubax", Opt_tossubax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
{ "tosugeax", Opt_tosugeax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
{ "tosugeax", Opt_tosugeax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
{ "tosugtax", Opt_tosugtax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
{ "tosugtax", Opt_tosugtax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
@@ -1599,11 +1703,13 @@ static int HarmlessCall (const char* Name)
|
|||||||
"aslax2",
|
"aslax2",
|
||||||
"aslax3",
|
"aslax3",
|
||||||
"aslax4",
|
"aslax4",
|
||||||
|
"aslaxy",
|
||||||
"asrax1",
|
"asrax1",
|
||||||
"asrax2",
|
"asrax2",
|
||||||
"asrax3",
|
"asrax3",
|
||||||
"asrax4",
|
"asrax4",
|
||||||
"bnegax",
|
"bnegax",
|
||||||
|
"complax",
|
||||||
"decax1",
|
"decax1",
|
||||||
"decax2",
|
"decax2",
|
||||||
"decax3",
|
"decax3",
|
||||||
@@ -1629,6 +1735,7 @@ static int HarmlessCall (const char* Name)
|
|||||||
"shlax2",
|
"shlax2",
|
||||||
"shlax3",
|
"shlax3",
|
||||||
"shlax4",
|
"shlax4",
|
||||||
|
"shlaxy",
|
||||||
"shrax1",
|
"shrax1",
|
||||||
"shrax2",
|
"shrax2",
|
||||||
"shrax3",
|
"shrax3",
|
||||||
@@ -1744,6 +1851,9 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
StackOpData Data;
|
StackOpData Data;
|
||||||
int I;
|
int I;
|
||||||
int OldEntryCount; /* Old number of entries */
|
int OldEntryCount; /* Old number of entries */
|
||||||
|
unsigned UsedRegs; /* Registers used */
|
||||||
|
unsigned ChangedRegs; /* Registers changed */
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Initialize,
|
Initialize,
|
||||||
@@ -1782,6 +1892,7 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
|
|
||||||
case Initialize:
|
case Initialize:
|
||||||
ResetStackOpData (&Data);
|
ResetStackOpData (&Data);
|
||||||
|
UsedRegs = ChangedRegs = REG_NONE;
|
||||||
State = Search;
|
State = Search;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
@@ -1868,6 +1979,17 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
Data.UsedRegs |= (E->Use | E->Chg);
|
Data.UsedRegs |= (E->Use | E->Chg);
|
||||||
TrackLoads (&Data.Rhs, E, I);
|
TrackLoads (&Data.Rhs, E, I);
|
||||||
}
|
}
|
||||||
|
/* If the registers from the push (A/X) are used before they're
|
||||||
|
* changed, we cannot change the sequence, because this would
|
||||||
|
* with a high probability change the register contents.
|
||||||
|
*/
|
||||||
|
UsedRegs |= E->Use;
|
||||||
|
if ((UsedRegs & ~ChangedRegs) & REG_AX) {
|
||||||
|
I = Data.PushIndex;
|
||||||
|
State = Initialize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ChangedRegs |= E->Chg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FoundOp:
|
case FoundOp:
|
||||||
|
|||||||
Reference in New Issue
Block a user