diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala index f0c95a6c..8898904b 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala @@ -1007,6 +1007,21 @@ object AlwaysGoodI80Optimizations { ctx.get[List[ZLine]](4) ++ ctx.get[List[ZLine]](7).map(x => x.copy(registers = x.registers.asInstanceOf[TwoRegisters].copy(source = DE))) }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(MEM_ABS_16, HL)) & MatchParameter(0)).captureLine(10) ~ + (Linear & DoesntChangeMemoryAt(10) & Not(Concerns(HL))).*.capture(55) ~ + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(HL, IMM_16)) & MatchParameter(0)) ~ + (Elidable & HasOpcodeIn(Set(ADD,ADC,INC,DEC,SUB,SBC,AND,OR,XOR)) & HasRegisters(OneRegister(MEM_HL)) & DoesntMatterWhatItDoesWith(HL)).capture(11) ~~> { (code, ctx) => + ctx.get[List[ZLine]](55) ++ ctx.get[List[ZLine]](11).map(_.copy(registers = OneRegister(L))) :+ code.head + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(MEM_ABS_16, HL)) & MatchParameter(0)).captureLine(10) ~ + (Linear & DoesntChangeMemoryAt(10) & Not(Concerns(HL))).*.capture(55) ~ + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(HL, IMM_16)) & MatchParameter(1)) ~ + Where(ctx => ctx.get[Constant](0).+(1).quickSimplify == ctx.get[Constant](1)) ~ + (Elidable & HasOpcodeIn(Set(ADD,ADC,INC,DEC,SUB,SBC,AND,OR,XOR)) & HasRegisters(OneRegister(MEM_HL)) & DoesntMatterWhatItDoesWith(HL)).capture(11) ~~> { (code, ctx) => + ctx.get[List[ZLine]](55) ++ ctx.get[List[ZLine]](11).map(_.copy(registers = OneRegister(H))) :+ code.head + }, ) val UnusedCodeRemoval = new RuleBasedAssemblyOptimization("Unreachable code removal", diff --git a/src/test/scala/millfork/test/StructSuite.scala b/src/test/scala/millfork/test/StructSuite.scala index 89b0eabc..a48dbad7 100644 --- a/src/test/scala/millfork/test/StructSuite.scala +++ b/src/test/scala/millfork/test/StructSuite.scala @@ -1,7 +1,7 @@ package millfork.test import millfork.Cpu -import millfork.test.emu.EmuUnoptimizedCrossPlatformRun +import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun} import org.scalatest.{FunSuite, Matchers} /** @@ -83,4 +83,28 @@ class StructSuite extends FunSuite with Matchers { m.readWord(0xc000) should equal(0x201) } } + + test("Optimize struct modifications") { + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(""" + | struct point { byte x, byte y } + | enum direction { none, right } + | direction last_direction @$c400 + | noinline point move_right(point p) { + | last_direction = right + | p.x += 1 + | return p + | } + | byte output @$c000 + | void main () { + | point p + | p.x = 1 + | p.y = 2 + | p = move_right(p) + | output = p.x + | } + """.stripMargin) { m => + m.readByte(0xc000) should equal(2) + m.readByte(0xc400) should equal(1) + } + } }