Prevent the removal of a ldaxysp runtime call as a "load instruction" for only the A or the X side, when the other is non-removable. Fixes issue #2942 / #2461.
This commit is contained in:
@@ -1123,6 +1123,8 @@ void AddOpLow (StackOpData* D, opc_t OPC, LoadInfo* LI)
|
|||||||
InsertEntry (D, X, D->IP++);
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
if (LI->A.LoadEntry->OPC == OP65_JSR) {
|
if (LI->A.LoadEntry->OPC == OP65_JSR) {
|
||||||
|
/* This should only happen in one known ldaxysp case. */
|
||||||
|
CHECK (CE_IsCallTo (LI->A.LoadEntry, "ldaxysp"));
|
||||||
/* opc (c_sp),y */
|
/* opc (c_sp),y */
|
||||||
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
||||||
} else {
|
} else {
|
||||||
@@ -1133,7 +1135,7 @@ void AddOpLow (StackOpData* D, opc_t OPC, LoadInfo* LI)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In both cases, we can remove the load */
|
/* In both cases, we may try removing the load */
|
||||||
LI->A.Flags |= LI_REMOVE;
|
LI->A.Flags |= LI_REMOVE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1188,6 +1190,8 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
|||||||
InsertEntry (D, X, D->IP++);
|
InsertEntry (D, X, D->IP++);
|
||||||
|
|
||||||
if (LI->X.LoadEntry->OPC == OP65_JSR) {
|
if (LI->X.LoadEntry->OPC == OP65_JSR) {
|
||||||
|
/* This should only happen in one known ldaxysp case. */
|
||||||
|
CHECK (CE_IsCallTo (LI->X.LoadEntry, "ldaxysp"));
|
||||||
/* opc (c_sp),y */
|
/* opc (c_sp),y */
|
||||||
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
||||||
} else {
|
} else {
|
||||||
@@ -1197,7 +1201,7 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
|||||||
InsertEntry (D, X, D->IP++);
|
InsertEntry (D, X, D->IP++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In both cases, we can remove the load */
|
/* In both cases, we may try removing the load */
|
||||||
LI->X.Flags |= LI_REMOVE;
|
LI->X.Flags |= LI_REMOVE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1225,12 +1229,65 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
|||||||
void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
|
void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
|
||||||
/* Remove register load insns */
|
/* Remove register load insns */
|
||||||
{
|
{
|
||||||
if ((LI->A.Flags & LI_REMOVE) == LI_REMOVE) {
|
int CanRemoveA;
|
||||||
if (LI->A.LoadIndex >= 0 &&
|
int CanRemoveX;
|
||||||
(LI->A.LoadEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
|
||||||
DelEntry (D, LI->A.LoadIndex);
|
/* When either A or X load insn is a call to ldaxysp runtime, the load
|
||||||
|
** affects both and must be treated as a single A/X unit. A request to
|
||||||
|
** remove the runtime call for just one (A or X) load is not valid in that
|
||||||
|
** case. Either both must be removable+removed, or the other load is
|
||||||
|
** independent, or ldaxysp runtime call must remain.
|
||||||
|
*/
|
||||||
|
CanRemoveA = (LI->A.Flags & LI_REMOVE) == LI_REMOVE &&
|
||||||
|
LI->A.LoadEntry != 0 &&
|
||||||
|
(LI->A.LoadEntry->Flags & CEF_DONT_REMOVE) == 0;
|
||||||
|
|
||||||
|
CanRemoveX = (LI->X.Flags & LI_REMOVE) == LI_REMOVE &&
|
||||||
|
LI->X.LoadEntry != 0 &&
|
||||||
|
(LI->X.LoadEntry->Flags & CEF_DONT_REMOVE) == 0;
|
||||||
|
|
||||||
|
/* The only runtime calls removable as load insns are calls to ldaxysp. */
|
||||||
|
CHECK (!CanRemoveA || LI->A.LoadEntry->OPC != OP65_JSR ||
|
||||||
|
CE_IsCallTo (LI->A.LoadEntry, "ldaxysp"));
|
||||||
|
CHECK (!CanRemoveX || LI->X.LoadEntry->OPC != OP65_JSR ||
|
||||||
|
CE_IsCallTo (LI->X.LoadEntry, "ldaxysp"));
|
||||||
|
|
||||||
|
/* When the A load is a runtime call and the X load cannot be removed,
|
||||||
|
** we cannot remove the A load either.
|
||||||
|
*/
|
||||||
|
if (CanRemoveA && LI->A.LoadEntry->OPC == OP65_JSR && !CanRemoveX) {
|
||||||
|
/* A load is not removable */
|
||||||
|
LI->A.LoadEntry->Flags |= CEF_DONT_REMOVE;
|
||||||
|
CanRemoveA = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When the X load is a runtime call and the A load cannot be removed,
|
||||||
|
** we cannot remove the X load either.
|
||||||
|
*/
|
||||||
|
if (CanRemoveX && LI->X.LoadEntry->OPC == OP65_JSR && !CanRemoveA) {
|
||||||
|
/* X load is not removable */
|
||||||
|
LI->X.LoadEntry->Flags |= CEF_DONT_REMOVE;
|
||||||
|
CanRemoveX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A request to remove a "change" insn (ChgIndex) when there is no
|
||||||
|
** corresponing load insn (LoadIndex) is never valid.
|
||||||
|
*/
|
||||||
|
CHECK ((LI->A.Flags & LI_REMOVE) == 0 || LI->A.ChgIndex < 0 ||
|
||||||
|
LI->A.LoadIndex >= 0);
|
||||||
|
CHECK ((LI->X.Flags & LI_REMOVE) == 0 || LI->X.ChgIndex < 0 ||
|
||||||
|
LI->X.LoadIndex >= 0);
|
||||||
|
|
||||||
|
if (CanRemoveA) {
|
||||||
|
|
||||||
|
CHECK (LI->A.LoadIndex >= 0);
|
||||||
|
DelEntry (D, LI->A.LoadIndex);
|
||||||
|
|
||||||
|
/* Only remove the Y load if it is not shared with a non-removable
|
||||||
|
** X load. A shared load will be removed here otherwise.
|
||||||
|
*/
|
||||||
if (LI->A.LoadYIndex >= 0 &&
|
if (LI->A.LoadYIndex >= 0 &&
|
||||||
|
(LI->A.LoadYIndex != LI->X.LoadYIndex || CanRemoveX) &&
|
||||||
(LI->A.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
(LI->A.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||||
DelEntry (D, LI->A.LoadYIndex);
|
DelEntry (D, LI->A.LoadYIndex);
|
||||||
}
|
}
|
||||||
@@ -1247,11 +1304,16 @@ void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
|
|||||||
LI->A.LoadYEntry->Flags |= CEF_DONT_REMOVE;
|
LI->A.LoadYEntry->Flags |= CEF_DONT_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((LI->X.Flags & LI_REMOVE) == LI_REMOVE) {
|
/* The X load may have already been removed above if it were a runtime
|
||||||
if (LI->X.LoadIndex >= 0 &&
|
** call (i.e. "jsr ldaxysp"), so need to check again.
|
||||||
(LI->X.LoadEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
*/
|
||||||
|
if (CanRemoveX && LI->X.LoadIndex >= 0) {
|
||||||
|
|
||||||
DelEntry (D, LI->X.LoadIndex);
|
DelEntry (D, LI->X.LoadIndex);
|
||||||
}
|
|
||||||
|
/* Only remove the Y load if it is not shared with non-removable A load.
|
||||||
|
** If it is shared and still needed, it was flaged non-removable above.
|
||||||
|
*/
|
||||||
if (LI->X.LoadYIndex >= 0 &&
|
if (LI->X.LoadYIndex >= 0 &&
|
||||||
(LI->X.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
(LI->X.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||||
DelEntry (D, LI->X.LoadYIndex);
|
DelEntry (D, LI->X.LoadYIndex);
|
||||||
|
|||||||
Reference in New Issue
Block a user