1
0
mirror of https://github.com/cc65/cc65.git synced 2024-07-03 06:29:36 +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:
uz 2009-09-03 12:13:08 +00:00
parent d85e6f9124
commit e1832b2e57
3 changed files with 181 additions and 12 deletions

View File

@ -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) {

View File

@ -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;
}

View File

@ -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 */