Changed code generated for compares. Fixed bugs in OptStackOps. Still
generates wrong code in at least one place. git-svn-id: svn://svn.cc65.org/cc65/trunk@4063 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -3553,8 +3553,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
case CF_CHAR:
|
case CF_CHAR:
|
||||||
if (flags & CF_FORCECHAR) {
|
if (flags & CF_FORCECHAR) {
|
||||||
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
AddCodeLine ("ldx #$00");
|
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3563,8 +3563,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
case CF_INT:
|
case CF_INT:
|
||||||
/* Just check the high byte */
|
/* Just check the high byte */
|
||||||
AddCodeLine ("cpx #$80"); /* Bit 7 -> carry */
|
AddCodeLine ("cpx #$80"); /* Bit 7 -> carry */
|
||||||
AddCodeLine ("ldx #$00");
|
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3572,8 +3572,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
/* Just check the high byte */
|
/* Just check the high byte */
|
||||||
AddCodeLine ("lda sreg+1");
|
AddCodeLine ("lda sreg+1");
|
||||||
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
AddCodeLine ("ldx #$00");
|
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3595,8 +3595,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
AddCodeLine ("eor #$80");
|
AddCodeLine ("eor #$80");
|
||||||
g_defcodelabel (Label);
|
g_defcodelabel (Label);
|
||||||
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
AddCodeLine ("ldx #$00");
|
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3612,8 +3612,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
AddCodeLine ("eor #$80");
|
AddCodeLine ("eor #$80");
|
||||||
g_defcodelabel (Label);
|
g_defcodelabel (Label);
|
||||||
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
AddCodeLine ("ldx #$00");
|
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3894,6 +3894,8 @@ void g_ge (unsigned flags, unsigned long val)
|
|||||||
"tosgeax", "tosugeax", "tosgeeax", "tosugeeax",
|
"tosgeax", "tosugeax", "tosgeeax", "tosugeeax",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsigned Label;
|
||||||
|
|
||||||
|
|
||||||
/* If the right hand side is const, the lhs is not on stack but still
|
/* If the right hand side is const, the lhs is not on stack but still
|
||||||
* in the primary register.
|
* in the primary register.
|
||||||
@@ -3934,7 +3936,7 @@ void g_ge (unsigned flags, unsigned long val)
|
|||||||
AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
|
AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
|
||||||
AddCodeLine ("lda #$00");
|
AddCodeLine ("lda #$00");
|
||||||
AddCodeLine ("ldx #$00");
|
AddCodeLine ("ldx #$00");
|
||||||
AddCodeLine ("rol a");
|
AddCodeLine ("rol a");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CF_LONG:
|
case CF_LONG:
|
||||||
@@ -3983,8 +3985,51 @@ void g_ge (unsigned flags, unsigned long val)
|
|||||||
default:
|
default:
|
||||||
typeerror (flags);
|
typeerror (flags);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Signed compare against a constant != zero */
|
||||||
|
switch (flags & CF_TYPE) {
|
||||||
|
|
||||||
|
case CF_CHAR:
|
||||||
|
if (flags & CF_FORCECHAR) {
|
||||||
|
Label = GetLocalLabel ();
|
||||||
|
AddCodeLine ("sec");
|
||||||
|
AddCodeLine ("sbc #$%02X", (unsigned char)val);
|
||||||
|
AddCodeLine ("bvs %s", LocalLabelName (Label));
|
||||||
|
AddCodeLine ("eor #$80");
|
||||||
|
g_defcodelabel (Label);
|
||||||
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
|
AddCodeLine ("rol a");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
case CF_INT:
|
||||||
|
/* Do a subtraction */
|
||||||
|
Label = GetLocalLabel ();
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
|
AddCodeLine ("txa");
|
||||||
|
AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
|
||||||
|
AddCodeLine ("bvs %s", LocalLabelName (Label));
|
||||||
|
AddCodeLine ("eor #$80");
|
||||||
|
g_defcodelabel (Label);
|
||||||
|
AddCodeLine ("asl a"); /* Bit 7 -> carry */
|
||||||
|
AddCodeLine ("lda #$00");
|
||||||
|
AddCodeLine ("ldx #$00");
|
||||||
|
AddCodeLine ("rol a");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CF_LONG:
|
||||||
|
/* This one is too costly */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
typeerror (flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||||
|
|||||||
@@ -88,7 +88,9 @@ typedef enum {
|
|||||||
OP_A_KNOWN = 0x01, /* Value of A must be known */
|
OP_A_KNOWN = 0x01, /* Value of A must be known */
|
||||||
OP_X_ZERO = 0x02, /* X must be zero */
|
OP_X_ZERO = 0x02, /* X must be zero */
|
||||||
OP_LHS_LOAD = 0x04, /* Must have load insns for LHS */
|
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;
|
} OP_FLAGS;
|
||||||
|
|
||||||
/* Structure forward decl */
|
/* Structure forward decl */
|
||||||
@@ -887,13 +889,6 @@ static unsigned Opt_tosaddax (StackOpData* D)
|
|||||||
|
|
||||||
} else {
|
} 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 */
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
ReplacePushByStore (D);
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
@@ -956,13 +951,6 @@ static unsigned Opt_tosandax (StackOpData* D)
|
|||||||
{
|
{
|
||||||
CodeEntry* X;
|
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 */
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
ReplacePushByStore (D);
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
@@ -989,18 +977,212 @@ static unsigned Opt_tosandax (StackOpData* 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)
|
static unsigned Opt_tosorax (StackOpData* D)
|
||||||
/* Optimize the tosorax sequence if possible */
|
/* Optimize the tosorax sequence if possible */
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
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 */
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
ReplacePushByStore (D);
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
@@ -1037,12 +1219,6 @@ static unsigned Opt_tossubax (StackOpData* D)
|
|||||||
{
|
{
|
||||||
CodeEntry* X;
|
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 */
|
/* Inline the sbc */
|
||||||
D->IP = D->OpIndex+1;
|
D->IP = D->OpIndex+1;
|
||||||
@@ -1128,17 +1304,97 @@ static unsigned Opt_tossubax (StackOpData* D)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
static unsigned Opt_tosxorax (StackOpData* D)
|
||||||
/* Optimize the tosxorax sequence if possible */
|
/* Optimize the tosxorax sequence if possible */
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
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 */
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
ReplacePushByStore (D);
|
ReplacePushByStore (D);
|
||||||
@@ -1180,10 +1436,11 @@ static const OptFuncDesc FuncTable[] = {
|
|||||||
{ "staxspidx", Opt_staxspidx, REG_AX, OP_NONE },
|
{ "staxspidx", Opt_staxspidx, REG_AX, OP_NONE },
|
||||||
{ "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE },
|
{ "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE },
|
||||||
{ "tosandax", Opt_tosandax, 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 },
|
{ "tosorax", Opt_tosorax, REG_NONE, OP_NONE },
|
||||||
#if 1
|
{ "tossubax", Opt_tossubax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
{ "tossubax", Opt_tossubax, REG_NONE, OP_NONE },
|
{ "tosugeax", Opt_tosugeax, REG_NONE, OP_RHS_LOAD_DIRECT },
|
||||||
#endif
|
|
||||||
{ "tosxorax", Opt_tosxorax, REG_NONE, OP_NONE },
|
{ "tosxorax", Opt_tosxorax, REG_NONE, OP_NONE },
|
||||||
};
|
};
|
||||||
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
|
#define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0]))
|
||||||
@@ -1284,15 +1541,27 @@ static int PreCondOk (StackOpData* D)
|
|||||||
/* Cannot optimize */
|
/* Cannot optimize */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((D->OptFunc->Flags & OP_LHS_LOAD) != 0 &&
|
if ((D->OptFunc->Flags & OP_LHS_LOAD) != 0) {
|
||||||
(D->Lhs.A.LoadIndex < 0 || D->Lhs.X.LoadIndex < 0)) {
|
if (D->Lhs.A.LoadIndex < 0 || D->Lhs.X.LoadIndex < 0) {
|
||||||
/* Cannot optimize */
|
/* Cannot optimize */
|
||||||
return 0;
|
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 &&
|
if ((D->OptFunc->Flags & OP_RHS_LOAD) != 0) {
|
||||||
(D->Rhs.A.LoadIndex < 0 || D->Rhs.X.LoadIndex < 0)) {
|
if (D->Rhs.A.LoadIndex < 0 || D->Rhs.X.LoadIndex < 0) {
|
||||||
/* Cannot optimize */
|
/* Cannot optimize */
|
||||||
return 0;
|
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 */
|
/* Determine the zero page locations to use */
|
||||||
@@ -1369,6 +1638,7 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
|
|
||||||
case Initialize:
|
case Initialize:
|
||||||
ResetStackOpData (&Data);
|
ResetStackOpData (&Data);
|
||||||
|
State = Search;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
case Search:
|
case Search:
|
||||||
@@ -1456,6 +1726,9 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
FinalizeLoadInfo (&Data.Lhs, S);
|
FinalizeLoadInfo (&Data.Lhs, S);
|
||||||
FinalizeLoadInfo (&Data.Rhs, S);
|
FinalizeLoadInfo (&Data.Rhs, S);
|
||||||
|
|
||||||
|
/* Set flags for direct operations */
|
||||||
|
CheckDirectOp (&Data);
|
||||||
|
|
||||||
/* If the Lhs loads do load from zeropage, we have to include
|
/* If the Lhs loads do load from zeropage, we have to include
|
||||||
* them into UsedRegs registers used. The Rhs loads have already
|
* them into UsedRegs registers used. The Rhs loads have already
|
||||||
* been tracked.
|
* been tracked.
|
||||||
@@ -1492,11 +1765,6 @@ unsigned OptStackOps (CodeSeg* S)
|
|||||||
Data.OpEntry = CS_GetEntry (S, Data.OpIndex);
|
Data.OpEntry = CS_GetEntry (S, Data.OpIndex);
|
||||||
Data.NextEntry = CS_GetNextEntry (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 */
|
/* Call the optimizer function */
|
||||||
Changes += Data.OptFunc->Func (&Data);
|
Changes += Data.OptFunc->Func (&Data);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user