From e1832b2e5745c659b517394ae7b5b76a73bc234a Mon Sep 17 00:00:00 2001 From: uz Date: Thu, 3 Sep 2009 12:13:08 +0000 Subject: [PATCH] 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 --- src/cc65/codeopt.c | 31 ++++++++++ src/cc65/coptind.c | 138 +++++++++++++++++++++++++++++++++++++++++---- src/cc65/coptind.h | 24 ++++++++ 3 files changed, 181 insertions(+), 12 deletions(-) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 422496792..dfb5ab115 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -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) { diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index b80610b56..63351677a 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -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; +} + + + diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index eb22301e1..98d205489 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -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 */