mirror of
https://github.com/cc65/cc65.git
synced 2025-04-22 18:37:05 +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 DOptDecouple = { OptDecouple, "OptDecouple", 100, 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 DOptJumpTarget1 = { OptJumpTarget1, "OptJumpTarget1", 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,
|
||||
&DOptDecouple,
|
||||
&DOptDupLoads,
|
||||
&DOptIndLoads1,
|
||||
&DOptIndLoads2,
|
||||
&DOptJumpCascades,
|
||||
&DOptJumpTarget1,
|
||||
&DOptJumpTarget2,
|
||||
@ -1644,6 +1648,32 @@ static unsigned RunOptGroup5 (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.
|
||||
*/
|
||||
{
|
||||
@ -1726,6 +1756,7 @@ void RunOpt (CodeSeg* S)
|
||||
RunOptGroup4 (S);
|
||||
RunOptGroup5 (S);
|
||||
RunOptGroup6 (S);
|
||||
RunOptGroup7 (S);
|
||||
|
||||
/* Write statistics */
|
||||
if (StatFileName) {
|
||||
|
@ -883,17 +883,17 @@ unsigned OptUnusedLoads (CodeSeg* S)
|
||||
/* Check which sort of load or transfer it is */
|
||||
unsigned R;
|
||||
switch (E->OPC) {
|
||||
case OP65_DEA:
|
||||
case OP65_INA:
|
||||
case OP65_LDA:
|
||||
case OP65_DEA:
|
||||
case OP65_INA:
|
||||
case OP65_LDA:
|
||||
case OP65_TXA:
|
||||
case OP65_TYA: R = REG_A; break;
|
||||
case OP65_DEX:
|
||||
case OP65_INX:
|
||||
case OP65_LDX:
|
||||
case OP65_DEX:
|
||||
case OP65_INX:
|
||||
case OP65_LDX:
|
||||
case OP65_TAX: R = REG_X; break;
|
||||
case OP65_DEY:
|
||||
case OP65_INY:
|
||||
case OP65_DEY:
|
||||
case OP65_INY:
|
||||
case OP65_LDY:
|
||||
case OP65_TAY: R = REG_Y; break;
|
||||
default: goto NextEntry; /* OOPS */
|
||||
@ -903,11 +903,11 @@ unsigned OptUnusedLoads (CodeSeg* S)
|
||||
if ((GetRegInfo (S, I+1, R) & R) == 0) {
|
||||
|
||||
/* 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. */
|
||||
++Changes;
|
||||
--I;
|
||||
/* Remember, we had changes. Account the deleted entry in I. */
|
||||
++Changes;
|
||||
--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);
|
||||
/* 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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user