1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-17 20:30:36 +00:00

Added several constraints to the optimizer functions to avoid breaking code.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4046 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-08-20 16:06:20 +00:00
parent 4a93f188a0
commit f63964e23c
2 changed files with 73 additions and 48 deletions

View File

@ -1319,16 +1319,18 @@ unsigned OptTransfers3 (CodeSeg* S)
*/ */
{ {
unsigned Changes = 0; unsigned Changes = 0;
unsigned Xfer = 0; /* Index of transfer insn */ unsigned UsedRegs = REG_NONE; /* Track used registers */
unsigned Store = 0; /* Index of store insn */ unsigned Xfer = 0; /* Index of transfer insn */
CodeEntry* XferEntry = 0; /* Pointer to xfer insn */ unsigned Store = 0; /* Index of store insn */
CodeEntry* StoreEntry = 0; /* Pointer to store insn */ CodeEntry* XferEntry = 0; /* Pointer to xfer insn */
CodeEntry* StoreEntry = 0; /* Pointer to store insn */
enum { enum {
Searching, Initialize,
Search,
FoundXfer, FoundXfer,
FoundStore FoundStore
} State = Searching; } State = Initialize;
/* Walk over the entries. Look for a xfer instruction that is followed by /* Walk over the entries. Look for a xfer instruction that is followed by
* a store later, where the value of the register is not used later. * a store later, where the value of the register is not used later.
@ -1341,7 +1343,12 @@ unsigned OptTransfers3 (CodeSeg* S)
switch (State) { switch (State) {
case Searching: case Initialize:
/* Clear the list of used registers */
UsedRegs = REG_NONE;
/* FALLTHROUGH */
case Search:
if (E->Info & OF_XFR) { if (E->Info & OF_XFR) {
/* Found start of sequence */ /* Found start of sequence */
Xfer = I; Xfer = I;
@ -1358,7 +1365,7 @@ unsigned OptTransfers3 (CodeSeg* S)
/* Switch back to searching */ /* Switch back to searching */
I = Xfer; I = Xfer;
State = Searching; State = Initialize;
/* Does this insn use the target register of the transfer? */ /* Does this insn use the target register of the transfer? */
} else if ((E->Use & XferEntry->Chg) != 0) { } else if ((E->Use & XferEntry->Chg) != 0) {
@ -1373,7 +1380,7 @@ unsigned OptTransfers3 (CodeSeg* S)
State = FoundStore; State = FoundStore;
} else { } else {
I = Xfer; I = Xfer;
State = Searching; State = Initialize;
} }
/* Does this insn change the target register of the transfer? */ /* Does this insn change the target register of the transfer? */
@ -1384,15 +1391,18 @@ unsigned OptTransfers3 (CodeSeg* S)
* do that and bail out instead. * do that and bail out instead.
*/ */
I = Xfer; I = Xfer;
State = Searching; State = Initialize;
/* Does this insn have a label? */ /* Does this insn have a label? */
} else if (CE_HasLabel (E)) { } else if (CE_HasLabel (E)) {
/* Too complex to handle - bail out */ /* Too complex to handle - bail out */
I = Xfer; I = Xfer;
State = Searching; State = Initialize;
} else {
/* Track used registers */
UsedRegs |= E->Use;
} }
break; break;
@ -1402,7 +1412,10 @@ unsigned OptTransfers3 (CodeSeg* S)
* replace the transfer by a store and remove the store here. * replace the transfer by a store and remove the store here.
*/ */
if ((GetRegInfo (S, I, XferEntry->Chg) & XferEntry->Chg) == 0 && if ((GetRegInfo (S, I, XferEntry->Chg) & XferEntry->Chg) == 0 &&
(StoreEntry->AM == AM65_ABS || StoreEntry->AM == AM65_ZP) && (StoreEntry->AM == AM65_ABS ||
StoreEntry->AM == AM65_ZP) &&
(StoreEntry->AM != AM65_ZP ||
(StoreEntry->Chg & UsedRegs) == 0) &&
!MemAccess (S, Xfer+1, Store-1, StoreEntry->Arg)) { !MemAccess (S, Xfer+1, Store-1, StoreEntry->Arg)) {
/* Generate the replacement store insn */ /* Generate the replacement store insn */
@ -1469,7 +1482,7 @@ unsigned OptTransfers3 (CodeSeg* S)
/* Restart after last xfer insn */ /* Restart after last xfer insn */
I = Xfer; I = Xfer;
} }
State = Searching; State = Initialize;
break; break;
} }
@ -1496,10 +1509,10 @@ unsigned OptTransfers4 (CodeSeg* S)
CodeEntry* XferEntry = 0; /* Pointer to xfer insn */ CodeEntry* XferEntry = 0; /* Pointer to xfer insn */
enum { enum {
Searching, Search,
FoundLoad, FoundLoad,
FoundXfer FoundXfer
} State = Searching; } State = Search;
/* Walk over the entries. Look for a load instruction that is followed by /* Walk over the entries. Look for a load instruction that is followed by
* a load later. * a load later.
@ -1512,7 +1525,7 @@ unsigned OptTransfers4 (CodeSeg* S)
switch (State) { switch (State) {
case Searching: case Search:
if (E->Info & OF_LOAD) { if (E->Info & OF_LOAD) {
/* Found start of sequence */ /* Found start of sequence */
Load = I; Load = I;
@ -1529,7 +1542,7 @@ unsigned OptTransfers4 (CodeSeg* S)
/* Switch back to searching */ /* Switch back to searching */
I = Load; I = Load;
State = Searching; State = Search;
/* Does this insn use the target register of the load? */ /* Does this insn use the target register of the load? */
} else if ((E->Use & LoadEntry->Chg) != 0) { } else if ((E->Use & LoadEntry->Chg) != 0) {
@ -1544,7 +1557,7 @@ unsigned OptTransfers4 (CodeSeg* S)
State = FoundXfer; State = FoundXfer;
} else { } else {
I = Load; I = Load;
State = Searching; State = Search;
} }
/* Does this insn change the target register of the load? */ /* Does this insn change the target register of the load? */
@ -1555,7 +1568,7 @@ unsigned OptTransfers4 (CodeSeg* S)
* do that and bail out instead. * do that and bail out instead.
*/ */
I = Load; I = Load;
State = Searching; State = Search;
} }
break; break;
@ -1627,7 +1640,7 @@ unsigned OptTransfers4 (CodeSeg* S)
/* Restart after last xfer insn */ /* Restart after last xfer insn */
I = Xfer; I = Xfer;
} }
State = Searching; State = Search;
break; break;
} }

