1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-26 17:36:57 +00:00

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:
uz 2009-08-28 16:32:58 +00:00
parent 1b2e0f66cc
commit f66cd4a13f
2 changed files with 370 additions and 57 deletions

View File

@ -3553,8 +3553,8 @@ void g_lt (unsigned flags, unsigned long val)
case CF_CHAR:
if (flags & CF_FORCECHAR) {
AddCodeLine ("asl a"); /* Bit 7 -> carry */
AddCodeLine ("ldx #$00");
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
return;
}
@ -3563,8 +3563,8 @@ void g_lt (unsigned flags, unsigned long val)
case CF_INT:
/* Just check the high byte */
AddCodeLine ("cpx #$80"); /* Bit 7 -> carry */
AddCodeLine ("ldx #$00");
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
return;
@ -3572,8 +3572,8 @@ void g_lt (unsigned flags, unsigned long val)
/* Just check the high byte */
AddCodeLine ("lda sreg+1");
AddCodeLine ("asl a"); /* Bit 7 -> carry */
AddCodeLine ("ldx #$00");
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
return;
@ -3595,8 +3595,8 @@ void g_lt (unsigned flags, unsigned long val)
AddCodeLine ("eor #$80");
g_defcodelabel (Label);
AddCodeLine ("asl a"); /* Bit 7 -> carry */
AddCodeLine ("ldx #$00");
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
return;
}
@ -3612,8 +3612,8 @@ void g_lt (unsigned flags, unsigned long val)
AddCodeLine ("eor #$80");
g_defcodelabel (Label);
AddCodeLine ("asl a"); /* Bit 7 -> carry */
AddCodeLine ("ldx #$00");
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
return;
@ -3894,6 +3894,8 @@ void g_ge (unsigned flags, unsigned long val)
"tosgeax", "tosugeax", "tosgeeax", "tosugeeax",
};
unsigned Label;
/* If the right hand side is const, the lhs is not on stack but still
* in the primary register.
@ -3934,7 +3936,7 @@ void g_ge (unsigned flags, unsigned long val)
AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
AddCodeLine ("lda #$00");
AddCodeLine ("ldx #$00");
AddCodeLine ("rol a");
AddCodeLine ("rol a");
return;
case CF_LONG:
@ -3983,8 +3985,51 @@ void g_ge (unsigned flags, unsigned long val)
default:
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
* into the normal, non-optimized stuff. Note: The standard stuff will

View File

@ -88,7 +88,9 @@ typedef enum {
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 */
@ -887,13 +889,6 @@ static unsigned Opt_tosaddax (StackOpData* D)
} 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);
@ -956,13 +951,6 @@ static unsigned Opt_tosandax (StackOpData* 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);
@ -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)
/* 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);
@ -1037,12 +1219,6 @@ static unsigned Opt_tossubax (StackOpData* 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;
@ -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)
/* 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);
@ -1180,10 +1436,11 @@ static const OptFuncDesc FuncTable[] = {
{ "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]))
@ -1284,15 +1541,27 @@ static int PreCondOk (StackOpData* D)
/* 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 */
@ -1369,6 +1638,7 @@ unsigned OptStackOps (CodeSeg* S)
case Initialize:
ResetStackOpData (&Data);
State = Search;
/* FALLTHROUGH */
case Search:
@ -1456,6 +1726,9 @@ unsigned OptStackOps (CodeSeg* S)
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.
@ -1492,11 +1765,6 @@ unsigned OptStackOps (CodeSeg* S)
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);