From b6e61f16ecaac3234ac9f70de4bbad01ca2033ea Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Fri, 1 Jun 2018 09:51:59 +0200 Subject: [PATCH] Optimizations of adding one --- .../opt/AlwaysGoodOptimizations.scala | 37 +++++++++++++++++++ .../test/AssemblyOptimizationSuite.scala | 34 +++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala index 05331e23..c3f4ca63 100644 --- a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala @@ -1388,8 +1388,32 @@ object AlwaysGoodOptimizations { (Elidable & HasOpcode(ADC) & MatchAddrMode(0) & MatchParameter(1) & HasClear(State.D) & DoesntMatterWhatItDoesWith(State.V)) ~~> { code => List(code.head, AssemblyLine.implied(ROL)) }, + (Elidable & HasOpcode(ADC) & HasImmediate(0) & HasClear(State.C) & DoesntMatterWhatItDoesWith(State.V, State.C, State.N, State.Z)) ~~> (_ => Nil), (Elidable & HasOpcode(ROL) & HasClear(State.C)) ~~> (code => code.map(_.copy(opcode = ASL))), (Elidable & HasOpcode(ROR) & HasClear(State.C)) ~~> (code => code.map(_.copy(opcode = LSR))), + (HasOpcode(AND) & HasImmediate(1)) ~ + (Linear & Not(ChangesNAndZ) & Not(HasOpcode(CLC)) & Not(ChangesA)).* ~ + (Elidable & HasOpcode(CLC) & HasClear(State.D)) ~ + (Elidable & HasOpcode(ADC) & MatchAddrMode(0) & MatchParameter(1) & HasAddrModeIn(Set(ZeroPage, ZeroPageX, Absolute, AbsoluteX))) ~ + (Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.V, State.Z, State.N, State.A)) ~~> { code => + val label = getNextLabel("in") + code.take(code.length - 3) ++ List( + AssemblyLine.relative(BEQ, label), + code.last.copy(opcode = INC), + AssemblyLine.label(label) + ) + }, + (HasOpcode(ANC) & HasImmediate(1)) ~ + (Linear & Not(ChangesNAndZ) & Not(ChangesA) & (Not(ChangesC) | HasOpcode(CLC))).* ~ + (Elidable & HasOpcode(ADC) & MatchAddrMode(0) & MatchParameter(1) & HasClear(State.D) & HasAddrModeIn(Set(ZeroPage, ZeroPageX, Absolute, AbsoluteX))) ~ + (Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.V, State.Z, State.N, State.A)) ~~> { code => + val label = getNextLabel("in") + code.head.copy(opcode = AND) :: code.take(code.length - 2).tail ++ List( + AssemblyLine.relative(BEQ, label), + code.last.copy(opcode = INC), + AssemblyLine.label(label) + ) + }, ) val IndexSequenceOptimization = new RuleBasedAssemblyOptimization("Index sequence optimization", @@ -1542,6 +1566,19 @@ object AlwaysGoodOptimizations { (Elidable & HasOpcode(ROR) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C) & MatchAddrMode(0) & MatchParameter(1)) ~~> { code => code.init.last :: code.last :: code.drop(2).init.init }, + (Elidable & HasOpcode(ASL) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Elidable & HasOpcode(INC) & MatchAddrMode(0) & MatchParameter(1)) ~~> { code => + List(AssemblyLine.implied(SEC), code.head.copy(opcode = ROL)) + }, + (Elidable & HasOpcode(ASL) & HasAddrMode(AddrMode.Implied)) ~ + (Elidable & HasOpcode(CLC)) ~ + (Elidable & HasOpcode(ADC) & HasImmediate(1) & DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { code => + List(AssemblyLine.implied(SEC), code.head.copy(opcode = ROL)) + }, + (Elidable & HasOpcode(ASL) & HasAddrMode(AddrMode.Implied)) ~ + (Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediate(1)) ~~> { code => + List(AssemblyLine.implied(SEC), code.head.copy(opcode = ROL)) + }, ) private def blockIsIdempotentWhenItComesToIndexRegisters(i: Int) = Where(ctx => { diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index 9aac53fb..1df9c4c6 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -506,4 +506,38 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { m.readByte(0xc000) should equal(0x46) } } + + test("Shift and increase") { + EmuBenchmarkRun( + """ + | byte output @$c000 + | void main() { + | output = twicePlusOne(5) + | } + | noinline byte twicePlusOne (byte x) { + | return x * 2 + 1 + | } + """.stripMargin + ){m => + m.readByte(0xc000) should equal(11) + } + } + + test("Add one bit") { + EmuBenchmarkRun( + """ + | byte output @$c000 + | void main() { + | output = 0 + | increaseByBit(5) + | } + | noinline void increaseByBit (byte y) { + | output += y & 1 + | } + """.stripMargin + ){m => + m.readByte(0xc000) should equal(1) + } + } + }