mirror of
https://github.com/cc65/cc65.git
synced 2024-12-28 06:30:16 +00:00
Better register tracking in the optimizer
git-svn-id: svn://svn.cc65.org/cc65/trunk@812 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
f249ae345e
commit
05eb03b32f
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -58,6 +58,7 @@ OBJS = anonname.o \
|
||||
opcodes.o \
|
||||
preproc.o \
|
||||
pragma.o \
|
||||
reginfo.o \
|
||||
scanner.o \
|
||||
segments.o \
|
||||
stdfunc.o \
|
||||
|
@ -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
|
||||
|
93
src/cc65/reginfo.c
Normal file
93
src/cc65/reginfo.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
95
src/cc65/reginfo.h
Normal file
95
src/cc65/reginfo.h
Normal file
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user