View File

@ -54,9 +54,8 @@
/* Flags for the functions */ /* Flags for the functions */
typedef enum { typedef enum {
STOP_NONE = 0x00, /* Nothing special */ STOP_NONE = 0x00, /* Nothing special */
STOP_A_UNUSED = 0x01, /* Call only if a unused later */ STOP_A_KNOWN = 0x01, /* Call only if A is known */
STOP_A_KNOWN = 0x02, /* Call only if A is known */ STOP_X_ZERO = 0x02 /* Call only if X is zero */
STOP_X_ZERO = 0x04 /* Call only if X is zero */
} STOP_FLAGS; } STOP_FLAGS;
/* Structure forward decl */ /* Structure forward decl */
@ -68,6 +67,7 @@ typedef struct OptFuncDesc OptFuncDesc;
struct OptFuncDesc { struct OptFuncDesc {
const char* Name; /* Name of the replaced runtime function */ const char* Name; /* Name of the replaced runtime function */
OptFunc Func; /* Function pointer */ OptFunc Func; /* Function pointer */
unsigned UnusedRegs; /* Regs that must not be used later */
STOP_FLAGS Flags; /* Flags */ STOP_FLAGS Flags; /* Flags */
}; };
@ -180,7 +180,7 @@ static void AdjustStackOffset (StackOpData* D, unsigned Offs)
/* If we need the value of Y later, be sure to reload it */ /* If we need the value of Y later, be sure to reload it */
if (RegYUsed (D->Code, I+1)) { if (RegYUsed (D->Code, I+1)) {
const char* Arg = MakeHexArg (E->RI->In.RegY); const char* Arg = MakeHexArg (E->RI->In.RegY);
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
CS_InsertEntry (D->Code, X, I+1); CS_InsertEntry (D->Code, X, I+1);
@ -644,7 +644,7 @@ static unsigned Opt_staxspidx (StackOpData* D)
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
InsertEntry (D, X, D->OpIndex+4); InsertEntry (D, X, D->OpIndex+4);
/* If we remove staspidx, we must restore the Y register to what the /* If we remove staxspidx, we must restore the Y register to what the
* function would return. * function would return.
*/ */
X = NewCodeEntry (OP65_LDY, AM65_IMM, "$00", 0, D->OpEntry->LI); X = NewCodeEntry (OP65_LDY, AM65_IMM, "$00", 0, D->OpEntry->LI);
@ -952,14 +952,14 @@ static unsigned Opt_tosxorax (StackOpData* D)
static const OptFuncDesc FuncTable[] = { static const OptFuncDesc FuncTable[] = {
{ "__bzero", Opt___bzero, STOP_X_ZERO | STOP_A_KNOWN }, { "__bzero", Opt___bzero, REG_NONE, STOP_X_ZERO | STOP_A_KNOWN },
{ "staspidx", Opt_staspidx, STOP_NONE }, { "staspidx", Opt_staspidx, REG_NONE, STOP_NONE },
{ "staxspidx", Opt_staxspidx, STOP_A_UNUSED }, { "staxspidx", Opt_staxspidx, REG_AX, STOP_NONE },
{ "tosaddax", Opt_tosaddax, STOP_NONE }, { "tosaddax", Opt_tosaddax, REG_NONE, STOP_NONE },
{ "tosandax", Opt_tosandax, STOP_NONE }, { "tosandax", Opt_tosandax, REG_NONE, STOP_NONE },
{ "tosorax", Opt_tosorax, STOP_NONE }, { "tosorax", Opt_tosorax, REG_NONE, STOP_NONE },
{ "tossubax", Opt_tossubax, STOP_NONE }, { "tossubax", Opt_tossubax, REG_NONE, STOP_NONE },
{ "tosxorax", Opt_tosxorax, STOP_NONE }, { "tosxorax", Opt_tosxorax, REG_NONE, STOP_NONE },
}; };
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0])) #define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
@ -1048,16 +1048,19 @@ static int PreCondOk (StackOpData* D)
*/ */
{ {
/* Check the flags */ /* Check the flags */
if ((D->OptFunc->Flags & STOP_A_UNUSED) != 0 && unsigned UnusedRegs = D->OptFunc->UnusedRegs;
RegAUsed (D->Code, D->OpIndex+1)) { if (UnusedRegs != REG_NONE &&
(GetRegInfo (D->Code, D->OpIndex+1, UnusedRegs) & UnusedRegs) != 0) {
/* Cannot optimize */ /* Cannot optimize */
return 0; return 0;
} else if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 && }
RegValIsUnknown (D->OpEntry->RI->In.RegA)) { if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 &&
RegValIsUnknown (D->OpEntry->RI->In.RegA)) {
/* Cannot optimize */ /* Cannot optimize */
return 0; return 0;
} else if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 && }
D->OpEntry->RI->In.RegX != 0) { if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 &&
D->OpEntry->RI->In.RegX != 0) {
/* Cannot optimize */ /* Cannot optimize */
return 0; return 0;
} }
@ -1237,6 +1240,23 @@ unsigned OptStackOps (CodeSeg* S)
/* Track zero page location usage beyond this point */ /* Track zero page location usage beyond this point */
Data.UsedRegs |= GetRegInfo (S, I, REG_SREG | REG_PTR1 | REG_PTR2); Data.UsedRegs |= GetRegInfo (S, I, REG_SREG | REG_PTR1 | REG_PTR2);
/* Get the entry pointers to the load insns. If these insns
* load from zero page, we have to include them into UsedRegs
* registers used.
*/
if (Data.LoadAIndex >= 0) {
Data.LoadAEntry = CS_GetEntry (S, Data.LoadAIndex);
if (Data.LoadAEntry->AM == AM65_ZP) {
Data.UsedRegs |= Data.LoadAEntry->Use;
}
}
if (Data.LoadXIndex >= 0) {
Data.LoadXEntry = CS_GetEntry (S, Data.LoadXIndex);
if (Data.LoadXEntry->AM == AM65_ZP) {
Data.UsedRegs |= Data.LoadXEntry->Use;
}
}
/* Check the preconditions. If they aren't ok, reset the insn /* Check the preconditions. If they aren't ok, reset the insn
* pointer to the pushax and start over. We will loose part of * pointer to the pushax and start over. We will loose part of
* load tracking but at least a/x has probably lost between * load tracking but at least a/x has probably lost between
@ -1249,18 +1269,10 @@ unsigned OptStackOps (CodeSeg* S)
break; break;
} }
/* Preconditions are ok, so call the optimizer function */
/* Adjust stack offsets to account for the upcoming removal */ /* Adjust stack offsets to account for the upcoming removal */
AdjustStackOffset (&Data, 2); AdjustStackOffset (&Data, 2);
/* Prepare the remainder of the data structure */ /* Prepare the remainder of the data structure. */
if (Data.LoadAIndex >= 0) {
Data.LoadAEntry = CS_GetEntry (S, Data.LoadAIndex);
}
if (Data.LoadXIndex >= 0) {
Data.LoadXEntry = CS_GetEntry (S, Data.LoadXIndex);
}
Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex); Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex);
Data.PushEntry = CS_GetEntry (S, Data.PushIndex); Data.PushEntry = CS_GetEntry (S, Data.PushIndex);
Data.OpEntry = CS_GetEntry (S, Data.OpIndex); Data.OpEntry = CS_GetEntry (S, Data.OpIndex);