X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptstop.c;h=f00410fa5e251a40d4d3fcd32ff903f95f6021b2;hb=35e1184901ca38bdb2e56d154ed3b71f6096eacc;hp=a7f6e80ebcb2eb5ce61df53efc1b38e98b6c0950;hpb=d85e6f91243cd709a41f53bc3ea685515a06dbed;p=cc65 diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index a7f6e80eb..f00410fa5 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -42,6 +42,7 @@ #include "codeent.h" #include "codeinfo.h" #include "coptstop.h" +#include "error.h" @@ -56,8 +57,8 @@ typedef enum { LI_NONE = 0x00, LI_DIRECT = 0x01, /* Direct op may be used */ LI_RELOAD_Y = 0x02, /* Reload index register Y */ - LI_TRANSFER = 0x04, /* Loaded value is transfered */ - LI_REMOVE = 0x08, /* Load may be removed */ + LI_REMOVE = 0x04, /* Load may be removed */ + LI_DUP_LOAD = 0x08, /* Duplicate load */ } LI_FLAGS; /* Structure that tells us how to load the lhs values */ @@ -68,7 +69,7 @@ struct LoadRegInfo { CodeEntry* LoadEntry; /* The actual entry, 0 if invalid */ int XferIndex; /* Index of transfer insn */ CodeEntry* XferEntry; /* The actual transfer entry */ - unsigned char Offs; /* Stack offset if data is on stack */ + int Offs; /* Stack offset if data is on stack */ }; /* Now combined for both registers */ @@ -152,18 +153,10 @@ struct StackOpData { static void ClearLoadRegInfo (LoadRegInfo* RI) /* Clear a LoadRegInfo struct */ { - RI->LoadIndex = -1; - RI->XferIndex = -1; RI->Flags = LI_NONE; -} - - - -static void InvalidateLoadRegInfo (LoadRegInfo* RI) -/* Invalidate a LoadRegInfo struct */ -{ RI->LoadIndex = -1; RI->XferIndex = -1; + RI->Offs = 0; } @@ -256,55 +249,114 @@ static void TrackLoads (LoadInfo* LI, CodeEntry* E, int I) /* Track loads for a code entry */ { if (E->Info & OF_LOAD) { + + LoadRegInfo* RI = 0; + + /* Determine, which register was loaded */ if (E->Chg & REG_A) { - LI->A.LoadIndex = I; - LI->A.XferIndex = -1; + RI = &LI->A; + } else if (E->Chg & REG_X) { + RI = &LI->X; + } else if (E->Chg & REG_Y) { + RI = &LI->Y; } - if (E->Chg & REG_X) { - LI->X.LoadIndex = I; - LI->X.XferIndex = -1; + CHECK (RI != 0); + + /* If we had a load or xfer op before, this is a duplicate load which + * can cause problems if it encountered between the pushax and the op, + * so remember it. + */ + if (RI->LoadIndex >= 0 || RI->XferIndex >= 0) { + RI->Flags |= LI_DUP_LOAD; } - if (E->Chg & REG_Y) { - LI->Y.LoadIndex = I; - LI->Y.XferIndex = -1; + + /* Remember the load */ + RI->LoadIndex = I; + RI->XferIndex = -1; + + /* Set load flags */ + RI->Flags &= ~(LI_DIRECT | LI_RELOAD_Y); + if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { + /* These insns are all ok and replaceable */ + RI->Flags |= LI_DIRECT; + } 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. + */ + RI->Offs = (unsigned char) E->RI->In.RegY; + RI->Flags |= (LI_DIRECT | LI_RELOAD_Y); } + + } else if (E->Info & OF_XFR) { + + /* Determine source and target of the transfer and handle the TSX insn */ + LoadRegInfo* Src; + LoadRegInfo* Tgt; switch (E->OPC) { - case OP65_TAX: - LI->X.LoadIndex = LI->A.LoadIndex; - LI->X.XferIndex = I; - break; - case OP65_TAY: - LI->Y.LoadIndex = LI->A.LoadIndex; - LI->Y.XferIndex = I; - break; - case OP65_TXA: - LI->A.LoadIndex = LI->X.LoadIndex; - LI->A.XferIndex = I; - break; - case OP65_TYA: - LI->A.LoadIndex = LI->Y.LoadIndex; - LI->A.XferIndex = I; - break; - default: - break; + case OP65_TAX: Src = &LI->A; Tgt = &LI->X; break; + case OP65_TAY: Src = &LI->A; Tgt = &LI->Y; break; + case OP65_TXA: Src = &LI->X; Tgt = &LI->A; break; + case OP65_TYA: Src = &LI->Y; Tgt = &LI->A; break; + case OP65_TSX: ClearLoadRegInfo (&LI->X); return; + case OP65_TXS: return; + default: Internal ("Unknown XFR insn in TrackLoads"); + } + + /* If we had a load or xfer op before, this is a duplicate load which + * can cause problems if it encountered between the pushax and the op, + * so remember it. + */ + if (Tgt->LoadIndex >= 0 || Tgt->XferIndex >= 0) { + Tgt->Flags |= LI_DUP_LOAD; + } + + /* Transfer the data */ + Tgt->LoadIndex = Src->LoadIndex; + Tgt->XferIndex = I; + Tgt->Offs = Src->Offs; + Tgt->Flags &= ~(LI_DIRECT | LI_RELOAD_Y); + Tgt->Flags |= Src->Flags & (LI_DIRECT | LI_RELOAD_Y); + + } else if (CE_IsCallTo (E, "ldaxysp") && RegValIsKnown (E->RI->In.RegY)) { + + /* If we had a load or xfer op before, this is a duplicate load which + * can cause problems if it encountered between the pushax and the op, + * so remember it for both registers involved. + */ + if (LI->A.LoadIndex >= 0 || LI->A.XferIndex >= 0) { + LI->A.Flags |= LI_DUP_LOAD; + } + if (LI->X.LoadIndex >= 0 || LI->X.XferIndex >= 0) { + LI->X.Flags |= LI_DUP_LOAD; } - } else if (CE_IsCallTo (E, "ldaxysp")) { + /* Both registers set, Y changed */ LI->A.LoadIndex = I; LI->A.XferIndex = -1; + LI->A.Flags |= (LI_DIRECT | LI_RELOAD_Y); + LI->A.Offs = (unsigned char) E->RI->In.RegY - 1; + LI->X.LoadIndex = I; LI->X.XferIndex = -1; - InvalidateLoadRegInfo (&LI->Y); + LI->X.Flags |= (LI_DIRECT | LI_RELOAD_Y); + LI->X.Offs = (unsigned char) E->RI->In.RegY; + + ClearLoadRegInfo (&LI->Y); } else { if (E->Chg & REG_A) { - InvalidateLoadRegInfo (&LI->A); + ClearLoadRegInfo (&LI->A); } if (E->Chg & REG_X) { - InvalidateLoadRegInfo (&LI->X); + ClearLoadRegInfo (&LI->X); } if (E->Chg & REG_Y) { - InvalidateLoadRegInfo (&LI->Y); + ClearLoadRegInfo (&LI->Y); } } } @@ -312,7 +364,7 @@ static void TrackLoads (LoadInfo* LI, CodeEntry* E, int I) /*****************************************************************************/ -/* Helpers */ +/* Helpers */ /*****************************************************************************/ @@ -443,68 +495,6 @@ static void AdjustStackOffset (StackOpData* D, unsigned Offs) -static void CheckOneDirectOp (LoadRegInfo* LI, unsigned char Offs) -/* Check if the given entry is a lda instruction with an addressing mode - * that allows us to replace it by another operation (like ora). If so, we may - * use this location for the or and must not save the value in the zero - * page location. - */ -{ - /* Get the load entry */ - CodeEntry* E = LI->LoadEntry; - if (E == 0) { - /* No load insn */ - return; - } - - /* Check the load entry */ - if (E) { - /* Must check the call first since addressing mode is ABS, so second - * "if" will catch otherwise. - */ - if (CE_IsCallTo (E, "ldaxysp")) { - /* Same as single loads from stack. Since we must distinguish - * between A and X here, the necessary offset is passed to the - * function as a parameter. - */ - LI->Offs = (unsigned char) E->RI->In.RegY - Offs; - LI->Flags |= (LI_DIRECT | LI_RELOAD_Y); - } else if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { - /* These insns are all ok and replaceable */ - LI->Flags |= LI_DIRECT; - } 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. - */ - LI->Offs = (unsigned char) E->RI->In.RegY; - LI->Flags |= (LI_DIRECT | LI_RELOAD_Y); - } - } -} - - - -static void CheckDirectOp (StackOpData* D) -/* Check if the given entry is a lda instruction with an addressing mode - * that allows us to replace it by another operation (like ora). If so, we may - * use this location for the or and must not save the value in the zero - * page location. - */ -{ - /* Check flags for all load instructions */ - CheckOneDirectOp (&D->Lhs.A, 1); - CheckOneDirectOp (&D->Lhs.X, 0); - CheckOneDirectOp (&D->Rhs.A, 1); - CheckOneDirectOp (&D->Rhs.X, 0); -} - - - static void AddStoreA (StackOpData* D) /* Add a store to zero page after the push insn */ { @@ -1697,6 +1687,10 @@ static int PreCondOk (StackOpData* D) } } } + if ((D->Rhs.A.Flags | D->Rhs.X.Flags) & LI_DUP_LOAD) { + /* Cannot optimize */ + return 0; + } /* Determine the zero page locations to use */ if ((D->UsedRegs & REG_PTR1) == REG_NONE) { @@ -1730,7 +1724,8 @@ unsigned OptStackOps (CodeSeg* S) { unsigned Changes = 0; /* Number of changes in one run */ StackOpData Data; - unsigned I; + int I; + int OldEntryCount; /* Old number of entries */ enum { Initialize, @@ -1762,7 +1757,7 @@ unsigned OptStackOps (CodeSeg* S) * intermediate code for zero page use. */ I = 0; - while (I < CS_GetEntryCount (S)) { + while (I < (int)CS_GetEntryCount (S)) { /* Get the next entry */ CodeEntry* E = CS_GetEntry (S, I); @@ -1779,6 +1774,10 @@ unsigned OptStackOps (CodeSeg* S) /* While searching, track register load insns, so we can tell * what is in a register once pushax is encountered. */ + if (CE_HasLabel (E)) { + /* Currently we don't track across branches */ + ClearLoadInfo (&Data.Lhs); + } if (CE_IsCallTo (E, "pushax")) { Data.PushIndex = I; State = FoundPush; @@ -1793,6 +1792,10 @@ unsigned OptStackOps (CodeSeg* S) * follow and in the meantime, track zeropage usage and check * for code that will disable us from translating the sequence. */ + if (CE_HasLabel (E)) { + /* Currently we don't track across branches */ + ClearLoadInfo (&Data.Rhs); + } if (E->OPC == OP65_JSR) { /* Subroutine call: Check if this is one of the functions, @@ -1860,9 +1863,6 @@ 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. @@ -1891,6 +1891,9 @@ unsigned OptStackOps (CodeSeg* S) Data.OpEntry = CS_GetEntry (S, Data.OpIndex); Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex); + /* Remember the current number of code lines */ + OldEntryCount = CS_GetEntryCount (S); + /* Adjust stack offsets to account for the upcoming removal */ AdjustStackOffset (&Data, 2); @@ -1902,12 +1905,17 @@ unsigned OptStackOps (CodeSeg* S) /* Call the optimizer function */ Changes += Data.OptFunc->Func (&Data); + /* Since the function may have added or deleted entries, + * correct the index. + */ + I += CS_GetEntryCount (S) - OldEntryCount; + /* Regenerate register info */ CS_GenRegInfo (S); /* Done */ State = Initialize; - break; + continue; }