diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 07764cd40..3c10183e4 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -178,6 +178,7 @@ static OptFunc DOptShift3 = { OptShift3, "OptShift3", 17, 0, static OptFunc DOptShift4 = { OptShift4, "OptShift4", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptShift5 = { OptShift5, "OptShift5", 110, 0, 0, 0, 0, 0 }; static OptFunc DOptShift6 = { OptShift6, "OptShift6", 200, 0, 0, 0, 0, 0 }; +static OptFunc DOptShiftBack = { OptShiftBack, "OptShiftBack", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptSignExtended = { OptSignExtended, "OptSignExtended", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSize2 = { OptSize2, "OptSize2", 100, 0, 0, 0, 0, 0 }; @@ -281,6 +282,7 @@ static OptFunc* OptFuncs[] = { &DOptShift4, &DOptShift5, &DOptShift6, + &DOptShiftBack, &DOptSignExtended, &DOptSize1, &DOptSize2, @@ -715,6 +717,7 @@ static unsigned RunOptGroup3 (CodeSeg* S) C += RunOptFunc (S, &DOptPushPop1, 1); C += RunOptFunc (S, &DOptPushPop2, 1); C += RunOptFunc (S, &DOptPrecalc, 1); + C += RunOptFunc (S, &DOptShiftBack, 1); C += RunOptFunc (S, &DOptSignExtended, 1); Changes += C; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 5fe3b5c03..f3e17fc87 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -1477,6 +1477,60 @@ unsigned OptPrecalc (CodeSeg* S) +unsigned OptShiftBack (CodeSeg* S) +/* Remove a pair of shifts to the opposite directions if none of the bits of +** the register A or the Z/N flags modified by these shifts are used later. +*/ +{ + unsigned Changes = 0; + CodeEntry* E; + CodeEntry* N; + unsigned CheckStates; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + E = CS_GetEntry (S, I); + + /* Check if it's a register load or transfer insn */ + if (E->OPC == OP65_ROL && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->OPC == OP65_LSR || + N->OPC == OP65_ROR) && + !CE_HasLabel (N)) { + + CheckStates = PSTATE_ZN; + + if (N->OPC == OP65_LSR && + !PStatesAreClear (E->RI->Out.PFlags, PSTATE_C)) { + CheckStates |= REG_A; + } + + if ((GetRegInfo (S, I+2, CheckStates) & CheckStates) == 0) { + + /* Remove the shifts */ + CS_DelEntries (S, I, 2); + + /* Remember, we had changes */ + ++Changes; + + /* Continue with next insn */ + continue; + } + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + unsigned OptSignExtended (CodeSeg* S) /* Change ** diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index 496b23447..c7ecf4194 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -93,6 +93,11 @@ unsigned OptPrecalc (CodeSeg* S); ** known by a load of the final value. */ +unsigned OptShiftBack (CodeSeg* S); +/* Remove a pair of shifts to the opposite directions if none of the bits of +** the register A or the Z/N flags modified by these shifts are used later. +*/ + unsigned OptSignExtended (CodeSeg* S); /* Change **