X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptstop.c;h=5a512cb206c202348dae6d746da32fce0e384dda;hb=638f54f3e4ad3ee6e6e5ee8043b48ef43324148c;hp=cca49c871eb0db701d70351214f5385160362ff5;hpb=7ce4196829a53194a546c752dfb4239013f0b16b;p=cc65 diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index cca49c871..5a512cb20 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 */ @@ -94,14 +93,27 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop, CodeEntry* E = CS_GetEntry (S, I); - if (E->Use & REG_SP) { - - CodeEntry* P; + int NeedCorrection = 0; + if ((E->Use & REG_SP) != 0) { /* Check for some things that should not happen */ CHECK (E->AM == AM65_ZP_INDY || E->RI->In.RegY >= (short) Offs); CHECK (strcmp (E->Arg, "sp") == 0); + /* We need to correct this one */ + NeedCorrection = 1; + + } else if (CE_IsCallTo (E, "ldaxysp")) { + + /* We need to correct this one */ + NeedCorrection = 1; + + } + + if (NeedCorrection) { + + CodeEntry* P; + /* Get the code entry before this one. If it's a LDY, adjust the * value. */ @@ -196,11 +208,13 @@ 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, D->ZPLo) != 0 && strcmp (E->Arg, D->ZPHi) != 0) { + /* Load indirect with known offset is also ok, provided that + * the zeropage location used is not the same as the one we're + * using for the temp storage. + */ + D->Flags |= (OP_DIRECT | OP_RELOAD_Y); } } } @@ -211,7 +225,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; @@ -229,7 +243,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. */ { @@ -239,7 +253,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++); @@ -286,6 +300,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 */ /*****************************************************************************/ @@ -296,12 +337,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 */ @@ -317,16 +366,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); @@ -335,7 +392,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 */ @@ -385,7 +442,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); @@ -471,7 +528,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); @@ -510,7 +568,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); @@ -594,7 +653,9 @@ static int HarmlessCall (const char* Name) */ { static const char* Tab[] = { + "ldaxidx", "ldaxysp", + "negax", }; void* R = bsearch (Name, @@ -632,8 +693,7 @@ unsigned OptStackOps (CodeSeg* S) * It depends on the code between the two if we can handle/transform the * sequence, so check this code for the following list of things: * - * - there must not be a jump or conditional branch (this may - * get relaxed later). + * - the range must be a basic block (one entry, one exit) * - there may not be accesses to local variables with unknown * offsets (because we have to adjust these offsets). * - no subroutine calls @@ -651,10 +711,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)) || - CE_HasLabel (E)) { + /* 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; @@ -688,7 +754,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 */ @@ -696,6 +762,11 @@ unsigned OptStackOps (CodeSeg* S) } } + /* Determine if we have a basic block */ + if (PreCondOk) { + PreCondOk = CS_IsBasicBlock (S, Push, I); + } + /* If preconditions are ok, call the optimizer function */ if (PreCondOk) { @@ -725,19 +796,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;