diff --git a/src/main/scala/millfork/OptimizationPresets.scala b/src/main/scala/millfork/OptimizationPresets.scala index ff3a2bb8..f25739b0 100644 --- a/src/main/scala/millfork/OptimizationPresets.scala +++ b/src/main/scala/millfork/OptimizationPresets.scala @@ -154,6 +154,7 @@ object OptimizationPresets { AlwaysGoodOptimizations.PointlessMathFromFlow, AlwaysGoodOptimizations.PointlessMathFromFlow, AlwaysGoodOptimizations.PointlessMathFromFlow, + LaterOptimizations.CommutativeInPlaceModifications, AlwaysGoodOptimizations.LoadingOfJustWrittenValue, AlwaysGoodOptimizations.PointlessStackStore, AlwaysGoodOptimizations.OptimizeZeroComparisons, diff --git a/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala index badad500..0dd6150e 100644 --- a/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/LaterOptimizations.scala @@ -544,7 +544,23 @@ object LaterOptimizations { ) + val CommutativeInPlaceModifications = new RuleBasedAssemblyOptimization("Commutative in-place modifications", + needsFlowInfo = FlowInfoRequirement.NoRequirement, + + (Elidable & HasOpcode(LDY) & HasAddrModeIn(Immediate, Absolute, ZeroPage, LongAbsolute, AbsoluteX, ZeroPageX) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Elidable & HasOpcode(LDA) & HasAddrModeIn(AbsoluteY, IndexedY, LongIndexedY)) ~ + (Elidable & HasOpcode(LDY) & HasAddrModeIn(Immediate, Absolute, ZeroPage, LongAbsolute, AbsoluteX, ZeroPageX)) ~ + (Elidable & HasOpcodeIn(ORA, EOR, AND) & HasAddrModeIn(AbsoluteY, IndexedY, LongIndexedY)) ~ + (Elidable & HasOpcode(LDY) & HasAddrModeIn(Immediate, Absolute, ZeroPage, LongAbsolute, AbsoluteX, ZeroPageX) & MatchAddrMode(0) & MatchParameter(1)) ~ + (HasOpcodeIn(INY, DEY)).* ~ + (HasOpcode(STA) & HasAddrModeIn(AbsoluteY, IndexedY, LongIndexedY)) ~~> { code => + List(code(2), code(3).copy(opcode = LDA), code(5), code(1).copy(opcode = code(3).opcode)) ++ code.drop(5) + }, + + ) + val All = List( + CommutativeInPlaceModifications, DontUseIndexRegisters, DoubleLoadToDifferentRegisters, DoubleLoadToTheSameRegister, diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index cf96707c..c0a2b8e4 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -845,4 +845,30 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { } EmuUndocumentedRun(code) } + + test("Optimize commutative in-place modifications using small arrays") { + + val code = + """ + | + |array output [4] @$c000 + | + |void main() { + | f($c000, 1, $c000, 2) + | g(1, 2) + |} + | + |noinline void f(pointer p1, byte i1, pointer p2, byte i2) { + | p1[i1] ^= p2[i2] + |} + | + |noinline void g(byte i1, byte i2) { + | output[i1] ^= output[i2] + |} + | + |""".stripMargin + EmuCrossPlatformBenchmarkRun(Cpu.Mos)(code) { m => + + } + } }