OP_A_KNOWN = 0x01, /* Value of A must be known */
OP_X_ZERO = 0x02, /* X must be zero */
OP_LHS_LOAD = 0x04, /* Must have load insns for LHS */
- OP_RHS_LOAD = 0x08, /* Must have load insns for RHS */
+ OP_LHS_LOAD_DIRECT = 0x0C, /* Must have direct load insn for LHS */
+ OP_RHS_LOAD = 0x10, /* Must have load insns for RHS */
+ OP_RHS_LOAD_DIRECT = 0x30, /* Must have direct load insn for RHS */
} OP_FLAGS;
/* Structure forward decl */
} else {
- /* Check the entry before the push. If it's a lda instruction with an
- * addressing mode that allows us to replace it, we may use this
- * location for the op and must not save the value in the zero page
- * location.
- */
- CheckDirectOp (D);
-
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
{
CodeEntry* X;
- /* Check the entry before the push. If it's a lda instruction with an
- * addressing mode that allows us to replace it, we may use this
- * location for the op and must not save the value in the zero page
- * location.
- */
- CheckDirectOp (D);
-
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
+static unsigned Opt_tosgeax (StackOpData* D)
+/* Optimize the tosgeax sequence if possible. */
+{
+ CodeEntry* X;
+ CodeLabel* L;
+
+ /* Inline the sbc */
+ D->IP = D->OpIndex+1;
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.A.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.A.Flags & LI_RELOAD_Y) == 0) {
+
+ /* cmp ... */
+ CodeEntry* LoadA = D->Rhs.A.LoadEntry;
+ X = NewCodeEntry (OP65_CMP, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.A.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* cmp (sp),y */
+ X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.A.Flags |= LI_REMOVE;
+
+ /* txa */
+ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.X.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.X.Flags & LI_RELOAD_Y) == 0) {
+
+ /* sbc ... */
+ CodeEntry* LoadX = D->Rhs.X.LoadEntry;
+ X = NewCodeEntry (OP65_SBC, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.X.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* sbc (sp),y */
+ X = NewCodeEntry (OP65_SBC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.X.Flags |= LI_REMOVE;
+
+ /* eor #$80 */
+ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$80", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* asl a */
+ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ L = CS_GenLabel (D->Code, X);
+
+ /* Insert a bvs L before the eor insn */
+ X = NewCodeEntry (OP65_BVS, AM65_BRA, L->Name, L, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP - 2);
+ ++D->IP;
+
+ /* lda #$00 */
+ X = NewCodeEntry (OP65_LDA, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* ldx #$00 */
+ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* rol a */
+ X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Remove the push and the call to the tosgeax function */
+ RemoveRemainders (D);
+
+ /* We changed the sequence */
+ return 1;
+}
+
+
+
+static unsigned Opt_tosltax (StackOpData* D)
+/* Optimize the tosltax sequence if possible. */
+{
+ CodeEntry* X;
+ CodeLabel* L;
+
+
+ /* Inline the sbc */
+ D->IP = D->OpIndex+1;
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.A.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.A.Flags & LI_RELOAD_Y) == 0) {
+
+ /* cmp ... */
+ CodeEntry* LoadA = D->Rhs.A.LoadEntry;
+ X = NewCodeEntry (OP65_CMP, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.A.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* cmp (sp),y */
+ X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.A.Flags |= LI_REMOVE;
+
+ /* txa */
+ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.X.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.X.Flags & LI_RELOAD_Y) == 0) {
+
+ /* sbc ... */
+ CodeEntry* LoadX = D->Rhs.X.LoadEntry;
+ X = NewCodeEntry (OP65_SBC, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.X.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* sbc (sp),y */
+ X = NewCodeEntry (OP65_SBC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.X.Flags |= LI_REMOVE;
+
+ /* eor #$80 */
+ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$80", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* asl a */
+ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ L = CS_GenLabel (D->Code, X);
+
+ /* Insert a bvc L before the eor insn */
+ X = NewCodeEntry (OP65_BVC, AM65_BRA, L->Name, L, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP - 2);
+ ++D->IP;
+
+ /* lda #$00 */
+ X = NewCodeEntry (OP65_LDA, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* ldx #$00 */
+ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* rol a */
+ X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Remove the push and the call to the tosltax function */
+ RemoveRemainders (D);
+
+ /* We changed the sequence */
+ return 1;
+}
+
+
+
static unsigned Opt_tosorax (StackOpData* D)
/* Optimize the tosorax sequence if possible */
{
CodeEntry* X;
- /* Check the entry before the push. If it's a lda instruction with an
- * addressing mode that allows us to replace it, we may use this
- * location for the op and must not save the value in the zero page
- * location.
- */
- CheckDirectOp (D);
-
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
{
CodeEntry* X;
- /* Check the load entry before the push. If it's a lda instruction with an
- * addressing mode that allows us to replace it, we may use this
- * location for the op and must not save the value in the zero page
- * location.
- */
- CheckDirectOp (D);
/* Inline the sbc */
D->IP = D->OpIndex+1;
+static unsigned Opt_tosugeax (StackOpData* D)
+/* Optimize the tosugeax sequence if possible. */
+{
+ CodeEntry* X;
+
+
+ /* Inline the sbc */
+ D->IP = D->OpIndex+1;
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.A.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.A.Flags & LI_RELOAD_Y) == 0) {
+
+ /* cmp ... */
+ CodeEntry* LoadA = D->Rhs.A.LoadEntry;
+ X = NewCodeEntry (OP65_CMP, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.A.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* cmp (sp),y */
+ X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.A.Flags |= LI_REMOVE;
+
+ /* txa */
+ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Must be true because of OP_RHS_LOAD */
+ CHECK ((D->Rhs.X.Flags & LI_DIRECT) != 0);
+
+ /* If the location is on the stack, we need to reload the Y register. */
+ if ((D->Rhs.X.Flags & LI_RELOAD_Y) == 0) {
+
+ /* sbc ... */
+ CodeEntry* LoadX = D->Rhs.X.LoadEntry;
+ X = NewCodeEntry (OP65_SBC, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ } else {
+
+ /* ldy #offs */
+ const char* Arg = MakeHexArg (D->Rhs.X.Offs);
+ X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* sbc (sp),y */
+ X = NewCodeEntry (OP65_SBC, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+ }
+
+ /* In both cases, we can remove the load */
+ D->Rhs.X.Flags |= LI_REMOVE;
+
+ /* lda #$00 */
+ X = NewCodeEntry (OP65_LDA, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* ldx #$00 */
+ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* rol a */
+ X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
+ InsertEntry (D, X, D->IP++);
+
+ /* Remove the push and the call to the tosugeax function */
+ RemoveRemainders (D);
+
+ /* We changed the sequence */
+ return 1;
+}
+
+
+
static unsigned Opt_tosxorax (StackOpData* D)
/* Optimize the tosxorax sequence if possible */
{
CodeEntry* X;
- /* Check the entry before the push. If it's a lda instruction with an
- * addressing mode that allows us to replace it, we may use this
- * location for the op and must not save the value in the zero page
- * location.
- */
- CheckDirectOp (D);
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
{ "staxspidx", Opt_staxspidx, REG_AX, OP_NONE },
{ "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE },
{ "tosandax", Opt_tosandax, REG_NONE, OP_NONE },
+ { "tosgeax", Opt_tosgeax, REG_NONE, OP_RHS_LOAD_DIRECT },
+ { "tosltax", Opt_tosltax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosorax", Opt_tosorax, REG_NONE, OP_NONE },
-#if 1
- { "tossubax", Opt_tossubax, REG_NONE, OP_NONE },
-#endif
+ { "tossubax", Opt_tossubax, REG_NONE, OP_RHS_LOAD_DIRECT },
+ { "tosugeax", Opt_tosugeax, REG_NONE, OP_RHS_LOAD_DIRECT },
{ "tosxorax", Opt_tosxorax, REG_NONE, OP_NONE },
};
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
/* Cannot optimize */
return 0;
}
- if ((D->OptFunc->Flags & OP_LHS_LOAD) != 0 &&
- (D->Lhs.A.LoadIndex < 0 || D->Lhs.X.LoadIndex < 0)) {
- /* Cannot optimize */
- return 0;
+ if ((D->OptFunc->Flags & OP_LHS_LOAD) != 0) {
+ if (D->Lhs.A.LoadIndex < 0 || D->Lhs.X.LoadIndex < 0) {
+ /* Cannot optimize */
+ return 0;
+ } else if ((D->OptFunc->Flags & OP_LHS_LOAD_DIRECT) != 0) {
+ if ((D->Lhs.A.Flags & D->Lhs.X.Flags & LI_DIRECT) == 0) {
+ /* Cannot optimize */
+ return 0;
+ }
+ }
}
- if ((D->OptFunc->Flags & OP_RHS_LOAD) != 0 &&
- (D->Rhs.A.LoadIndex < 0 || D->Rhs.X.LoadIndex < 0)) {
- /* Cannot optimize */
- return 0;
+ if ((D->OptFunc->Flags & OP_RHS_LOAD) != 0) {
+ if (D->Rhs.A.LoadIndex < 0 || D->Rhs.X.LoadIndex < 0) {
+ /* Cannot optimize */
+ return 0;
+ } else if ((D->OptFunc->Flags & OP_RHS_LOAD_DIRECT) != 0) {
+ if ((D->Rhs.A.Flags & D->Rhs.X.Flags & LI_DIRECT) == 0) {
+ /* Cannot optimize */
+ return 0;
+ }
+ }
}
/* Determine the zero page locations to use */
case Initialize:
ResetStackOpData (&Data);
+ State = Search;
/* FALLTHROUGH */
case Search:
FinalizeLoadInfo (&Data.Lhs, S);
FinalizeLoadInfo (&Data.Rhs, S);
+ /* Set flags for direct operations */
+ CheckDirectOp (&Data);
+
/* If the Lhs loads do load from zeropage, we have to include
* them into UsedRegs registers used. The Rhs loads have already
* been tracked.
Data.OpEntry = CS_GetEntry (S, Data.OpIndex);
Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex);
- /* Regenerate register info, since AdjustStackOffset changed
- * the code
- */
- CS_GenRegInfo (S);
-
/* Call the optimizer function */
Changes += Data.OptFunc->Func (&Data);