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:
parent
4a93f188a0
commit
f63964e23c
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user