From bebb8c45a5921ea9478aa3332ce20194b0cc8166 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Wed, 1 Aug 2018 10:22:34 +0200 Subject: [PATCH] Z80: More optimizations --- .../scala/millfork/assembly/z80/ZLine.scala | 1 + .../z80/opt/AlwaysGoodI80Optimizations.scala | 54 +++++++++++++++++++ .../z80/opt/AlwaysGoodZ80Optimizations.scala | 14 ++++- .../opt/RuleBasedAssemblyOptimization.scala | 12 ++++- 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/main/scala/millfork/assembly/z80/ZLine.scala b/src/main/scala/millfork/assembly/z80/ZLine.scala index cabc9e20..b4abb536 100644 --- a/src/main/scala/millfork/assembly/z80/ZLine.scala +++ b/src/main/scala/millfork/assembly/z80/ZLine.scala @@ -14,6 +14,7 @@ object ZFlag extends Enumeration { val Z, P, C, S, H, N = Value val AllButSZ: Seq[Value] = Seq(P, C, H, N) + val AllButZ: Seq[Value] = Seq(P, C, H, N, S) } sealed trait ZRegisters diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala index 0a3b3a24..95660dd5 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala @@ -5,6 +5,7 @@ import millfork.assembly.z80._ import millfork.assembly.z80.ZOpcode._ import millfork.env.{CompoundConstant, Constant, MathOperator, NumericConstant} import millfork.node.ZRegister +import ZRegister._ /** * Optimizations valid for Intel8080, Z80, EZ80 and Sharp @@ -742,8 +743,61 @@ object AlwaysGoodI80Optimizations { ZLine.implied(RLCA), ZLine.imm8(AND, 7)) }, + (Elidable & HasOpcode(RR) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlagsExceptCarry) ~~> {_ => + List(ZLine.implied(RRA)) + }, + (Elidable & HasOpcode(RRC) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlagsExceptCarry) ~~> {_ => + List(ZLine.implied(RRCA)) + }, + (Elidable & HasOpcode(RL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlagsExceptCarry) ~~> {_ => + List(ZLine.implied(RLA)) + }, + (Elidable & HasOpcode(RLC) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlagsExceptCarry) ~~> {_ => + List(ZLine.implied(RLCA)) + }, ) + val PointlessExdehl = new RuleBasedAssemblyOptimization("Pointless EX DE,HL", + needsFlowInfo = FlowInfoRequirement.NoRequirement, + + (Elidable & HasOpcode(EX_DE_HL)) ~ + (Elidable & ( + HasOpcode(LD_16) & (HasRegisters(TwoRegisters(DE, IMM_16)) | HasRegisters(TwoRegisters(HL, IMM_16)) | HasRegisters(TwoRegisters(BC, IMM_16))) | + Is8BitLoad(A, H) | + Is8BitLoad(A, L) | + Is8BitLoad(A, D) | + Is8BitLoad(A, E) | + Is8BitLoad(H, A) | + Is8BitLoad(L, A) | + Is8BitLoad(D, A) | + Is8BitLoad(E, A) | + HasOpcodeIn(Set(POP, PUSH, INC_16, DEC_16)) | + HasOpcodeIn(Set(INC, DEC, ADD, ADC, SUB, SBC, RLA, RLA, RRCA, RRCA, RL, RR, RRC, RLC, AND, XOR, OR, CP)) + )).* ~ + (Elidable & HasOpcode(EX_DE_HL)) ~~> { code => + code.tail.init.map { line => + line.registers match { + case OneRegister(HL) => line.copy(registers = OneRegister(DE)) + case OneRegister(DE) => line.copy(registers = OneRegister(HL)) + case TwoRegisters(HL, source) => line.copy(registers = TwoRegisters(DE, source)) + case TwoRegisters(DE, source) => line.copy(registers = TwoRegisters(HL, source)) + case TwoRegisters(H, r) => line.copy(registers = TwoRegisters(D, r)) + case TwoRegisters(L, r) => line.copy(registers = TwoRegisters(E, r)) + case TwoRegisters(D, r) => line.copy(registers = TwoRegisters(H, r)) + case TwoRegisters(E, r) => line.copy(registers = TwoRegisters(L, r)) + case TwoRegisters(r, H) => line.copy(registers = TwoRegisters(r, D)) + case TwoRegisters(r, L) => line.copy(registers = TwoRegisters(r, E)) + case TwoRegisters(r, D) => line.copy(registers = TwoRegisters(r, H)) + case TwoRegisters(r, E) => line.copy(registers = TwoRegisters(r, L)) + case _ => line + } + } + }, + + + ) + + val All: List[AssemblyOptimization[ZLine]] = List[AssemblyOptimization[ZLine]]( BranchInPlaceRemoval, FreeHL, diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala index 326aab72..99f634a4 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala @@ -3,8 +3,9 @@ package millfork.assembly.z80.opt import millfork.assembly.AssemblyOptimization import millfork.assembly.z80._ import millfork.assembly.z80.ZOpcode._ -import millfork.env.{CompoundConstant, Constant, MathOperator, NumericConstant} +import millfork.env.Constant import millfork.node.ZRegister +import ZRegister._ /** * Optimizations valid for Z80 and EZ80 @@ -81,6 +82,17 @@ object AlwaysGoodZ80Optimizations { (Elidable & HasOpcode(NEG)) ~ (Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.implied(CPL))), + (Elidable & HasOpcode(OR) & HasRegisters(OneRegister(A)) & HasRegister(BC, 0)) ~ + (Elidable & HasOpcode(SBC_16) & HasRegisters(TwoRegisters(HL, BC)) & DoesntMatterWhatItDoesWithFlagsExceptZero) ~~> { code => + List(ZLine.ld8(A, H), ZLine.register(OR, L)) + }, + + (Elidable & HasOpcode(OR) & HasRegisters(OneRegister(A)) & HasRegister(DE, 0)) ~ + (Elidable & HasOpcode(SBC_16) & HasRegisters(TwoRegisters(HL, DE)) & DoesntMatterWhatItDoesWithFlagsExceptZero) ~~> { code => + List(ZLine.ld8(A, H), ZLine.register(OR, L)) + }, + + ) val FreeHL = new RuleBasedAssemblyOptimization("Free HL (Z80)", diff --git a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala index 9a2957c2..bdef7997 100644 --- a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala @@ -621,11 +621,21 @@ case object DoesntMatterWhatItDoesWithFlagsOtherThanSZ extends AssemblyLinePatte override def toString: String = "[¯\\_(ツ)_/¯:NPVH]" } -case object DoesntMatterWhatItDoesWithFlagsExceptCarry extends AssemblyLinePattern { +case object DoesntMatterWhatItDoesWithFlagsExceptZero extends AssemblyLinePattern { override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = FlowInfoRequirement.assertBackward(needsFlowInfo) + override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean = + ZFlag.AllButZ.forall(r => flowInfo.importanceAfter.getFlag(r) != Important) + + override def toString: String = "[¯\\_(ツ)_/¯:NPVHS]" +} + +case object DoesntMatterWhatItDoesWithFlagsExceptCarry extends AssemblyLinePattern { + override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = + FlowInfoRequirement.assertBackward(needsFlowInfo) + override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean = ZFlag.values.forall(r => r == ZFlag.C || flowInfo.importanceAfter.getFlag(r) != Important)