X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptstop.c;h=4f83b8ef5b64de7d7965b165c56d494eb299d391;hb=73dfa23c987d8a7f1154801b85c171f9e01dcd58;hp=ed51fe1306b859d4a40900ac54312369fdd105fb;hpb=c61729a15ad1da563addc233dbafb2b30dda9b22;p=cc65 diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index ed51fe130..4f83b8ef5 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -34,6 +34,7 @@ #include +#include /* cc65 */ #include "codeent.h" @@ -66,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 */ @@ -207,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 && - RegValIsKnown (E->RI->In.RegY) && - (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); } } } @@ -222,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; @@ -240,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. */ { @@ -250,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++); @@ -297,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 */ /*****************************************************************************/ @@ -307,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 */ @@ -328,12 +368,20 @@ 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); @@ -346,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 */ @@ -607,8 +655,9 @@ static int HarmlessCall (const char* Name) */ { static const char* Tab[] = { - "ldaxidx", + "ldaxidx", "ldaxysp", + "negax", }; void* R = bsearch (Name, @@ -664,8 +713,16 @@ unsigned OptStackOps (CodeSeg* S) /* Handling depends if we're inside a sequence or not */ if (InSeq) { - if (((E->Use & REG_SP) != 0 && - (E->AM != AM65_ZP_INDY || RegValIsUnknown (E->RI->In.RegY)))) { + /* 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;