1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +00:00

Added code replacements for several missing compare functions. Fixed a bug in

coptstop.c that popped up if transfer instructions were used to load a value
into X.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4111 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-09-01 20:57:39 +00:00
parent 7c613f7a83
commit 7cd92c82fa

View File

@ -56,18 +56,21 @@ typedef enum {
LI_NONE = 0x00,
LI_DIRECT = 0x01, /* Direct op may be used */
LI_RELOAD_Y = 0x02, /* Reload index register Y */
LI_REMOVE = 0x04, /* Load may be removed */
LI_TRANSFER = 0x04, /* Loaded value is transfered */
LI_REMOVE = 0x08, /* Load may be removed */
} LI_FLAGS;
/* Structure that tells us how to load the lhs values */
typedef struct LoadRegInfo LoadRegInfo;
struct LoadRegInfo {
LI_FLAGS Flags; /* Tells us how to load */
int LoadIndex; /* Index of load insn, -1 if invalid */
CodeEntry* LoadEntry; /* The actual entry, 0 if invalid */
LI_FLAGS Flags; /* Tells us how to load */
int XferIndex; /* Index of transfer insn */
CodeEntry* XferEntry; /* The actual transfer entry */
unsigned char Offs; /* Stack offset if data is on stack */
};
/* Now combined for both registers */
typedef struct LoadInfo LoadInfo;
struct LoadInfo {
@ -150,6 +153,17 @@ static void ClearLoadRegInfo (LoadRegInfo* RI)
/* Clear a LoadRegInfo struct */
{
RI->LoadIndex = -1;
RI->XferIndex = -1;
RI->Flags = LI_NONE;
}
static void InvalidateLoadRegInfo (LoadRegInfo* RI)
/* Invalidate a LoadRegInfo struct */
{
RI->LoadIndex = -1;
RI->XferIndex = -1;
}
@ -157,13 +171,17 @@ static void ClearLoadRegInfo (LoadRegInfo* RI)
static void FinalizeLoadRegInfo (LoadRegInfo* RI, CodeSeg* S)
/* Prepare a LoadRegInfo struct for use */
{
/* Get the entry */
/* Get the entries */
if (RI->LoadIndex >= 0) {
RI->LoadEntry = CS_GetEntry (S, RI->LoadIndex);
} else {
RI->LoadEntry = 0;
}
RI->Flags = LI_NONE;
if (RI->XferIndex >= 0) {
RI->XferEntry = CS_GetEntry (S, RI->XferIndex);
} else {
RI->XferEntry = 0;
}
}
@ -178,7 +196,7 @@ static void ClearLoadInfo (LoadInfo* LI)
static void AdjustLoadRegInfo (LoadRegInfo* RI, int DelIndex, int Change)
static void AdjustLoadRegInfo (LoadRegInfo* RI, int Index, int Change)
/* Adjust a load register info struct after deleting or inserting an entry
* with a given index
*/
@ -186,18 +204,28 @@ static void AdjustLoadRegInfo (LoadRegInfo* RI, int DelIndex, int Change)
CHECK (abs (Change) == 1);
if (Change < 0) {
/* Deletion */
if (DelIndex < RI->LoadIndex) {
if (Index < RI->LoadIndex) {
--RI->LoadIndex;
} else if (DelIndex == RI->LoadIndex) {
} else if (Index == RI->LoadIndex) {
/* Has been removed */
RI->LoadIndex = -1;
RI->LoadEntry = 0;
}
if (Index < RI->XferIndex) {
--RI->XferIndex;
} else if (Index == RI->XferIndex) {
/* Has been removed */
RI->XferIndex = -1;
RI->XferEntry = 0;
}
} else {
/* Insertion */
if (DelIndex <= RI->LoadIndex) {
if (Index <= RI->LoadIndex) {
++RI->LoadIndex;
}
if (Index <= RI->XferIndex) {
++RI->XferIndex;
}
}
}
@ -214,12 +242,12 @@ static void FinalizeLoadInfo (LoadInfo* LI, CodeSeg* S)
static void AdjustLoadInfo (LoadInfo* LI, int DelIndex, int Change)
static void AdjustLoadInfo (LoadInfo* LI, int Index, int Change)
/* Adjust a load info struct after deleting entry with a given index */
{
AdjustLoadRegInfo (&LI->A, DelIndex, Change);
AdjustLoadRegInfo (&LI->X, DelIndex, Change);
AdjustLoadRegInfo (&LI->Y, DelIndex, Change);
AdjustLoadRegInfo (&LI->A, Index, Change);
AdjustLoadRegInfo (&LI->X, Index, Change);
AdjustLoadRegInfo (&LI->Y, Index, Change);
}
@ -230,35 +258,53 @@ static void TrackLoads (LoadInfo* LI, CodeEntry* E, int I)
if (E->Info & OF_LOAD) {
if (E->Chg & REG_A) {
LI->A.LoadIndex = I;
LI->A.XferIndex = -1;
}
if (E->Chg & REG_X) {
LI->X.LoadIndex = I;
LI->X.XferIndex = -1;
}
if (E->Chg & REG_Y) {
LI->Y.LoadIndex = I;
LI->Y.XferIndex = -1;
}
} else if (E->Info & OF_XFR) {
switch (E->OPC) {
case OP65_TAX: LI->X.LoadIndex = LI->A.LoadIndex; break;
case OP65_TAY: LI->Y.LoadIndex = LI->A.LoadIndex; break;
case OP65_TXA: LI->A.LoadIndex = LI->X.LoadIndex; break;
case OP65_TYA: LI->A.LoadIndex = LI->Y.LoadIndex; break;
default: break;
case OP65_TAX:
LI->X.LoadIndex = LI->A.LoadIndex;
LI->X.XferIndex = I;
break;
case OP65_TAY:
LI->Y.LoadIndex = LI->A.LoadIndex;
LI->Y.XferIndex = I;
break;
case OP65_TXA:
LI->A.LoadIndex = LI->X.LoadIndex;
LI->A.XferIndex = I;
break;
case OP65_TYA:
LI->A.LoadIndex = LI->Y.LoadIndex;
LI->A.XferIndex = I;
break;
default:
break;
}
} else if (CE_IsCallTo (E, "ldaxysp")) {
/* Both registers set, Y changed */
LI->A.LoadIndex = I;
LI->X.LoadIndex = I;
LI->Y.LoadIndex = -1;
LI->A.XferIndex = -1;
LI->X.LoadIndex = I;
LI->X.XferIndex = -1;
InvalidateLoadRegInfo (&LI->Y);
} else {
if (E->Chg & REG_A) {
LI->A.LoadIndex = -1;
InvalidateLoadRegInfo (&LI->A);
}
if (E->Chg & REG_X) {
LI->X.LoadIndex = -1;
InvalidateLoadRegInfo (&LI->X);
}
if (E->Chg & REG_Y) {
LI->Y.LoadIndex = -1;
InvalidateLoadRegInfo (&LI->Y);
}
}
}
@ -271,88 +317,6 @@ static void TrackLoads (LoadInfo* LI, CodeEntry* E, int I)
static void AdjustStackOffset (StackOpData* D, unsigned Offs)
/* Adjust the offset for all stack accesses in the range PushIndex to OpIndex.
* OpIndex is adjusted according to the insertions.
*/
{
/* Walk over all entries */
int I = D->PushIndex + 1;
while (I < D->OpIndex) {
CodeEntry* E = CS_GetEntry (D->Code, I);
int NeedCorrection = 0;
if ((E->Use & REG_SP) != 0) {
/* Check for some things that should not happen */
CHECK (E->AM == AM65_ZP_INDY || E->RI->In.RegY >= (short) Offs);
CHECK (strcmp (E->Arg, "sp") == 0);
/* We need to correct this one */
NeedCorrection = 1;
} else if (CE_IsCallTo (E, "ldaxysp")) {
/* We need to correct this one */
NeedCorrection = 1;
}
if (NeedCorrection) {
/* Get the code entry before this one. If it's a LDY, adjust the
* value.
*/
CodeEntry* P = CS_GetPrevEntry (D->Code, I);
if (P && P->OPC == OP65_LDY && CE_IsConstImm (P)) {
/* The Y load is just before the stack access, adjust it */
CE_SetNumArg (P, P->Num - Offs);
} else {
/* Insert a new load instruction before the stack access */
const char* Arg = MakeHexArg (E->RI->In.RegY - Offs);
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
CS_InsertEntry (D->Code, X, I++);
/* One more inserted entries */
++D->OpIndex;
}
/* If we need the value of Y later, be sure to reload it */
if (RegYUsed (D->Code, I+1)) {
const char* Arg = MakeHexArg (E->RI->In.RegY);
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
CS_InsertEntry (D->Code, X, I+1);
/* One more inserted entries */
++D->OpIndex;
/* Skip this instruction in the next round */
++I;
}
}
/* Next entry */
++I;
}
/* If we have rhs load insns that load from stack, we'll have to adjust
* the offsets for these also.
*/
if (D->Rhs.A.Flags & LI_RELOAD_Y) {
D->Rhs.A.Offs -= Offs;
}
if (D->Rhs.X.Flags & LI_RELOAD_Y) {
D->Rhs.X.Offs -= Offs;
}
}
static void InsertEntry (StackOpData* D, CodeEntry* E, int Index)
/* Insert a new entry. Depending on Index, D->PushIndex and D->OpIndex will
* be adjusted by this function.
@ -403,6 +367,82 @@ static void DelEntry (StackOpData* D, int Index)
static void AdjustStackOffset (StackOpData* D, unsigned Offs)
/* Adjust the offset for all stack accesses in the range PushIndex to OpIndex.
* OpIndex is adjusted according to the insertions.
*/
{
/* Walk over all entries */
int I = D->PushIndex + 1;
while (I < D->OpIndex) {
CodeEntry* E = CS_GetEntry (D->Code, I);
int NeedCorrection = 0;
if ((E->Use & REG_SP) != 0) {
/* Check for some things that should not happen */
CHECK (E->AM == AM65_ZP_INDY || E->RI->In.RegY >= (short) Offs);
CHECK (strcmp (E->Arg, "sp") == 0);
/* We need to correct this one */
NeedCorrection = 1;
} else if (CE_IsCallTo (E, "ldaxysp")) {
/* We need to correct this one */
NeedCorrection = 1;
}
if (NeedCorrection) {
/* Get the code entry before this one. If it's a LDY, adjust the
* value.
*/
CodeEntry* P = CS_GetPrevEntry (D->Code, I);
if (P && P->OPC == OP65_LDY && CE_IsConstImm (P)) {
/* The Y load is just before the stack access, adjust it */
CE_SetNumArg (P, P->Num - Offs);
} else {
/* Insert a new load instruction before the stack access */
const char* Arg = MakeHexArg (E->RI->In.RegY - Offs);
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
InsertEntry (D, X, I++);
}
/* If we need the value of Y later, be sure to reload it */
if (RegYUsed (D->Code, I+1)) {
const char* Arg = MakeHexArg (E->RI->In.RegY);
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
InsertEntry (D, X, I+1);
/* Skip this instruction in the next round */
++I;
}
}
/* Next entry */
++I;
}
/* If we have rhs load insns that load from stack, we'll have to adjust
* the offsets for these also.
*/
if (D->Rhs.A.Flags & LI_RELOAD_Y) {
D->Rhs.A.Offs -= Offs;
}
if (D->Rhs.X.Flags & LI_RELOAD_Y) {
D->Rhs.X.Offs -= Offs;
}
}
static void CheckOneDirectOp (LoadRegInfo* LI, unsigned char Offs)
/* Check if the given entry is a lda instruction with an addressing mode
* that allows us to replace it by another operation (like ora). If so, we may
@ -616,11 +656,21 @@ static void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
/* Both registers may be loaded with one insn, but DelEntry will in this
* case clear the other one.
*/
if (LI->A.LoadIndex >= 0 && (LI->A.Flags & LI_REMOVE)) {
DelEntry (D, LI->A.LoadIndex);
if (LI->A.Flags & LI_REMOVE) {
if (LI->A.LoadIndex >= 0) {
DelEntry (D, LI->A.LoadIndex);
}
if (LI->A.XferIndex >= 0) {
DelEntry (D, LI->A.XferIndex);
}
}
if (LI->X.LoadIndex >= 0 && (LI->X.Flags & LI_REMOVE)) {
DelEntry (D, LI->X.LoadIndex);
if (LI->X.Flags & LI_REMOVE) {
if (LI->X.LoadIndex >= 0) {
DelEntry (D, LI->X.LoadIndex);
}
if (LI->X.XferIndex >= 0) {
DelEntry (D, LI->X.XferIndex);
}
}
}
@ -1344,6 +1394,99 @@ static unsigned Opt_tosugeax (StackOpData* D)
static unsigned Opt_tosugtax (StackOpData* D)
/* Optimize the tosugtax sequence */
{
CodeEntry* X;
/* Inline the sbc */
D->IP = D->OpIndex+1;
/* Must be true because of OP_RHS_LOAD */
CHECK ((D->Rhs.A.Flags & D->Rhs.X.Flags & LI_DIRECT) != 0);
/* Add code for low operand */
AddOpLow (D, OP65_CMP, &D->Rhs);
/* Add code for high operand */
AddOpHigh (D, OP65_SBC, &D->Rhs, 0);
/* Transform to boolean */
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolugt", 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
/* Remove the push and the call to the operator function */
RemoveRemainders (D);
/* We changed the sequence */
return 1;
}
static unsigned Opt_tosuleax (StackOpData* D)
/* Optimize the tosuleax sequence */
{
CodeEntry* X;
/* Inline the sbc */
D->IP = D->OpIndex+1;
/* Must be true because of OP_RHS_LOAD */
CHECK ((D->Rhs.A.Flags & D->Rhs.X.Flags & LI_DIRECT) != 0);
/* Add code for low operand */
AddOpLow (D, OP65_CMP, &D->Rhs);
/* Add code for high operand */
AddOpHigh (D, OP65_SBC, &D->Rhs, 0);
/* Transform to boolean */
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolule", 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
/* Remove the push and the call to the operator function */
RemoveRemainders (D);
/* We changed the sequence */
return 1;
}
static unsigned Opt_tosultax (StackOpData* D)
/* Optimize the tosultax sequence */
{
CodeEntry* X;
/* Inline the sbc */
D->IP = D->OpIndex+1;
/* Must be true because of OP_RHS_LOAD */
CHECK ((D->Rhs.A.Flags & D->Rhs.X.Flags & LI_DIRECT) != 0);
/* Add code for low operand */
AddOpLow (D, OP65_CMP, &D->Rhs);
/* Add code for high operand */
AddOpHigh (D, OP65_SBC, &D->Rhs, 0);
/* Transform to boolean */
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolult", 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
/* Remove the push and the call to the operator function */
RemoveRemainders (D);
/* We changed the sequence */
return 1;
}
static unsigned Opt_tosxorax (StackOpData* D)
/* Optimize the tosxorax sequence */
{
@ -1397,6 +1540,9 @@ static const OptFuncDesc FuncTable[] = {
{ "tosorax", Opt_tosorax, REG_NONE, OP_NONE },
{ "tossubax", Opt_tossubax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosugeax", Opt_tosugeax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosugtax", Opt_tosugtax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosuleax", Opt_tosuleax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosultax", Opt_tosultax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosxorax", Opt_tosxorax, REG_NONE, OP_NONE },
};
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
@ -1715,6 +1861,12 @@ unsigned OptStackOps (CodeSeg* S)
break;
}
/* 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);
Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex);
/* Adjust stack offsets to account for the upcoming removal */
AdjustStackOffset (&Data, 2);
@ -1723,12 +1875,6 @@ unsigned OptStackOps (CodeSeg* S)
*/
CS_GenRegInfo (S);
/* 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);
Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex);
/* Call the optimizer function */
Changes += Data.OptFunc->Func (&Data);