mirror of
https://github.com/cc65/cc65.git
synced 2024-07-05 21:29:03 +00:00
Replace "lda (zp),y" by "lda (zp,x)" where possible and where it saves us
cycles and code bytes. git-svn-id: svn://svn.cc65.org/cc65/trunk@4113 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
d85e6f9124
commit
e1832b2e57
@ -1105,6 +1105,8 @@ static OptFunc DOptDeadCode = { OptDeadCode, "OptDeadCode", 100, 0,
|
|||||||
static OptFunc DOptDeadJumps = { OptDeadJumps, "OptDeadJumps", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptDeadJumps = { OptDeadJumps, "OptDeadJumps", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptDecouple = { OptDecouple, "OptDecouple", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptDecouple = { OptDecouple, "OptDecouple", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptDupLoads = { OptDupLoads, "OptDupLoads", 0, 0, 0, 0, 0, 0 };
|
static OptFunc DOptDupLoads = { OptDupLoads, "OptDupLoads", 0, 0, 0, 0, 0, 0 };
|
||||||
|
static OptFunc DOptIndLoads1 = { OptIndLoads1, "OptIndLoads1", 0, 0, 0, 0, 0, 0 };
|
||||||
|
static OptFunc DOptIndLoads2 = { OptIndLoads2, "OptIndLoads2", 0, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptJumpTarget1 = { OptJumpTarget1, "OptJumpTarget1", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptJumpTarget1 = { OptJumpTarget1, "OptJumpTarget1", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptJumpTarget2 = { OptJumpTarget2, "OptJumpTarget2", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptJumpTarget2 = { OptJumpTarget2, "OptJumpTarget2", 100, 0, 0, 0, 0, 0 };
|
||||||
@ -1191,6 +1193,8 @@ static OptFunc* OptFuncs[] = {
|
|||||||
&DOptDeadJumps,
|
&DOptDeadJumps,
|
||||||
&DOptDecouple,
|
&DOptDecouple,
|
||||||
&DOptDupLoads,
|
&DOptDupLoads,
|
||||||
|
&DOptIndLoads1,
|
||||||
|
&DOptIndLoads2,
|
||||||
&DOptJumpCascades,
|
&DOptJumpCascades,
|
||||||
&DOptJumpTarget1,
|
&DOptJumpTarget1,
|
||||||
&DOptJumpTarget2,
|
&DOptJumpTarget2,
|
||||||
@ -1644,6 +1648,32 @@ static unsigned RunOptGroup5 (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
static unsigned RunOptGroup6 (CodeSeg* S)
|
static unsigned RunOptGroup6 (CodeSeg* S)
|
||||||
|
/* This one is quite special. It tries to replace "lda (sp),y" by "lda (sp,x)".
|
||||||
|
* The latter is ony cycle slower, but if we're able to remove the necessary
|
||||||
|
* load of the Y register, because X is zero anyway, we gain 1 cycle and
|
||||||
|
* shorten the code by one (transfer) or two bytes (load). So what we do is
|
||||||
|
* to replace the insns, remove unused loads, and then change back all insns
|
||||||
|
* where Y is still zero (meaning that the load has not been removed).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* This group will only run for a standard 6502, because the 65C02 has a
|
||||||
|
* better addressing mode that covers this case.
|
||||||
|
*/
|
||||||
|
if ((CPUIsets[CPU] & CPU_ISET_65SC02) == 0) {
|
||||||
|
Changes += RunOptFunc (S, &DOptIndLoads1, 1);
|
||||||
|
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||||
|
Changes += RunOptFunc (S, &DOptIndLoads2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned RunOptGroup7 (CodeSeg* S)
|
||||||
/* The last group of optimization steps. Adjust branches, do size optimizations.
|
/* The last group of optimization steps. Adjust branches, do size optimizations.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@ -1726,6 +1756,7 @@ void RunOpt (CodeSeg* S)
|
|||||||
RunOptGroup4 (S);
|
RunOptGroup4 (S);
|
||||||
RunOptGroup5 (S);
|
RunOptGroup5 (S);
|
||||||
RunOptGroup6 (S);
|
RunOptGroup6 (S);
|
||||||
|
RunOptGroup7 (S);
|
||||||
|
|
||||||
/* Write statistics */
|
/* Write statistics */
|
||||||
if (StatFileName) {
|
if (StatFileName) {
|
||||||
|
@ -883,17 +883,17 @@ unsigned OptUnusedLoads (CodeSeg* S)
|
|||||||
/* Check which sort of load or transfer it is */
|
/* Check which sort of load or transfer it is */
|
||||||
unsigned R;
|
unsigned R;
|
||||||
switch (E->OPC) {
|
switch (E->OPC) {
|
||||||
case OP65_DEA:
|
case OP65_DEA:
|
||||||
case OP65_INA:
|
case OP65_INA:
|
||||||
case OP65_LDA:
|
case OP65_LDA:
|
||||||
case OP65_TXA:
|
case OP65_TXA:
|
||||||
case OP65_TYA: R = REG_A; break;
|
case OP65_TYA: R = REG_A; break;
|
||||||
case OP65_DEX:
|
case OP65_DEX:
|
||||||
case OP65_INX:
|
case OP65_INX:
|
||||||
case OP65_LDX:
|
case OP65_LDX:
|
||||||
case OP65_TAX: R = REG_X; break;
|
case OP65_TAX: R = REG_X; break;
|
||||||
case OP65_DEY:
|
case OP65_DEY:
|
||||||
case OP65_INY:
|
case OP65_INY:
|
||||||
case OP65_LDY:
|
case OP65_LDY:
|
||||||
case OP65_TAY: R = REG_Y; break;
|
case OP65_TAY: R = REG_Y; break;
|
||||||
default: goto NextEntry; /* OOPS */
|
default: goto NextEntry; /* OOPS */
|
||||||
@ -903,11 +903,11 @@ unsigned OptUnusedLoads (CodeSeg* S)
|
|||||||
if ((GetRegInfo (S, I+1, R) & R) == 0) {
|
if ((GetRegInfo (S, I+1, R) & R) == 0) {
|
||||||
|
|
||||||
/* Register value is not used, remove the load */
|
/* Register value is not used, remove the load */
|
||||||
CS_DelEntry (S, I);
|
CS_DelEntry (S, I);
|
||||||
|
|
||||||
/* Remember, we had changes. Account the deleted entry in I. */
|
/* Remember, we had changes. Account the deleted entry in I. */
|
||||||
++Changes;
|
++Changes;
|
||||||
--I;
|
--I;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2036,3 +2036,117 @@ unsigned OptBranchDist (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Optimize indirect loads */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptIndLoads1 (CodeSeg* S)
|
||||||
|
/* Change
|
||||||
|
*
|
||||||
|
* lda (zp),y
|
||||||
|
*
|
||||||
|
* into
|
||||||
|
*
|
||||||
|
* lda (zp,x)
|
||||||
|
*
|
||||||
|
* provided that x and y are both zero.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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 if it's what we're looking for */
|
||||||
|
if (E->OPC == OP65_LDA &&
|
||||||
|
E->AM == AM65_ZP_INDY &&
|
||||||
|
E->RI->In.RegY == 0 &&
|
||||||
|
E->RI->In.RegX == 0) {
|
||||||
|
|
||||||
|
/* Replace by the same insn with other addressing mode */
|
||||||
|
CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZPX_IND, E->Arg, 0, E->LI);
|
||||||
|
CS_InsertEntry (S, X, I+1);
|
||||||
|
|
||||||
|
/* Remove the old insn */
|
||||||
|
CS_DelEntry (S, I);
|
||||||
|
++Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free register info */
|
||||||
|
CS_FreeRegInfo (S);
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptIndLoads2 (CodeSeg* S)
|
||||||
|
/* Change
|
||||||
|
*
|
||||||
|
* lda (zp,x)
|
||||||
|
*
|
||||||
|
* into
|
||||||
|
*
|
||||||
|
* lda (zp),y
|
||||||
|
*
|
||||||
|
* provided that x and y are both zero.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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 if it's what we're looking for */
|
||||||
|
if (E->OPC == OP65_LDA &&
|
||||||
|
E->AM == AM65_ZPX_IND &&
|
||||||
|
E->RI->In.RegY == 0 &&
|
||||||
|
E->RI->In.RegX == 0) {
|
||||||
|
|
||||||
|
/* Replace by the same insn with other addressing mode */
|
||||||
|
CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_INDY, E->Arg, 0, E->LI);
|
||||||
|
CS_InsertEntry (S, X, I+1);
|
||||||
|
|
||||||
|
/* Remove the old insn */
|
||||||
|
CS_DelEntry (S, I);
|
||||||
|
++Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free register info */
|
||||||
|
CS_FreeRegInfo (S);
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,6 +141,30 @@ unsigned OptPrecalc (CodeSeg* S);
|
|||||||
unsigned OptBranchDist (CodeSeg* S);
|
unsigned OptBranchDist (CodeSeg* S);
|
||||||
/* Change branches for the distance needed. */
|
/* Change branches for the distance needed. */
|
||||||
|
|
||||||
|
unsigned OptIndLoads1 (CodeSeg* S);
|
||||||
|
/* Change
|
||||||
|
*
|
||||||
|
* lda (zp),y
|
||||||
|
*
|
||||||
|
* into
|
||||||
|
*
|
||||||
|
* lda (zp,x)
|
||||||
|
*
|
||||||
|
* provided that x and y are both zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned OptIndLoads2 (CodeSeg* S);
|
||||||
|
/* Change
|
||||||
|
*
|
||||||
|
* lda (zp,x)
|
||||||
|
*
|
||||||
|
* into
|
||||||
|
*
|
||||||
|
* lda (zp),y
|
||||||
|
*
|
||||||
|
* provided that x and y are both zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of coptind.h */
|
/* End of coptind.h */
|
||||||
|
Loading…
Reference in New Issue
Block a user