X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptstop.c;h=4f83b8ef5b64de7d7965b165c56d494eb299d391;hb=73dfa23c987d8a7f1154801b85c171f9e01dcd58;hp=625ddfe709e70f39022af2be7e687ca04734e1ff;hpb=a0496ca53d4355d50027f91a21ccfe413c79ca39;p=cc65 diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 625ddfe70..4f83b8ef5 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -34,12 +34,11 @@ #include +#include /* cc65 */ #include "codeent.h" #include "codeinfo.h" -#include "codeopt.h" -#include "error.h" #include "coptstop.h" @@ -68,7 +67,7 @@ struct StackOpData { /* Flags returned by DirectOp */ #define OP_DIRECT 0x01 /* Direct op may be used */ -#define OP_ONSTACK 0x02 /* Operand is on stack */ +#define OP_RELOAD_Y 0x02 /* Must reload index register Y */ @@ -104,7 +103,7 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop, /* We need to correct this one */ NeedCorrection = 1; - } else if (CE_IsCall (E, "ldaxysp")) { + } else if (CE_IsCallTo (E, "ldaxysp")) { /* We need to correct this one */ NeedCorrection = 1; @@ -209,11 +208,15 @@ static void CheckDirectOp (StackOpData* D) if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { /* These insns are all ok and replaceable */ D->Flags |= OP_DIRECT; - } else if (E->AM == AM65_ZP_INDY && - E->RI->In.RegY >= 0 && - (E->Use & REG_SP) != 0) { - /* Load from stack with known offset is also ok */ - D->Flags |= (OP_DIRECT | OP_ONSTACK); + } else if (E->AM == AM65_ZP_INDY && RegValIsKnown (E->RI->In.RegY) && + strcmp (E->Arg, "sp") == 0) { + /* A load from the stack with known offset is also ok, but in this + * case we must reload the index register later. Please note that + * a load indirect via other zero page locations is not ok, since + * these locations may change between the push and the actual + * operation. + */ + D->Flags |= (OP_DIRECT | OP_RELOAD_Y); } } } @@ -224,7 +227,7 @@ static void ReplacePushByStore (StackOpData* D) /* Replace the call to the push subroutine by a store into the zero page * location (actually, the push is not replaced, because we need it for * later, but the name is still ok since the push will get removed at the - * end of each routine. + * end of each routine). */ { CodeEntry* X; @@ -242,7 +245,7 @@ static void ReplacePushByStore (StackOpData* D) static void AddOpLow (StackOpData* D, opc_t OPC) /* Add an op for the low byte of an operator. This function honours the - * OP_DIRECT and OP_ONSTACK flags and generates the necessary instructions. + * OP_DIRECT and OP_RELOAD_Y flags and generates the necessary instructions. * All code is inserted at the current insertion point. */ { @@ -252,7 +255,7 @@ static void AddOpLow (StackOpData* D, opc_t OPC) /* Op with a variable location. If the location is on the stack, we * need to reload the Y register. */ - if ((D->Flags & OP_ONSTACK) != 0) { + if ((D->Flags & OP_RELOAD_Y) != 0) { const char* Arg = MakeHexArg (D->PrevEntry->RI->In.RegY); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI); InsertEntry (D, X, D->IP++); @@ -299,6 +302,33 @@ static void RemovePushAndOp (StackOpData* D) +static const char* IsRegVar (const StackOpData* D) +/* If the value pushed is that of a register variable, return the name of the + * entry in the register bank. Otherwise return NULL. + */ +{ + CodeEntry* P; + + if (D->PushIndex >= 2 && + (P = D->PrevEntry) != 0 && + P->OPC == OP65_LDX && + P->AM == AM65_ZP && + strncmp (P->Arg, "regbank+", 7) == 0 && + isdigit (P->Arg[8]) && + (P = CS_GetEntry (D->Code, D->PushIndex-2)) != 0 && + P->OPC == OP65_LDA && + P->AM == AM65_ZP && + strncmp (P->Arg, "regbank+", 7) == 0 && + isdigit (P->Arg[8])) { + /* Ok, it loads the register variable */ + return P->Arg; + } else { + return 0; + } +} + + + /*****************************************************************************/ /* Actual optimization functions */ /*****************************************************************************/ @@ -309,12 +339,20 @@ static unsigned Opt_staspidx (StackOpData* D) /* Optimize the staspidx sequence if possible */ { CodeEntry* X; + const char* ZPLo; - /* Store the value into the zeropage instead of pushing it */ - ReplacePushByStore (D); + /* Check if we're using a register variable */ + if ((ZPLo = IsRegVar (D)) == 0) { + + /* Store the value into the zeropage instead of pushing it */ + ReplacePushByStore (D); + + /* Use the given zero page loc */ + ZPLo = D->ZPLo; + } /* Replace the store subroutine call by a direct op */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI); InsertEntry (D, X, D->OpIndex+1); /* Remove the push and the call to the staspidx function */ @@ -330,16 +368,24 @@ static unsigned Opt_staxspidx (StackOpData* D) /* Optimize the staxspidx sequence if possible */ { CodeEntry* X; + const char* ZPLo; - /* Store the value into the zeropage instead of pushing it */ - ReplacePushByStore (D); + /* Check if we're using a register variable */ + if ((ZPLo = IsRegVar (D)) == 0) { + + /* Store the value into the zeropage instead of pushing it */ + ReplacePushByStore (D); + + /* Use the given zero page loc */ + ZPLo = D->ZPLo; + } /* Inline the store */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI); InsertEntry (D, X, D->OpIndex+1); X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI); InsertEntry (D, X, D->OpIndex+2); - if (D->OpEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Value of X is known */ const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -348,7 +394,7 @@ static unsigned Opt_staxspidx (StackOpData* D) X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI); } InsertEntry (D, X, D->OpIndex+3); - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI); InsertEntry (D, X, D->OpIndex+4); /* Remove the push and the call to the staspidx function */ @@ -398,7 +444,7 @@ static unsigned Opt_tosaddax (StackOpData* D) } else if (D->OpEntry->RI->In.RegX == 0) { /* The high byte is that of the first operand plus carry */ CodeLabel* L; - if (D->PushEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX)) { /* Value of first op high byte is known */ const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -484,7 +530,8 @@ static unsigned Opt_tosorax (StackOpData* D) AddOpLow (D, OP65_ORA); /* High byte */ - if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX) && + RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Both values known, precalculate the result */ const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX | D->OpEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -523,7 +570,8 @@ static unsigned Opt_tosxorax (StackOpData* D) AddOpLow (D, OP65_EOR); /* High byte */ - if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX) && + RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Both values known, precalculate the result */ const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX ^ D->OpEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -607,7 +655,9 @@ static int HarmlessCall (const char* Name) */ { static const char* Tab[] = { + "ldaxidx", "ldaxysp", + "negax", }; void* R = bsearch (Name, @@ -663,9 +713,16 @@ unsigned OptStackOps (CodeSeg* S) /* Handling depends if we're inside a sequence or not */ if (InSeq) { - if ((E->Info & OF_BRA) != 0 || - ((E->Use & REG_SP) != 0 && - (E->AM != AM65_ZP_INDY || E->RI->In.RegY < 0))) { + /* If we are using the stack, and we don't have "indirect Y" + * addressing mode, or the value of Y is unknown, or less than + * two, we cannot cope with this piece of code. Having an unknown + * value of Y means that we cannot correct the stack offset, while + * having an offset less than two means that the code works with + * the value on stack which is to be removed. + */ + if ((E->Use & REG_SP) != 0 && + (E->AM != AM65_ZP_INDY || RegValIsUnknown (E->RI->In.RegY) || + E->RI->In.RegY < 2)) { /* All this stuff is not allowed in a sequence */ InSeq = 0; @@ -699,7 +756,7 @@ unsigned OptStackOps (CodeSeg* S) Data.ZPLo = "ptr1"; Data.ZPHi = "ptr1+1"; } else if ((UsedRegs & REG_PTR2) == REG_NONE) { - Data.ZPLo = "ptr2"; + Data.ZPLo = "ptr2"; Data.ZPHi = "ptr2+1"; } else { /* No registers available */ @@ -741,19 +798,20 @@ unsigned OptStackOps (CodeSeg* S) /* Restart the sequence */ Push = I; UsedRegs = REG_NONE; - } else if (!HarmlessCall (E->Arg)) { + } else if (HarmlessCall (E->Arg)) { + /* Track zeropage register usage */ + UsedRegs |= (E->Use | E->Chg); + } else { /* A call to an unkown subroutine ends the sequence */ InSeq = 0; } } else { - /* Other stuff: Track zeropage register usage */ UsedRegs |= (E->Use | E->Chg); - } - } else if (CE_IsCall (E, "pushax")) { + } else if (CE_IsCallTo (E, "pushax")) { /* This starts a sequence */ Push = I;