From: cuz Date: Tue, 24 Jul 2001 17:07:33 +0000 (+0000) Subject: Better register tracking in the optimizer X-Git-Tag: V2.12.0~2763 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=05eb03b32f8cbe3eb40aabcc7ee528238b94fc8d;p=cc65 Better register tracking in the optimizer git-svn-id: svn://svn.cc65.org/cc65/trunk@812 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index fbbd5b6e7..e6f9fe542 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -161,7 +161,7 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D) CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg, - CodeLabel* JumpTo, LineInfo* LI) + CodeLabel* JumpTo, LineInfo* LI) /* Create a new code entry, initialize and return it */ { /* Get the opcode description */ @@ -179,6 +179,7 @@ CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg, E->Size = GetInsnSize (E->OPC, E->AM); E->JumpTo = JumpTo; E->LI = UseLineInfo (LI); + E->RI = 0; SetUseChgInfo (E, D); InitCollection (&E->Labels); @@ -205,6 +206,9 @@ void FreeCodeEntry (CodeEntry* E) /* Release the line info */ ReleaseLineInfo (E->LI); + /* Delete the register info */ + CE_FreeRegInfo (E); + /* Free the entry */ xfree (E); } @@ -273,6 +277,384 @@ void CE_SetArg (CodeEntry* E, const char* Arg) +int CE_KnownImm (const CodeEntry* E) +/* Return true if the argument of E is a known immediate value */ +{ + return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0); +} + + + +void CE_FreeRegInfo (CodeEntry* E) +/* Free an existing register info struct */ +{ + if (E->RI) { + FreeRegInfo (E->RI); + E->RI = 0; + } +} + + + +void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) +/* Generate register info for this instruction. If an old info exists, it is + * overwritten. + */ +{ + /* Pointers to the register contents */ + RegContents* In; + RegContents* Out; + + /* Function register usage */ + unsigned char Use, Chg; + + /* If we don't have a register info struct, allocate one. */ + if (E->RI == 0) { + E->RI = NewRegInfo (InputRegs); + } else { + if (InputRegs) { + E->RI->In = *InputRegs; + } else { + RC_Invalidate (&E->RI->In); + } + E->RI->Out = E->RI->In; + } + + /* Get pointers to the register contents */ + In = &E->RI->In; + Out = &E->RI->Out; + + /* Handle the different instructions */ + switch (E->OPC) { + + case OP65_ADC: + /* We don't know the value of the carry, so the result is + * always unknown. + */ + Out->RegA = -1; + break; + + case OP65_AND: + if (In->RegA >= 0) { + if (CE_KnownImm (E)) { + Out->RegA = In->RegA & (short) E->Num; + } else { + Out->RegA = -1; + } + } + break; + + case OP65_ASL: + if (E->AM == AM65_ACC && In->RegA >= 0) { + Out->RegA = (In->RegA << 1) & 0xFF; + } + break; + + case OP65_BCC: + break; + + case OP65_BCS: + break; + + case OP65_BEQ: + break; + + case OP65_BIT: + break; + + case OP65_BMI: + break; + + case OP65_BNE: + break; + + case OP65_BPL: + break; + + case OP65_BRA: + break; + + case OP65_BRK: + break; + + case OP65_BVC: + break; + + case OP65_BVS: + break; + + case OP65_CLC: + break; + + case OP65_CLD: + break; + + case OP65_CLI: + break; + + case OP65_CLV: + break; + + case OP65_CMP: + break; + + case OP65_CPX: + break; + + case OP65_CPY: + break; + + case OP65_DEA: + if (In->RegA >= 0) { + Out->RegA = In->RegA - 1; + } + break; + + case OP65_DEC: + if (E->AM == AM65_ACC && In->RegA >= 0) { + Out->RegA = In->RegA - 1; + } + break; + + case OP65_DEX: + if (In->RegX >= 0) { + Out->RegX = In->RegX - 1; + } + break; + + case OP65_DEY: + if (In->RegY >= 0) { + Out->RegY = In->RegY - 1; + } + break; + + case OP65_EOR: + if (In->RegA >= 0) { + if (CE_KnownImm (E)) { + Out->RegA = In->RegA ^ (short) E->Num; + } else { + Out->RegA = -1; + } + } + break; + + case OP65_INA: + if (In->RegA >= 0) { + Out->RegA = In->RegA + 1; + } + break; + + case OP65_INC: + if (E->AM == AM65_ACC && In->RegA >= 0) { + Out->RegA = In->RegA + 1; + } + break; + + case OP65_INX: + if (In->RegX >= 0) { + Out->RegX = In->RegX + 1; + } + break; + + case OP65_INY: + if (In->RegY >= 0) { + Out->RegY = In->RegY + 1; + } + break; + + case OP65_JCC: + break; + + case OP65_JCS: + break; + + case OP65_JEQ: + break; + + case OP65_JMI: + break; + + case OP65_JMP: + break; + + case OP65_JNE: + break; + + case OP65_JPL: + break; + + case OP65_JSR: + /* Get the code info for the function */ + GetFuncInfo (E->Arg, &Use, &Chg); + if (Chg & REG_A) { + Out->RegA = -1; + } + if (Chg & REG_X) { + Out->RegX = -1; + } + if (Chg & REG_Y) { + Out->RegY = -1; + } + break; + + case OP65_JVC: + break; + + case OP65_JVS: + break; + + case OP65_LDA: + if (CE_KnownImm (E)) { + Out->RegA = (unsigned char) E->Num; + } else { + /* A is now unknown */ + Out->RegA = -1; + } + break; + + case OP65_LDX: + if (CE_KnownImm (E)) { + Out->RegX = (unsigned char) E->Num; + } else { + /* X is now unknown */ + Out->RegX = -1; + } + break; + + case OP65_LDY: + if (CE_KnownImm (E)) { + Out->RegY = (unsigned char) E->Num; + } else { + /* Y is now unknown */ + Out->RegY = -1; + } + break; + + case OP65_LSR: + if (E->AM == AM65_ACC && In->RegA >= 0) { + Out->RegA = (In->RegA >> 1) & 0xFF; + } + break; + + case OP65_NOP: + break; + + case OP65_ORA: + if (In->RegA >= 0) { + if (CE_KnownImm (E)) { + Out->RegA = In->RegA | (short) E->Num; + } else { + /* A is now unknown */ + Out->RegA = -1; + } + } + break; + + case OP65_PHA: + break; + + case OP65_PHP: + break; + + case OP65_PHX: + break; + + case OP65_PHY: + break; + + case OP65_PLA: + Out->RegA = -1; + break; + + case OP65_PLP: + break; + + case OP65_PLX: + Out->RegX = -1; + break; + + case OP65_PLY: + Out->RegY = -1; + break; + + case OP65_ROL: + Out->RegA = -1; + break; + + case OP65_ROR: + Out->RegA = -1; + break; + + case OP65_RTI: + break; + + case OP65_RTS: + break; + + case OP65_SBC: + /* We don't know the value of the carry bit */ + Out->RegA = -1; + break; + + case OP65_SEC: + break; + + case OP65_SED: + break; + + case OP65_SEI: + break; + + case OP65_STA: + break; + + case OP65_STX: + break; + + case OP65_STY: + break; + + case OP65_TAX: + Out->RegX = In->RegA; + break; + + case OP65_TAY: + Out->RegY = In->RegA; + break; + + case OP65_TRB: + /* For now... */ + Out->RegA = -1; + break; + + case OP65_TSB: + /* For now... */ + Out->RegA = -1; + break; + + case OP65_TSX: + Out->RegX = -1; + break; + + case OP65_TXA: + Out->RegA = In->RegX; + break; + + case OP65_TXS: + break; + + case OP65_TYA: + Out->RegA = In->RegY; + break; + + default: + break; + + } +} + + + void CE_Output (const CodeEntry* E, FILE* F) /* Output the code entry to a file */ { @@ -311,7 +693,7 @@ void CE_Output (const CodeEntry* E, FILE* F) /* immidiate */ Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg); break; - + case AM_ABS: case AM65_ZP: case AM65_ABS: diff --git a/src/cc65/codeent.h b/src/cc65/codeent.h index 278e471bd..c698f7a56 100644 --- a/src/cc65/codeent.h +++ b/src/cc65/codeent.h @@ -48,6 +48,7 @@ #include "codelab.h" #include "lineinfo.h" #include "opcodes.h" +#include "reginfo.h" @@ -76,6 +77,7 @@ struct CodeEntry { CodeLabel* JumpTo; /* Jump label */ Collection Labels; /* Labels for this instruction */ LineInfo* LI; /* Source line info for this insn */ + RegInfo* RI; /* Register info for this insn */ }; @@ -87,7 +89,7 @@ struct CodeEntry { CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg, - CodeLabel* JumpTo, LineInfo* LI); + CodeLabel* JumpTo, LineInfo* LI); /* Create a new code entry, initialize and return it */ void FreeCodeEntry (CodeEntry* E); @@ -170,6 +172,17 @@ INLINE void CE_ResetMark (CodeEntry* E) void CE_SetArg (CodeEntry* E, const char* Arg); /* Set a new argument for the given code entry. An old string is deleted. */ +int CE_KnownImm (const CodeEntry* E); +/* Return true if the argument of E is a known immediate value */ + +void CE_FreeRegInfo (CodeEntry* E); +/* Free an existing register info struct */ + +void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs); +/* Generate register info for this instruction. If an old info exists, it is + * overwritten. + */ + void CE_Output (const CodeEntry* E, FILE* F); /* Output the code entry to a file */ @@ -180,4 +193,4 @@ void CE_Output (const CodeEntry* E, FILE* F); - + diff --git a/src/cc65/codelab.h b/src/cc65/codelab.h index c2871c9bc..8f298e0fb 100644 --- a/src/cc65/codelab.h +++ b/src/cc65/codelab.h @@ -85,6 +85,26 @@ CodeLabel* NewCodeLabel (const char* Name, unsigned Hash); void FreeCodeLabel (CodeLabel* L); /* Free the given code label */ +#if defined(HAVE_INLINE) +INLINE unsigned CL_GetRefCount (const CodeLabel* L) +/* Get the number of references for this label */ +{ + return CollCount (&L->JumpFrom); +} +#else +# define CL_GetRefCount(L) CollCount (&(L)->JumpFrom) +#endif + +#if defined(HAVE_INLINE) +INLINE struct CodeEntry* CL_GetRef (CodeLabel* L, unsigned Index) +/* Get a code entry referencing this label */ +{ + return CollAt (&L->JumpFrom, Index); +} +#else +# define CL_GetRef(L, Index) CollAt (&(L)->JumpFrom, (Index)) +#endif + void CL_AddRef (CodeLabel* L, struct CodeEntry* E); /* Let the CodeEntry E reference the label L */ diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index a82073aa4..84c32797c 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -63,7 +63,7 @@ static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E) -/* Move all labels from the label pool to the given entry and remove them +/* Move all labels from the label pool to the given entry and remove them * from the pool. */ { @@ -545,7 +545,7 @@ void CS_DelEntry (CodeSeg* S, unsigned Index) FreeCodeEntry (E); } - + void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count) /* Delete a range of code entries. This includes removing references to labels, @@ -1000,4 +1000,104 @@ void CS_Output (const CodeSeg* S, FILE* F) +void CS_FreeRegInfo (CodeSeg* S) +/* Free register infos for all instructions */ +{ + unsigned I; + for (I = 0; I < CS_GetEntryCount (S); ++I) { + CE_FreeRegInfo (CS_GetEntry(S, I)); + } +} + + + +void CS_GenRegInfo (CodeSeg* S) +/* Generate register infos for all instructions */ +{ + unsigned I; + RegContents Regs; + RegContents* CurrentRegs; + int WasJump; + + /* Be sure to delete all register infos */ + CS_FreeRegInfo (S); + + /* On entry, the register contents are unknown */ + RC_Invalidate (&Regs); + CurrentRegs = &Regs; + + /* First pass. Walk over all insns an note just the changes from one + * insn to the next one. + */ + WasJump = 0; + for (I = 0; I < CS_GetEntryCount (S); ++I) { + + /* Get the next instruction */ + CodeEntry* E = CollAtUnchecked (&S->Entries, I); + + /* If the instruction has a label, we need some special handling */ + unsigned LabelCount = CE_GetLabelCount (E); + if (LabelCount > 0) { + + /* Loop over all entry points that jump here. If these entry + * points already have register info, check if all values are + * known and identical. If all values are identical, and the + * preceeding instruction was not an unconditional branch, check + * if the register value on exit of the preceeding instruction + * is also identical. If all these values are identical, the + * value of a register is known, otherwise it is unknown. + */ + CodeLabel* Label = CE_GetLabel (E, 0); + unsigned Entry; + if (WasJump) { + /* Preceeding insn was an unconditional branch */ + CodeEntry* J = CL_GetRef(Label, 0); + if (J->RI) { + Regs = J->RI->Out; + } else { + RC_Invalidate (&Regs); + } + Entry = 1; + } else { + Regs = *CurrentRegs; + Entry = 0; + } + + while (Entry < CL_GetRefCount (Label)) { + /* Get this entry */ + CodeEntry* J = CL_GetRef (Label, Entry); + if (J->RI == 0) { + /* No register info for this entry, bail out */ + RC_Invalidate (&Regs); + break; + } + if (J->RI->Out.RegA != Regs.RegA) { + Regs.RegA = -1; + } + if (J->RI->Out.RegX != Regs.RegX) { + Regs.RegX = -1; + } + if (J->RI->Out.RegY != Regs.RegY) { + Regs.RegY = -1; + } + ++Entry; + } + + /* Use this register info */ + CurrentRegs = &Regs; + + } + + /* Generate register info for this instruction */ + CE_GenRegInfo (E, CurrentRegs); + + /* Output registers for this insn are input for the next */ + CurrentRegs = &E->RI->Out; + + /* Remember for the next insn if this insn was an uncondition branch */ + WasJump = (E->Info & OF_UBRA) != 0; + } +} + + diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index 59353e889..99342f423 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -215,6 +215,12 @@ INLINE unsigned CS_GetEntryCount (const CodeSeg* S) # define CS_GetEntryCount(S) CollCount (&(S)->Entries) #endif +void CS_FreeRegInfo (CodeSeg* S); +/* Free register infos for all instructions */ + +void CS_GenRegInfo (CodeSeg* S); +/* Generate register infos for all instructions */ + /* End of codeseg.h */ diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index ba1ffdc7f..36ca5b3d7 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -56,20 +56,6 @@ -/*****************************************************************************/ -/* Helpers */ -/*****************************************************************************/ - - - -static int IsKnownImm (const CodeEntry* E) -/* Return true if the argument of E is a known immediate value */ -{ - return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0); -} - - - /*****************************************************************************/ /* Replace jumps to RTS by RTS */ /*****************************************************************************/ @@ -670,312 +656,56 @@ unsigned OptDuplicateLoads (CodeSeg* S) /* Remove loads of registers where the value loaded is already in the register. */ { unsigned Changes = 0; + unsigned I; - /* Remember the last load instructions for all registers */ - int RegA = -1; - int RegX = -1; - int RegY = -1; + /* Generate register info for this step */ + CS_GenRegInfo (S); /* Walk over the entries */ - unsigned I = 0; + I = 0; while (I < CS_GetEntryCount (S)) { - unsigned char Use, Chg; - CodeEntry* N; + CodeEntry* N; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); - /* Assume we won't delete the entry */ - int Delete = 0; - - /* If this entry has a label attached, remove all knownledge about the - * register contents. This may be improved but for now it's ok. - */ - if (CE_HasLabel (E)) { - RegA = RegX = RegY = -1; - } + /* Assume we won't delete the entry */ + int Delete = 0; /* Handle the different instructions */ switch (E->OPC) { - case OP65_ADC: - /* We don't know the value of the carry, so the result is - * always unknown. - */ - RegA = -1; - break; - - case OP65_AND: - if (RegA >= 0) { - if (IsKnownImm (E)) { - RegA &= (int) E->Num; - } else { - RegA = -1; - } - } - break; - - case OP65_ASL: - if (RegA >= 0) { - RegA = (RegA << 1) & 0xFF; - } - break; - - case OP65_BCC: - break; - - case OP65_BCS: - break; - - case OP65_BEQ: - break; - - case OP65_BIT: - break; - - case OP65_BMI: - break; - - case OP65_BNE: - break; - - case OP65_BPL: - break; - - case OP65_BRA: - break; - - case OP65_BRK: - break; - - case OP65_BVC: - break; - - case OP65_BVS: - break; - - case OP65_CLC: - break; - - case OP65_CLD: - break; - - case OP65_CLI: - break; - - case OP65_CLV: - break; - - case OP65_CMP: - break; - - case OP65_CPX: - break; - - case OP65_CPY: - break; - - case OP65_DEA: - DEC (RegA, 1); - break; - - case OP65_DEC: - break; - - case OP65_DEX: - DEC (RegX, 1); - break; - - case OP65_DEY: - DEC (RegY, 1); - break; - - case OP65_EOR: - if (RegA >= 0) { - if (IsKnownImm (E)) { - RegA ^= (int) E->Num; - } else { - RegA = -1; - } - } - break; - - case OP65_INA: - INC (RegA, 1); - break; - - case OP65_INC: - break; - - case OP65_INX: - INC (RegX, 1); - break; - - case OP65_INY: - INC (RegY, 1); - break; - - case OP65_JCC: - break; - - case OP65_JCS: - break; - - case OP65_JEQ: - break; - - case OP65_JMI: - break; - - case OP65_JMP: - break; - - case OP65_JNE: - break; - - case OP65_JPL: - break; - - case OP65_JSR: - /* Get the code info for the function */ - GetFuncInfo (E->Arg, &Use, &Chg); - if (Chg & REG_A) { - RegA = -1; - } - if (Chg & REG_X) { - RegX = -1; - } - if (Chg & REG_Y) { - RegY = -1; - } - break; - - case OP65_JVC: - break; - - case OP65_JVS: - break; - case OP65_LDA: - if (IsKnownImm (E)) { - N = CS_GetNextEntry (S, I); - if (RegA >= 0 && RegA == E->Num && N && (N->Info & OF_FBRA) == 0) { - Delete = 1; - } else { - RegA = (unsigned char) E->Num; - } - } else { - /* A is now unknown */ - RegA = -1; + if (E->RI->In.RegA >= 0 && /* Value of A is known */ + CE_KnownImm (E) && /* Value to be loaded is known */ + E->RI->In.RegA == E->Num && /* Both are equal */ + (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ + (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + Delete = 1; } break; case OP65_LDX: - if (IsKnownImm (E)) { - N = CS_GetNextEntry (S, I); - if (RegX >= 0 && RegX == E->Num && N && (N->Info & OF_FBRA) == 0) { - Delete = 1; - } else { - RegX = (unsigned char) E->Num; - } - } else { - /* X is now unknown */ - RegX = -1; + if (E->RI->In.RegX >= 0 && /* Value of X is known */ + CE_KnownImm (E) && /* Value to be loaded is known */ + E->RI->In.RegX == E->Num && /* Both are equal */ + (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ + (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + Delete = 1; } break; case OP65_LDY: - if (IsKnownImm (E)) { - N = CS_GetNextEntry (S, I); - if (RegY >= 0 && RegY == E->Num && N && (N->Info & OF_FBRA) == 0) { - Delete = 1; - } else { - RegY = (unsigned char) E->Num; - } - } else { - /* Y is now unknown */ - RegY = -1; - } - break; - - case OP65_LSR: - if (RegA >= 0) { - RegA = (RegA >> 1) & 0xFF; - } - break; - - case OP65_NOP: - break; - - case OP65_ORA: - if (RegA >= 0) { - if (IsKnownImm (E)) { - RegA |= (unsigned char) E->Num; - } else { - /* A is now unknown */ - RegA = -1; - } + if (E->RI->In.RegY >= 0 && /* Value of Y is known */ + CE_KnownImm (E) && /* Value to be loaded is known */ + E->RI->In.RegY == E->Num && /* Both are equal */ + (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ + (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + Delete = 1; } break; - case OP65_PHA: - break; - - case OP65_PHP: - break; - - case OP65_PHX: - break; - - case OP65_PHY: - break; - - case OP65_PLA: - RegA = -1; - break; - - case OP65_PLP: - break; - - case OP65_PLX: - RegX = -1; - break; - - case OP65_PLY: - RegY = -1; - break; - - case OP65_ROL: - RegA = -1; - break; - - case OP65_ROR: - RegA = -1; - break; - - case OP65_RTI: - break; - - case OP65_RTS: - break; - - case OP65_SBC: - RegA = -1; - break; - - case OP65_SEC: - break; - - case OP65_SED: - break; - - case OP65_SEI: - break; - - case OP65_STA: - break; - case OP65_STX: /* If the value in the X register is known and the same as * that in the A register, replace the store by a STA. The @@ -983,11 +713,13 @@ unsigned OptDuplicateLoads (CodeSeg* S) * later. STX does support the zeropage,y addressing mode, * so be sure to check for that. */ - if (RegX >= 0 && RegX == RegA && - E->AM != AM65_ABSY && E->AM != AM65_ZPY) { + if (E->RI->In.RegX >= 0 && + E->RI->In.RegX == E->RI->In.RegA && + E->AM != AM65_ABSY && + E->AM != AM65_ZPY) { /* Use the A register instead */ - CE_ReplaceOPC (E, OP65_STA); - } + CE_ReplaceOPC (E, OP65_STA); + } break; case OP65_STY: @@ -998,65 +730,54 @@ unsigned OptDuplicateLoads (CodeSeg* S) * replacement by X, but check for invalid addressing modes * in this case. */ - if (RegY >= 0) { - if (RegY == RegA) { - CE_ReplaceOPC (E, OP65_STA); - } else if (RegY == RegX && E->AM != AM65_ABSX && E->AM != AM65_ZPX) { - CE_ReplaceOPC (E, OP65_STX); + if (E->RI->In.RegY >= 0) { + if (E->RI->In.RegY == E->RI->In.RegA) { + CE_ReplaceOPC (E, OP65_STA); + } else if (E->RI->In.RegY == E->RI->In.RegX && + E->AM != AM65_ABSX && + E->AM != AM65_ZPX) { + CE_ReplaceOPC (E, OP65_STX); } } break; case OP65_TAX: - N = CS_GetNextEntry (S, I); - if (RegA >= 0 && RegA == RegX && N && (N->Info & OF_FBRA) == 0) { + if (E->RI->In.RegA >= 0 && + E->RI->In.RegA == E->RI->In.RegX && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->Info & OF_FBRA) == 0) { /* Value is identical and not followed by a branch */ Delete = 1; - } else { - RegX = RegA; } break; case OP65_TAY: - N = CS_GetNextEntry (S, I); - if (RegA >= 0 && RegA == RegY && N && (N->Info & OF_FBRA) == 0) { + if (E->RI->In.RegA >= 0 && + E->RI->In.RegA == E->RI->In.RegY && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->Info & OF_FBRA) == 0) { /* Value is identical and not followed by a branch */ Delete = 1; - } else { - RegY = RegA; } break; - case OP65_TRB: - break; - - case OP65_TSB: - break; - - case OP65_TSX: - RegX = -1; - break; - - case OP65_TXA: - N = CS_GetNextEntry (S, I); - if (RegX >= 0 && RegX == RegA && N && (N->Info & OF_FBRA) == 0) { + case OP65_TXA: + if (E->RI->In.RegX >= 0 && + E->RI->In.RegX == E->RI->In.RegA && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->Info & OF_FBRA) == 0) { /* Value is identical and not followed by a branch */ Delete = 1; - } else { - RegA = RegX; } break; - case OP65_TXS: - break; - case OP65_TYA: - N = CS_GetNextEntry (S, I); - if (RegY >= 0 && RegY == RegA && N && (N->Info & OF_FBRA) == 0) { + if (E->RI->In.RegY >= 0 && + E->RI->In.RegY == E->RI->In.RegA && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->Info & OF_FBRA) == 0) { /* Value is identical and not followed by a branch */ Delete = 1; - } else { - RegA = RegY; } break; diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index ff780220c..38db8dffd 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -58,6 +58,7 @@ OBJS = anonname.o \ opcodes.o \ preproc.o \ pragma.o \ + reginfo.o \ scanner.o \ segments.o \ stdfunc.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 4b90b5dfe..62a982120 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -103,6 +103,7 @@ OBJS = anonname.obj \ opcodes.obj \ preproc.obj \ pragma.obj \ + reginfo.obj \ scanner.obj \ segments.obj \ stdfunc.obj \ @@ -170,6 +171,7 @@ FILE main.obj FILE opcodes.obj FILE preproc.obj FILE pragma.obj +FILE reginfo.obj FILE scanner.obj FILE segments.obj FILE stdfunc.obj diff --git a/src/cc65/reginfo.c b/src/cc65/reginfo.c new file mode 100644 index 000000000..f62dd3791 --- /dev/null +++ b/src/cc65/reginfo.c @@ -0,0 +1,93 @@ +/*****************************************************************************/ +/* */ +/* reginfo.c */ +/* */ +/* 6502 register tracking info */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* common */ +#include "xmalloc.h" + +/* cc65 */ +#include "reginfo.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void RC_Invalidate (RegContents* C) +/* Invalidate all registers */ +{ + C->RegA = -1; + C->RegX = -1; + C->RegY = -1; + C->SRegLo = -1; + C->SRegHi = -1; +} + + + +RegInfo* NewRegInfo (const RegContents* RC) +/* Allocate a new register info, initialize and return it. If RC is not + * a NULL pointer, it is used to initialize both, the input and output + * registers. If the pointer is NULL, all registers are set to unknown. + */ +{ + /* Allocate memory */ + RegInfo* RI = xmalloc (sizeof (RegInfo)); + + /* Initialize the registers */ + if (RC) { + RI->In = *RC; + RI->Out = *RC; + } else { + RC_Invalidate (&RI->In); + RC_Invalidate (&RI->Out); + } + + /* Return the new struct */ + return RI; +} + + + +void FreeRegInfo (RegInfo* RI) +/* Free a RegInfo struct */ +{ + xfree (RI); +} + + + diff --git a/src/cc65/reginfo.h b/src/cc65/reginfo.h new file mode 100644 index 000000000..21415a819 --- /dev/null +++ b/src/cc65/reginfo.h @@ -0,0 +1,95 @@ +/*****************************************************************************/ +/* */ +/* reginfo.h */ +/* */ +/* 6502 register tracking info */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef REGINFO_H +#define REGINFO_H + + + +/* common */ +#include "inline.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Register contents */ +typedef struct RegContents RegContents; +struct RegContents { + short RegA; + short RegX; + short RegY; + short SRegLo; + short SRegHi; +}; + +/* Register change info */ +typedef struct RegInfo RegInfo; +struct RegInfo { + RegContents In; /* Incoming register values */ + RegContents Out; /* Outgoing register values */ +}; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void RC_Invalidate (RegContents* C); +/* Invalidate all registers */ + +RegInfo* NewRegInfo (const RegContents* RC); +/* Allocate a new register info, initialize and return it. If RC is not + * a NULL pointer, it is used to initialize both, the input and output + * registers. If the pointer is NULL, all registers are set to unknown. + */ + +void FreeRegInfo (RegInfo* RI); +/* Free a RegInfo struct */ + + + +/* End of reginfo.h */ +#endif + + +