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

View File

@ -54,9 +54,8 @@
/* Flags for the functions */
typedef enum {
STOP_NONE = 0x00, /* Nothing special */
STOP_A_UNUSED = 0x01, /* Call only if a unused later */
STOP_A_KNOWN = 0x02, /* Call only if A is known */
STOP_X_ZERO = 0x04 /* Call only if X is zero */
STOP_A_KNOWN = 0x01, /* Call only if A is known */
STOP_X_ZERO = 0x02 /* Call only if X is zero */
} STOP_FLAGS;
/* Structure forward decl */
@ -68,6 +67,7 @@ typedef struct OptFuncDesc OptFuncDesc;
struct OptFuncDesc {
const char* Name; /* Name of the replaced runtime function */
OptFunc Func; /* Function pointer */
unsigned UnusedRegs; /* Regs that must not be used later */
STOP_FLAGS Flags; /* Flags */
};
@ -644,7 +644,7 @@ static unsigned Opt_staxspidx (StackOpData* D)
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
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.
*/
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[] = {
{ "__bzero", Opt___bzero, STOP_X_ZERO | STOP_A_KNOWN },
{ "staspidx", Opt_staspidx, STOP_NONE },
{ "staxspidx", Opt_staxspidx, STOP_A_UNUSED },
{ "tosaddax", Opt_tosaddax, STOP_NONE },
{ "tosandax", Opt_tosandax, STOP_NONE },
{ "tosorax", Opt_tosorax, STOP_NONE },
{ "tossubax", Opt_tossubax, STOP_NONE },
{ "tosxorax", Opt_tosxorax, STOP_NONE },
{ "__bzero", Opt___bzero, REG_NONE, STOP_X_ZERO | STOP_A_KNOWN },
{ "staspidx", Opt_staspidx, REG_NONE, STOP_NONE },
{ "staxspidx", Opt_staxspidx, REG_AX, STOP_NONE },
{ "tosaddax", Opt_tosaddax, REG_NONE, STOP_NONE },
{ "tosandax", Opt_tosandax, REG_NONE, STOP_NONE },
{ "tosorax", Opt_tosorax, REG_NONE, STOP_NONE },
{ "tossubax", Opt_tossubax, REG_NONE, STOP_NONE },
{ "tosxorax", Opt_tosxorax, REG_NONE, STOP_NONE },
};
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
@ -1048,15 +1048,18 @@ static int PreCondOk (StackOpData* D)
*/
{
/* Check the flags */
if ((D->OptFunc->Flags & STOP_A_UNUSED) != 0 &&
RegAUsed (D->Code, D->OpIndex+1)) {
unsigned UnusedRegs = D->OptFunc->UnusedRegs;
if (UnusedRegs != REG_NONE &&
(GetRegInfo (D->Code, D->OpIndex+1, UnusedRegs) & UnusedRegs) != 0) {
/* Cannot optimize */
return 0;
} else if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 &&
}
if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 &&
RegValIsUnknown (D->OpEntry->RI->In.RegA)) {
/* Cannot optimize */
return 0;
} else if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 &&
}
if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 &&
D->OpEntry->RI->In.RegX != 0) {
/* Cannot optimize */
return 0;
@ -1237,6 +1240,23 @@ unsigned OptStackOps (CodeSeg* S)
/* Track zero page location usage beyond this point */
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
* pointer to the pushax and start over. We will loose part of
* load tracking but at least a/x has probably lost between
@ -1249,18 +1269,10 @@ unsigned OptStackOps (CodeSeg* S)
break;
}
/* Preconditions are ok, so call the optimizer function */
/* Adjust stack offsets to account for the upcoming removal */
AdjustStackOffset (&Data, 2);
/* 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);
}
/* Prepare the remainder of the data structure. */
Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex);
Data.PushEntry = CS_GetEntry (S, Data.PushIndex);
Data.OpEntry = CS_GetEntry (S, Data.OpIndex);