From f63964e23c935d7a0b6ea3da887cc08db02a27b0 Mon Sep 17 00:00:00 2001 From: uz Date: Thu, 20 Aug 2009 16:06:20 +0000 Subject: [PATCH] Added several constraints to the optimizer functions to avoid breaking code. git-svn-id: svn://svn.cc65.org/cc65/trunk@4046 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/coptind.c | 53 ++++++++++++++++++++++------------- src/cc65/coptstop.c | 68 ++++++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index eee07f879..135c39f00 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -1319,16 +1319,18 @@ unsigned OptTransfers3 (CodeSeg* S) */ { unsigned Changes = 0; - unsigned Xfer = 0; /* Index of transfer insn */ - unsigned Store = 0; /* Index of store insn */ - CodeEntry* XferEntry = 0; /* Pointer to xfer insn */ - CodeEntry* StoreEntry = 0; /* Pointer to store insn */ + unsigned UsedRegs = REG_NONE; /* Track used registers */ + unsigned Xfer = 0; /* Index of transfer insn */ + unsigned Store = 0; /* Index of store insn */ + CodeEntry* XferEntry = 0; /* Pointer to xfer insn */ + CodeEntry* StoreEntry = 0; /* Pointer to store insn */ enum { - Searching, + Initialize, + Search, FoundXfer, FoundStore - } State = Searching; + } State = Initialize; /* Walk over the entries. Look for a xfer instruction that is followed by * a store later, where the value of the register is not used later. @@ -1341,7 +1343,12 @@ unsigned OptTransfers3 (CodeSeg* S) switch (State) { - case Searching: + case Initialize: + /* Clear the list of used registers */ + UsedRegs = REG_NONE; + /* FALLTHROUGH */ + + case Search: if (E->Info & OF_XFR) { /* Found start of sequence */ Xfer = I; @@ -1358,7 +1365,7 @@ unsigned OptTransfers3 (CodeSeg* S) /* Switch back to searching */ I = Xfer; - State = Searching; + State = Initialize; /* Does this insn use the target register of the transfer? */ } else if ((E->Use & XferEntry->Chg) != 0) { @@ -1373,7 +1380,7 @@ unsigned OptTransfers3 (CodeSeg* S) State = FoundStore; } else { I = Xfer; - State = Searching; + State = Initialize; } /* Does this insn change the target register of the transfer? */ @@ -1384,15 +1391,18 @@ unsigned OptTransfers3 (CodeSeg* S) * do that and bail out instead. */ I = Xfer; - State = Searching; + State = Initialize; /* Does this insn have a label? */ } else if (CE_HasLabel (E)) { /* Too complex to handle - bail out */ I = Xfer; - State = Searching; + State = Initialize; + } else { + /* Track used registers */ + UsedRegs |= E->Use; } break; @@ -1402,7 +1412,10 @@ unsigned OptTransfers3 (CodeSeg* S) * replace the transfer by a store and remove the store here. */ if ((GetRegInfo (S, I, XferEntry->Chg) & XferEntry->Chg) == 0 && - (StoreEntry->AM == AM65_ABS || StoreEntry->AM == AM65_ZP) && + (StoreEntry->AM == AM65_ABS || + StoreEntry->AM == AM65_ZP) && + (StoreEntry->AM != AM65_ZP || + (StoreEntry->Chg & UsedRegs) == 0) && !MemAccess (S, Xfer+1, Store-1, StoreEntry->Arg)) { /* Generate the replacement store insn */ @@ -1469,7 +1482,7 @@ unsigned OptTransfers3 (CodeSeg* S) /* Restart after last xfer insn */ I = Xfer; } - State = Searching; + State = Initialize; break; } @@ -1496,10 +1509,10 @@ unsigned OptTransfers4 (CodeSeg* S) CodeEntry* XferEntry = 0; /* Pointer to xfer insn */ enum { - Searching, + Search, FoundLoad, FoundXfer - } State = Searching; + } State = Search; /* Walk over the entries. Look for a load instruction that is followed by * a load later. @@ -1512,7 +1525,7 @@ unsigned OptTransfers4 (CodeSeg* S) switch (State) { - case Searching: + case Search: if (E->Info & OF_LOAD) { /* Found start of sequence */ Load = I; @@ -1529,7 +1542,7 @@ unsigned OptTransfers4 (CodeSeg* S) /* Switch back to searching */ I = Load; - State = Searching; + State = Search; /* Does this insn use the target register of the load? */ } else if ((E->Use & LoadEntry->Chg) != 0) { @@ -1544,7 +1557,7 @@ unsigned OptTransfers4 (CodeSeg* S) State = FoundXfer; } else { I = Load; - State = Searching; + State = Search; } /* Does this insn change the target register of the load? */ @@ -1555,7 +1568,7 @@ unsigned OptTransfers4 (CodeSeg* S) * do that and bail out instead. */ I = Load; - State = Searching; + State = Search; } break; @@ -1627,7 +1640,7 @@ unsigned OptTransfers4 (CodeSeg* S) /* Restart after last xfer insn */ I = Xfer; } - State = Searching; + State = Search; break; } diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 4c960dd06..08d98311d 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -54,9 +54,8 @@ /* Flags for the functions */ typedef enum { STOP_NONE = 0x00, /* Nothing special */ - STOP_A_UNUSED = 0x01, /* Call only if a unused later */ - STOP_A_KNOWN = 0x02, /* Call only if A is known */ - STOP_X_ZERO = 0x04 /* Call only if X is zero */ + STOP_A_KNOWN = 0x01, /* Call only if A is known */ + STOP_X_ZERO = 0x02 /* Call only if X is zero */ } STOP_FLAGS; /* Structure forward decl */ @@ -68,6 +67,7 @@ typedef struct OptFuncDesc OptFuncDesc; struct OptFuncDesc { const char* Name; /* Name of the replaced runtime function */ OptFunc Func; /* Function pointer */ + unsigned UnusedRegs; /* Regs that must not be used later */ STOP_FLAGS Flags; /* Flags */ }; @@ -180,7 +180,7 @@ static void AdjustStackOffset (StackOpData* D, unsigned Offs) /* If we need the value of Y later, be sure to reload it */ if (RegYUsed (D->Code, I+1)) { - const char* Arg = MakeHexArg (E->RI->In.RegY); + const char* Arg = MakeHexArg (E->RI->In.RegY); CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); CS_InsertEntry (D->Code, X, I+1); @@ -644,7 +644,7 @@ static unsigned Opt_staxspidx (StackOpData* D) X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); InsertEntry (D, X, D->OpIndex+4); - /* If we remove staspidx, we must restore the Y register to what the + /* If we remove staxspidx, we must restore the Y register to what the * function would return. */ X = NewCodeEntry (OP65_LDY, AM65_IMM, "$00", 0, D->OpEntry->LI); @@ -952,14 +952,14 @@ static unsigned Opt_tosxorax (StackOpData* D) static const OptFuncDesc FuncTable[] = { - { "__bzero", Opt___bzero, STOP_X_ZERO | STOP_A_KNOWN }, - { "staspidx", Opt_staspidx, STOP_NONE }, - { "staxspidx", Opt_staxspidx, STOP_A_UNUSED }, - { "tosaddax", Opt_tosaddax, STOP_NONE }, - { "tosandax", Opt_tosandax, STOP_NONE }, - { "tosorax", Opt_tosorax, STOP_NONE }, - { "tossubax", Opt_tossubax, STOP_NONE }, - { "tosxorax", Opt_tosxorax, STOP_NONE }, + { "__bzero", Opt___bzero, REG_NONE, STOP_X_ZERO | STOP_A_KNOWN }, + { "staspidx", Opt_staspidx, REG_NONE, STOP_NONE }, + { "staxspidx", Opt_staxspidx, REG_AX, STOP_NONE }, + { "tosaddax", Opt_tosaddax, REG_NONE, STOP_NONE }, + { "tosandax", Opt_tosandax, REG_NONE, STOP_NONE }, + { "tosorax", Opt_tosorax, REG_NONE, STOP_NONE }, + { "tossubax", Opt_tossubax, REG_NONE, STOP_NONE }, + { "tosxorax", Opt_tosxorax, REG_NONE, STOP_NONE }, }; #define FUNC_COUNT (sizeof(FuncTable) / sizeof(FuncTable[0])) @@ -1048,16 +1048,19 @@ static int PreCondOk (StackOpData* D) */ { /* Check the flags */ - if ((D->OptFunc->Flags & STOP_A_UNUSED) != 0 && - RegAUsed (D->Code, D->OpIndex+1)) { + unsigned UnusedRegs = D->OptFunc->UnusedRegs; + if (UnusedRegs != REG_NONE && + (GetRegInfo (D->Code, D->OpIndex+1, UnusedRegs) & UnusedRegs) != 0) { /* Cannot optimize */ return 0; - } else if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 && - RegValIsUnknown (D->OpEntry->RI->In.RegA)) { + } + if ((D->OptFunc->Flags & STOP_A_KNOWN) != 0 && + RegValIsUnknown (D->OpEntry->RI->In.RegA)) { /* Cannot optimize */ return 0; - } else if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 && - D->OpEntry->RI->In.RegX != 0) { + } + if ((D->OptFunc->Flags & STOP_X_ZERO) != 0 && + D->OpEntry->RI->In.RegX != 0) { /* Cannot optimize */ return 0; } @@ -1237,6 +1240,23 @@ unsigned OptStackOps (CodeSeg* S) /* Track zero page location usage beyond this point */ Data.UsedRegs |= GetRegInfo (S, I, REG_SREG | REG_PTR1 | REG_PTR2); + /* Get the entry pointers to the load insns. If these insns + * load from zero page, we have to include them into UsedRegs + * registers used. + */ + if (Data.LoadAIndex >= 0) { + Data.LoadAEntry = CS_GetEntry (S, Data.LoadAIndex); + if (Data.LoadAEntry->AM == AM65_ZP) { + Data.UsedRegs |= Data.LoadAEntry->Use; + } + } + if (Data.LoadXIndex >= 0) { + Data.LoadXEntry = CS_GetEntry (S, Data.LoadXIndex); + if (Data.LoadXEntry->AM == AM65_ZP) { + Data.UsedRegs |= Data.LoadXEntry->Use; + } + } + /* Check the preconditions. If they aren't ok, reset the insn * pointer to the pushax and start over. We will loose part of * load tracking but at least a/x has probably lost between @@ -1249,18 +1269,10 @@ unsigned OptStackOps (CodeSeg* S) break; } - /* Preconditions are ok, so call the optimizer function */ - /* Adjust stack offsets to account for the upcoming removal */ AdjustStackOffset (&Data, 2); - /* Prepare the remainder of the data structure */ - if (Data.LoadAIndex >= 0) { - Data.LoadAEntry = CS_GetEntry (S, Data.LoadAIndex); - } - if (Data.LoadXIndex >= 0) { - Data.LoadXEntry = CS_GetEntry (S, Data.LoadXIndex); - } + /* Prepare the remainder of the data structure. */ Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex); Data.PushEntry = CS_GetEntry (S, Data.PushIndex); Data.OpEntry = CS_GetEntry (S, Data.OpIndex); -- 2.39.2