mirror of
https://github.com/cc65/cc65.git
synced 2025-08-08 06:25:17 +00:00
Added 65C02 specific optimizations.
Make two runs over the code when generating register info to get info for backward jumps right. git-svn-id: svn://svn.cc65.org/cc65/trunk@1049 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -48,6 +48,7 @@
|
|||||||
#include "codeent.h"
|
#include "codeent.h"
|
||||||
#include "codeinfo.h"
|
#include "codeinfo.h"
|
||||||
#include "coptadd.h"
|
#include "coptadd.h"
|
||||||
|
#include "coptc02.h"
|
||||||
#include "coptcmp.h"
|
#include "coptcmp.h"
|
||||||
#include "coptind.h"
|
#include "coptind.h"
|
||||||
#include "coptneg.h"
|
#include "coptneg.h"
|
||||||
@@ -1349,6 +1350,7 @@ struct OptFunc {
|
|||||||
#define OptFuncEntry(func) static OptFuncDesc D##func = { func, #func, 0 }
|
#define OptFuncEntry(func) static OptFuncDesc D##func = { func, #func, 0 }
|
||||||
|
|
||||||
/* A list of all the function descriptions */
|
/* A list of all the function descriptions */
|
||||||
|
static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 0, 0, 0, 0, 0 };
|
||||||
@@ -1401,6 +1403,7 @@ static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0,
|
|||||||
|
|
||||||
/* Table containing all the steps in alphabetical order */
|
/* Table containing all the steps in alphabetical order */
|
||||||
static OptFunc* OptFuncs[] = {
|
static OptFunc* OptFuncs[] = {
|
||||||
|
&DOpt65C02Ind,
|
||||||
&DOptAdd1,
|
&DOptAdd1,
|
||||||
&DOptAdd2,
|
&DOptAdd2,
|
||||||
&DOptAdd3,
|
&DOptAdd3,
|
||||||
@@ -1750,7 +1753,24 @@ static void RunOptGroup3 (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
static void RunOptGroup4 (CodeSeg* S)
|
static void RunOptGroup4 (CodeSeg* S)
|
||||||
/* The last group of optimization steps. Adjust branches.
|
/* 65C02 specific optimizations. */
|
||||||
|
{
|
||||||
|
if (CPU < CPU_65C02) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace (zp),y by (zp) if Y is zero. If we have changes, run register
|
||||||
|
* load optimization again, since loads of Y may have become unnecessary.
|
||||||
|
*/
|
||||||
|
if (RunOptFunc (S, &DOpt65C02Ind, 1) > 0) {
|
||||||
|
RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void RunOptGroup5 (CodeSeg* S)
|
||||||
|
/* The last group of optimization steps. Adjust branches, do size optimizations.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* Optimize for size, that is replace operations by shorter ones, even
|
/* Optimize for size, that is replace operations by shorter ones, even
|
||||||
@@ -1805,6 +1825,7 @@ void RunOpt (CodeSeg* S)
|
|||||||
RunOptGroup2 (S);
|
RunOptGroup2 (S);
|
||||||
RunOptGroup3 (S);
|
RunOptGroup3 (S);
|
||||||
RunOptGroup4 (S);
|
RunOptGroup4 (S);
|
||||||
|
RunOptGroup5 (S);
|
||||||
|
|
||||||
/* Write statistics */
|
/* Write statistics */
|
||||||
if (StatFileName) {
|
if (StatFileName) {
|
||||||
|
@@ -160,7 +160,7 @@ static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name,
|
static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name,
|
||||||
void (*ErrorFunc) (const char*, ...))
|
void (*ErrorFunc) (const char*, ...))
|
||||||
/* Add a code label for the next instruction to follow */
|
/* Add a code label for the next instruction to follow */
|
||||||
{
|
{
|
||||||
@@ -1109,217 +1109,232 @@ void CS_GenRegInfo (CodeSeg* S)
|
|||||||
RegContents Regs; /* Initial register contents */
|
RegContents Regs; /* Initial register contents */
|
||||||
RegContents* CurrentRegs; /* Current register contents */
|
RegContents* CurrentRegs; /* Current register contents */
|
||||||
int WasJump; /* True if last insn was a jump */
|
int WasJump; /* True if last insn was a jump */
|
||||||
|
int Done; /* All runs done flag */
|
||||||
|
|
||||||
/* Be sure to delete all register infos */
|
/* Be sure to delete all register infos */
|
||||||
CS_FreeRegInfo (S);
|
CS_FreeRegInfo (S);
|
||||||
|
|
||||||
/* On entry, the register contents are unknown */
|
/* We may need two runs to get back references right */
|
||||||
RC_Invalidate (&Regs);
|
do {
|
||||||
CurrentRegs = &Regs;
|
|
||||||
|
|
||||||
/* First pass. Walk over all insns and note just the changes from one
|
/* Assume we're done after this run */
|
||||||
* insn to the next one.
|
Done = 1;
|
||||||
*/
|
|
||||||
WasJump = 0;
|
/* On entry, the register contents are unknown */
|
||||||
for (I = 0; I < CS_GetEntryCount (S); ++I) {
|
RC_Invalidate (&Regs);
|
||||||
|
CurrentRegs = &Regs;
|
||||||
|
|
||||||
CodeEntry* P;
|
/* Walk over all insns and note just the changes from one insn to the
|
||||||
|
* next one.
|
||||||
/* 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->Out2;
|
|
||||||
} 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->Out2.RegA != Regs.RegA) {
|
|
||||||
Regs.RegA = -1;
|
|
||||||
}
|
|
||||||
if (J->RI->Out2.RegX != Regs.RegX) {
|
|
||||||
Regs.RegX = -1;
|
|
||||||
}
|
|
||||||
if (J->RI->Out2.RegY != Regs.RegY) {
|
|
||||||
Regs.RegY = -1;
|
|
||||||
}
|
|
||||||
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
|
|
||||||
Regs.SRegLo = -1;
|
|
||||||
}
|
|
||||||
if (J->RI->Out2.SRegHi != Regs.SRegHi) {
|
|
||||||
Regs.SRegHi = -1;
|
|
||||||
}
|
|
||||||
++Entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use this register info */
|
|
||||||
CurrentRegs = &Regs;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate register info for this instruction */
|
|
||||||
CE_GenRegInfo (E, CurrentRegs);
|
|
||||||
|
|
||||||
/* Remember for the next insn if this insn was an uncondition branch */
|
|
||||||
WasJump = (E->Info & OF_UBRA) != 0;
|
|
||||||
|
|
||||||
/* Output registers for this insn are input for the next */
|
|
||||||
CurrentRegs = &E->RI->Out;
|
|
||||||
|
|
||||||
/* If this insn is a branch on zero flag, we may have more info on
|
|
||||||
* register contents for one of both flow directions, but only if
|
|
||||||
* there is a previous instruction.
|
|
||||||
*/
|
*/
|
||||||
if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
|
WasJump = 0;
|
||||||
|
for (I = 0; I < CS_GetEntryCount (S); ++I) {
|
||||||
|
|
||||||
/* Get the branch condition */
|
CodeEntry* P;
|
||||||
bc_t BC = GetBranchCond (E->OPC);
|
|
||||||
|
|
||||||
/* Check the previous instruction */
|
/* Get the next instruction */
|
||||||
switch (P->OPC) {
|
CodeEntry* E = CollAtUnchecked (&S->Entries, I);
|
||||||
|
|
||||||
case OP65_ADC:
|
/* If the instruction has a label, we need some special handling */
|
||||||
case OP65_AND:
|
unsigned LabelCount = CE_GetLabelCount (E);
|
||||||
case OP65_DEA:
|
if (LabelCount > 0) {
|
||||||
case OP65_EOR:
|
|
||||||
case OP65_INA:
|
/* Loop over all entry points that jump here. If these entry
|
||||||
case OP65_LDA:
|
* points already have register info, check if all values are
|
||||||
case OP65_ORA:
|
* known and identical. If all values are identical, and the
|
||||||
case OP65_PLA:
|
* preceeding instruction was not an unconditional branch, check
|
||||||
case OP65_SBC:
|
* if the register value on exit of the preceeding instruction
|
||||||
/* A is zero in one execution flow direction */
|
* is also identical. If all these values are identical, the
|
||||||
if (BC == BC_EQ) {
|
* value of a register is known, otherwise it is unknown.
|
||||||
E->RI->Out2.RegA = 0;
|
*/
|
||||||
|
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->Out2;
|
||||||
} else {
|
} else {
|
||||||
E->RI->Out.RegA = 0;
|
RC_Invalidate (&Regs);
|
||||||
}
|
}
|
||||||
break;
|
Entry = 1;
|
||||||
|
} else {
|
||||||
|
Regs = *CurrentRegs;
|
||||||
|
Entry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
case OP65_CMP:
|
while (Entry < CL_GetRefCount (Label)) {
|
||||||
/* If this is an immidiate compare, the A register has
|
/* Get this entry */
|
||||||
* the value of the compare later.
|
CodeEntry* J = CL_GetRef (Label, Entry);
|
||||||
*/
|
if (J->RI == 0) {
|
||||||
if (CE_KnownImm (P)) {
|
/* No register info for this entry. This means that the
|
||||||
if (BC == BC_EQ) {
|
* instruction that jumps here is at higher addresses and
|
||||||
E->RI->Out2.RegA = (unsigned char)P->Num;
|
* the jump is a backward jump. We need a second run to
|
||||||
} else {
|
* get the register info right in this case. Until then,
|
||||||
E->RI->Out.RegA = (unsigned char)P->Num;
|
* assume unknown register contents.
|
||||||
}
|
*/
|
||||||
}
|
Done = 0;
|
||||||
break;
|
RC_Invalidate (&Regs);
|
||||||
|
break;
|
||||||
case OP65_CPX:
|
|
||||||
/* If this is an immidiate compare, the X register has
|
|
||||||
* the value of the compare later.
|
|
||||||
*/
|
|
||||||
if (CE_KnownImm (P)) {
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegX = (unsigned char)P->Num;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegX = (unsigned char)P->Num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP65_CPY:
|
|
||||||
/* If this is an immidiate compare, the Y register has
|
|
||||||
* the value of the compare later.
|
|
||||||
*/
|
|
||||||
if (CE_KnownImm (P)) {
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegY = (unsigned char)P->Num;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegY = (unsigned char)P->Num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OP65_DEX:
|
|
||||||
case OP65_INX:
|
|
||||||
case OP65_LDX:
|
|
||||||
case OP65_PLX:
|
|
||||||
/* X is zero in one execution flow direction */
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegX = 0;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegX = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
if (J->RI->Out2.RegA != Regs.RegA) {
|
||||||
|
Regs.RegA = -1;
|
||||||
case OP65_DEY:
|
|
||||||
case OP65_INY:
|
|
||||||
case OP65_LDY:
|
|
||||||
case OP65_PLY:
|
|
||||||
/* X is zero in one execution flow direction */
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegY = 0;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegY = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
if (J->RI->Out2.RegX != Regs.RegX) {
|
||||||
|
Regs.RegX = -1;
|
||||||
case OP65_TAX:
|
|
||||||
case OP65_TXA:
|
|
||||||
/* If the branch is a beq, both A and X are zero at the
|
|
||||||
* branch target, otherwise they are zero at the next
|
|
||||||
* insn.
|
|
||||||
*/
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegA = E->RI->Out.RegX = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
if (J->RI->Out2.RegY != Regs.RegY) {
|
||||||
|
Regs.RegY = -1;
|
||||||
case OP65_TAY:
|
|
||||||
case OP65_TYA:
|
|
||||||
/* If the branch is a beq, both A and Y are zero at the
|
|
||||||
* branch target, otherwise they are zero at the next
|
|
||||||
* insn.
|
|
||||||
*/
|
|
||||||
if (BC == BC_EQ) {
|
|
||||||
E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
|
|
||||||
} else {
|
|
||||||
E->RI->Out.RegA = E->RI->Out.RegY = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
|
||||||
|
Regs.SRegLo = -1;
|
||||||
default:
|
}
|
||||||
break;
|
if (J->RI->Out2.SRegHi != Regs.SRegHi) {
|
||||||
|
Regs.SRegHi = -1;
|
||||||
|
}
|
||||||
|
++Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use this register info */
|
||||||
|
CurrentRegs = &Regs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate register info for this instruction */
|
||||||
|
CE_GenRegInfo (E, CurrentRegs);
|
||||||
|
|
||||||
|
/* Remember for the next insn if this insn was an uncondition branch */
|
||||||
|
WasJump = (E->Info & OF_UBRA) != 0;
|
||||||
|
|
||||||
|
/* Output registers for this insn are input for the next */
|
||||||
|
CurrentRegs = &E->RI->Out;
|
||||||
|
|
||||||
|
/* If this insn is a branch on zero flag, we may have more info on
|
||||||
|
* register contents for one of both flow directions, but only if
|
||||||
|
* there is a previous instruction.
|
||||||
|
*/
|
||||||
|
if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
|
||||||
|
|
||||||
|
/* Get the branch condition */
|
||||||
|
bc_t BC = GetBranchCond (E->OPC);
|
||||||
|
|
||||||
|
/* Check the previous instruction */
|
||||||
|
switch (P->OPC) {
|
||||||
|
|
||||||
|
case OP65_ADC:
|
||||||
|
case OP65_AND:
|
||||||
|
case OP65_DEA:
|
||||||
|
case OP65_EOR:
|
||||||
|
case OP65_INA:
|
||||||
|
case OP65_LDA:
|
||||||
|
case OP65_ORA:
|
||||||
|
case OP65_PLA:
|
||||||
|
case OP65_SBC:
|
||||||
|
/* A is zero in one execution flow direction */
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegA = 0;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegA = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_CMP:
|
||||||
|
/* If this is an immidiate compare, the A register has
|
||||||
|
* the value of the compare later.
|
||||||
|
*/
|
||||||
|
if (CE_KnownImm (P)) {
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegA = (unsigned char)P->Num;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegA = (unsigned char)P->Num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_CPX:
|
||||||
|
/* If this is an immidiate compare, the X register has
|
||||||
|
* the value of the compare later.
|
||||||
|
*/
|
||||||
|
if (CE_KnownImm (P)) {
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegX = (unsigned char)P->Num;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegX = (unsigned char)P->Num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_CPY:
|
||||||
|
/* If this is an immidiate compare, the Y register has
|
||||||
|
* the value of the compare later.
|
||||||
|
*/
|
||||||
|
if (CE_KnownImm (P)) {
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegY = (unsigned char)P->Num;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegY = (unsigned char)P->Num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_DEX:
|
||||||
|
case OP65_INX:
|
||||||
|
case OP65_LDX:
|
||||||
|
case OP65_PLX:
|
||||||
|
/* X is zero in one execution flow direction */
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegX = 0;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegX = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_DEY:
|
||||||
|
case OP65_INY:
|
||||||
|
case OP65_LDY:
|
||||||
|
case OP65_PLY:
|
||||||
|
/* X is zero in one execution flow direction */
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegY = 0;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegY = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_TAX:
|
||||||
|
case OP65_TXA:
|
||||||
|
/* If the branch is a beq, both A and X are zero at the
|
||||||
|
* branch target, otherwise they are zero at the next
|
||||||
|
* insn.
|
||||||
|
*/
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegA = E->RI->Out.RegX = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP65_TAY:
|
||||||
|
case OP65_TYA:
|
||||||
|
/* If the branch is a beq, both A and Y are zero at the
|
||||||
|
* branch target, otherwise they are zero at the next
|
||||||
|
* insn.
|
||||||
|
*/
|
||||||
|
if (BC == BC_EQ) {
|
||||||
|
E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
|
||||||
|
} else {
|
||||||
|
E->RI->Out.RegA = E->RI->Out.RegY = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (!Done);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
110
src/cc65/coptc02.c
Normal file
110
src/cc65/coptc02.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* coptc02.h */
|
||||||
|
/* */
|
||||||
|
/* 65C02 specific optimizations */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (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. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "codeent.h"
|
||||||
|
#include "codeinfo.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "coptc02.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Helper functions */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned Opt65C02Ind (CodeSeg* S)
|
||||||
|
/* Try to use the indirect addressing mode where possible */
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
unsigned I;
|
||||||
|
|
||||||
|
/* Generate register info for this step */
|
||||||
|
CS_GenRegInfo (S);
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
I = 0;
|
||||||
|
while (I < CS_GetEntryCount (S)) {
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = CS_GetEntry (S, I);
|
||||||
|
|
||||||
|
/* Check for addressing mode indirect indexed Y where Y is zero.
|
||||||
|
* Note: All opcodes that are available as (zp),y are also available
|
||||||
|
* as (zp), so we can ignore the actual opcode here.
|
||||||
|
*/
|
||||||
|
if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) {
|
||||||
|
|
||||||
|
/* Replace it by indirect addressing mode */
|
||||||
|
CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_IND, E->Arg, 0, E->LI);
|
||||||
|
CS_InsertEntry (S, X, I+1);
|
||||||
|
CS_DelEntry (S, I);
|
||||||
|
|
||||||
|
/* We had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free register info */
|
||||||
|
CS_FreeRegInfo (S);
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
61
src/cc65/coptc02.h
Normal file
61
src/cc65/coptc02.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* coptc02.h */
|
||||||
|
/* */
|
||||||
|
/* 65C02 specific optimizations */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (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 COPTC02_H
|
||||||
|
#define COPTC02_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "codeseg.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned Opt65C02Ind (CodeSeg* S);
|
||||||
|
/* Try to use the indirect addressing mode where possible */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of coptc02.h */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -35,6 +35,7 @@ OBJS = anonname.o \
|
|||||||
codeseg.o \
|
codeseg.o \
|
||||||
compile.o \
|
compile.o \
|
||||||
coptadd.o \
|
coptadd.o \
|
||||||
|
coptc02.o \
|
||||||
coptcmp.o \
|
coptcmp.o \
|
||||||
coptind.o \
|
coptind.o \
|
||||||
coptneg.o \
|
coptneg.o \
|
||||||
|
@@ -80,6 +80,7 @@ OBJS = anonname.obj \
|
|||||||
codeseg.obj \
|
codeseg.obj \
|
||||||
compile.obj \
|
compile.obj \
|
||||||
coptadd.obj \
|
coptadd.obj \
|
||||||
|
coptc02.obj \
|
||||||
coptcmp.obj \
|
coptcmp.obj \
|
||||||
coptind.obj \
|
coptind.obj \
|
||||||
coptneg.obj \
|
coptneg.obj \
|
||||||
@@ -157,6 +158,7 @@ FILE codeopt.obj
|
|||||||
FILE codeseg.obj
|
FILE codeseg.obj
|
||||||
FILE compile.obj
|
FILE compile.obj
|
||||||
FILE coptadd.obj
|
FILE coptadd.obj
|
||||||
|
FILE coptc02.obj
|
||||||
FILE coptcmp.obj
|
FILE coptcmp.obj
|
||||||
FILE coptind.obj
|
FILE coptind.obj
|
||||||
FILE coptneg.obj
|
FILE coptneg.obj
|
||||||
|
Reference in New Issue
Block a user