From 6cf746045f1163494582b70d702dfbab39b039c5 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Wed, 26 Jun 2019 01:47:03 +0200 Subject: [PATCH] 8080/Z80: More optimizations --- .../z80/opt/AlwaysGoodI80Optimizations.scala | 32 +++++++++++++++++++ .../z80/opt/AlwaysGoodZ80Optimizations.scala | 24 ++++++++++++++ .../opt/RuleBasedAssemblyOptimization.scala | 21 ++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala index 5301b72e..309d0926 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala @@ -442,6 +442,13 @@ object AlwaysGoodI80Optimizations { shallowerStack(code.tail.init) } }), + //32 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.AF)) ~ + (Linear & Not(Changes(ZRegister.A)) & Not(ReadsStackPointer)).*.capture(2) ~ + Where(ctx => ctx.isStackPreservingBlock(2)) ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.AF) & DoesntMatterWhatItDoesWithFlags) ~~> {code => + code.tail.init + }, ) private def shallowerStack(lines: List[ZLine]): List[ZLine] = lines match { @@ -463,6 +470,13 @@ object AlwaysGoodI80Optimizations { code.tail.init :+ ZLine.ldImm16(register, i) } }), + // 5 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.AF) & MatchRegister(ZRegister.A, 1)) ~ + ((Linear | HasOpcode(CALL)) & Not(HasOpcode(POP) & HasRegisterParam(ZRegister.AF)) & Not(ReadsStackPointer)).*.capture(2) ~ + Where(ctx => ctx.isStackPreservingBlock(2)) ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.AF) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + code.tail.init :+ ZLine.ldImm8(ZRegister.A, ctx.get[Int](1)).pos(code.last.source) + }, ) val PointlessStackUnstashing = new RuleBasedAssemblyOptimization("Pointless stack unstashing", @@ -821,6 +835,15 @@ object AlwaysGoodI80Optimizations { code(2).copy(registers = OneRegister(ZRegister.BC)) )), + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L)) ~ + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + code(2).copy(registers = OneRegister(ZRegister.BC)) + )), + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ @@ -830,6 +853,15 @@ object AlwaysGoodI80Optimizations { code(2).copy(registers = OneRegister(ZRegister.DE)) )), + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ + (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + code(2).copy(registers = OneRegister(ZRegister.DE)) + )), + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala index 7773a003..0df8c5f9 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala @@ -140,24 +140,48 @@ object AlwaysGoodZ80Optimizations { List(ZLine.ld8(ZRegister.MEM_BC, ZRegister.A)) }, + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.ld8(ZRegister.MEM_BC, ZRegister.A)) + }, + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ (Elidable & Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => List(ZLine.ld8(ZRegister.MEM_DE, ZRegister.A)) }, + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ + (Elidable & Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.ld8(ZRegister.MEM_DE, ZRegister.A)) + }, + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => List(ZLine.ld8(ZRegister.A, ZRegister.MEM_BC)) }, + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.ld8(ZRegister.A, ZRegister.MEM_BC)) + }, + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => List(ZLine.ld8(ZRegister.A, ZRegister.MEM_DE)) }, + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.ld8(ZRegister.A, ZRegister.MEM_DE)) + }, + ) val All: List[AssemblyOptimization[ZLine]] = List[AssemblyOptimization[ZLine]]( diff --git a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala index fa4cae3f..65efe80a 100644 --- a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala @@ -181,6 +181,23 @@ class AssemblyMatchingContext(val compilationOptions: CompilationOptions) { jumps.isEmpty } + def isStackPreservingBlock(i: Int): Boolean = { + import millfork.assembly.z80.ZOpcode._ + var pushCount = 0 + get[List[ZLine]](i).foreach { + case ZLine0(RET | RST | RETI | RETN, _, _) => + return false + case ZLine0(PUSH, _, _) => + pushCount += 1 + case ZLine0(POP, _, _) => + pushCount -= 1 + if (pushCount < 0) return false + case l => + if (ReadsStackPointer(l)) return false + } + pushCount == 0 + } + def isAlignableBlock(i: Int): Boolean = { if (!isExternallyLinearBlock(i)) return false import ZOpcode._ @@ -911,6 +928,10 @@ case object ReadsStackPointer extends TrivialAssemblyLinePattern { case _ => false } case LD_HLSP | LD_DESP | PUSH | POP => true + case CALL => line.parameter match { + case MemoryAddressConstant(th: NormalFunction) => false + case _ => true + } case _ => false } }