From 2bac42c187fd0845b18fd6faa8dc8f252400d003 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Mon, 30 Jul 2018 23:51:41 +0200 Subject: [PATCH] Optimizations for LR35902 and 8080 --- .../z80/opt/AlwaysGoodI80Optimizations.scala | 761 ++++++++++++++++++ .../z80/opt/AlwaysGoodZ80Optimizations.scala | 620 +------------- .../z80/opt/LaterI80Optimizations.scala | 31 + .../z80/opt/LaterIntel8080Optimizations.scala | 31 + .../z80/opt/LaterSharpOptimizations.scala | 59 ++ .../opt/RuleBasedAssemblyOptimization.scala | 32 + .../z80/opt/Z80OptimizationPresets.scala | 33 +- .../millfork/test/emu/EmuBenchmarkRun.scala | 50 +- 8 files changed, 971 insertions(+), 646 deletions(-) create mode 100644 src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala create mode 100644 src/main/scala/millfork/assembly/z80/opt/LaterI80Optimizations.scala create mode 100644 src/main/scala/millfork/assembly/z80/opt/LaterIntel8080Optimizations.scala create mode 100644 src/main/scala/millfork/assembly/z80/opt/LaterSharpOptimizations.scala diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala new file mode 100644 index 00000000..0a3b3a24 --- /dev/null +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala @@ -0,0 +1,761 @@ +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.node.ZRegister + +/** + * Optimizations valid for Intel8080, Z80, EZ80 and Sharp + * @author Karol Stasiak + */ +object AlwaysGoodI80Optimizations { + + def change8BitLoadTarget(line: ZLine, newTarget: ZRegister.Value): ZLine = { + line match { + case ZLine(LD, TwoRegistersOffset(_, s, o), p, _) => ZLine(LD, TwoRegistersOffset(newTarget, s, o), p) + case ZLine(LD, TwoRegisters(_, s), p, _) => ZLine(LD, TwoRegisters(newTarget, s), p) + } + } + + def for7Registers(f: ZRegister.Value => AssemblyRuleSet) = MultipleAssemblyRules( + List(ZRegister.A, ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L).map(f)) + + def for5LargeRegisters(f: ZRegister.Value => AssemblyRuleSet) = MultipleAssemblyRules( + List(ZRegister.HL, ZRegister.BC, ZRegister.DE, ZRegister.IX, ZRegister.IY).map(f)) + + def for6Registers(f: ZRegister.Value => AssemblyRuleSet) = MultipleAssemblyRules( + List(ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L).map(f)) + + val UsingKnownValueFromAnotherRegister = new RuleBasedAssemblyOptimization("Using known value from another register", + needsFlowInfo = FlowInfoRequirement.ForwardFlow, + for7Registers(register => + (Elidable & IsRegular8BitLoadFrom(register) & MatchRegister(register, 0)) ~~> ((code, ctx) => + code.map(x => x.copy( + parameter = NumericConstant(ctx.get[Int](0), 1), + registers = x.registers match { + case TwoRegisters(t, _) => TwoRegisters(t, ZRegister.IMM_8) + case TwoRegistersOffset(t@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), _, o) => TwoRegistersOffset(t, ZRegister.IMM_8, o) + case TwoRegistersOffset(t, ZRegister.MEM_IX_D | ZRegister.MEM_IY_D, _) => TwoRegisters(t, ZRegister.IMM_8) + } + ))) + ), + (Elidable & MatchSourceIxOffsetOf8BitLoad(0) & MatchValueAtMatchedIxOffset(0, 1)) ~~> ((code, ctx) => + code.map(x => x.copy( + parameter = NumericConstant(ctx.get[Int](1), 1), + registers = x.registers match { + case TwoRegisters(t, _) => TwoRegisters(t, ZRegister.IMM_8) + case TwoRegistersOffset(t@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), _, o) => TwoRegistersOffset(t, ZRegister.IMM_8, o) + case TwoRegistersOffset(t, ZRegister.MEM_IX_D | ZRegister.MEM_IY_D, _) => TwoRegisters(t, ZRegister.IMM_8) + } + )) + ), + for6Registers(register => + (Elidable & HasRegisterParam(register) & HasOpcodeIn(Set(AND, ADD, ADC, SUB, SBC, XOR, OR, CP)) & MatchRegister(register, 0)) ~~> ((code, ctx) => + code.map(x => x.copy( + parameter = NumericConstant(ctx.get[Int](0), 1), + registers = OneRegister(ZRegister.IMM_8) + ))) + ), + (Elidable & MatchIxOffset(0) & HasOpcodeIn(Set(AND, ADD, ADC, SUB, SBC, XOR, OR, CP)) & MatchValueAtMatchedIxOffset(0, 1)) ~~> ((code, ctx) => + code.map(x => x.copy( + parameter = NumericConstant(ctx.get[Int](1), 1), + registers = OneRegister(ZRegister.IMM_8) + )) + ), + ) + + val ReloadingKnownValueFromMemory = new RuleBasedAssemblyOptimization("Reloading known value from memory", + needsFlowInfo = FlowInfoRequirement.ForwardFlow, + for7Registers(register => + Is8BitLoad(ZRegister.MEM_HL, register) ~ + (Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~ + (Elidable & Is8BitLoad(register, ZRegister.MEM_HL)) ~~> { code => code.init } + ), + for7Registers(register => + Is8BitLoad(ZRegister.MEM_HL, register) ~ + (Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~ + (Elidable & IsRegular8BitLoadFrom(ZRegister.MEM_HL)) ~~> { code => + val last = code.last + code.init :+ last.copy(registers = TwoRegisters(last.registers.asInstanceOf[TwoRegisters].target, register)) + } + ), + (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init }, + + (Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init }, + + (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init }, + + (Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init }, + + (Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.HL))).* ~ + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { code => code.init }, + + (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0) & MatchRegister(ZRegister.A, 2)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8))).* ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { (code, ctx) => + code.init :+ ZLine.ldImm8(ZRegister.A, ctx.get[Int](2)) + }, + + (Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0) & MatchConstantInHL(2)).captureLine(1) ~ + (Linear & DoesntChangeMemoryAt(1) & Not(Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16))).* ~ + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { (code, ctx) => + code.init :+ ZLine.ldImm16(ZRegister.HL, ctx.get[Constant](2)) + }, + ) + + val PointlessLoad = new RuleBasedAssemblyOptimization("Pointless load", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + // 0-6 + for7Registers(register => + (Elidable & Is8BitLoadTo(register) & DoesntMatterWhatItDoesWith(register)) ~~> (_ => Nil) + ), + // 7-11 + for5LargeRegisters(register => + (Elidable & Is16BitLoadTo(register) & DoesntMatterWhatItDoesWith(register)) ~~> (_ => Nil) + ), + // 12-18 + for7Registers(register => + (Is8BitLoad(register, ZRegister.IMM_8) & MatchImmediate(0)) ~ + (Linear & Not(Changes(register))).* ~ + (Elidable & Is8BitLoad(register, ZRegister.IMM_8) & MatchImmediate(0)) ~~> (_.init) + ), + // 19-23 + for5LargeRegisters(register => + (Is16BitLoad(register, ZRegister.IMM_16) & MatchImmediate(0)) ~ + (Linear & Not(Changes(register))).* ~ + (Elidable & Is16BitLoad(register, ZRegister.IMM_16) & MatchImmediate(0)) ~~> (_.init) + ), + // 24 + (Elidable & Is8BitLoadTo(ZRegister.MEM_HL)) ~ + (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.HL))).* ~ + Is8BitLoadTo(ZRegister.MEM_HL) ~~> (_.tail), + // 25 + (Elidable & Is8BitLoadTo(ZRegister.MEM_DE)) ~ + (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.DE))).* ~ + Is8BitLoadTo(ZRegister.MEM_DE) ~~> (_.tail), + // 26 + (Elidable & Is8BitLoadTo(ZRegister.MEM_BC)) ~ + (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.BC))).* ~ + Is8BitLoadTo(ZRegister.MEM_BC) ~~> (_.tail), + // 27 + (Elidable & MatchTargetIxOffsetOf8BitLoad(0) & MatchUnimportantIxOffset(0)) ~~> (_ => Nil), + // 28-34 + for7Registers(register => + (Elidable & Is8BitLoadTo(register) & NoOffset & MatchSourceRegisterAndOffset(1)) ~ + (Linear & Not(Concerns(register)) & DoesntChangeMatchedRegisterAndOffset(1)).* ~ + (Elidable & IsRegular8BitLoadFrom(register) & DoesntMatterWhatItDoesWith(register)) ~~> { code => + val last = code.last + val head = code.head + code.tail.init :+ ZLine(LD, (last.registers, head.registers) match { + case (TwoRegisters(t, _), TwoRegisters(_, s)) => TwoRegisters(t, s) + case (TwoRegistersOffset(t, _, o), TwoRegisters(_, s)) => TwoRegistersOffset(t, s, o) + case (TwoRegisters(t, _), TwoRegistersOffset(_, s, o)) => TwoRegistersOffset(t, s, o) + case _ => ??? + }, head.parameter) + } + ), + // 35-41 + for7Registers(register => + (Elidable & Is8BitLoad(register, register)) ~~> (_ => Nil) + ), + // 42-48 + for6Registers(register => + (Elidable & Is8BitLoadTo(register) & MatchSourceRegisterAndOffset(0) & MatchParameterOrNothing(1)) ~ + (Linear & Not(Concerns(register)) & DoesntChangeMatchedRegisterAndOffset(0)).* ~ + (Elidable & HasOpcodeIn(Set(ADD, ADC, XOR, OR, AND, CP, SUB, SBC)) & + HasRegisters(OneRegister(register)) & DoesntMatterWhatItDoesWith(register)) ~~> { (code, ctx) => + code.tail.init :+ code.last.copy(registers = ctx.get[RegisterAndOffset](0).toOneRegister, parameter = ctx.get[Constant](1)) + } + ), + + // 49-54 + MultipleAssemblyRules { + import ZRegister._ + val regs = Seq((BC, B, C), (DE, D, E), (HL, H, L)) + for { + (t, th, tl) <- regs + (s, sh, sl) <- regs + if t != HL + if t != s + } yield { + // TODO: make it a bit more universal + (Elidable & Is8BitLoad(th, sh)) ~ + (Elidable & Is8BitLoad(tl, sl)) ~ + (HasOpcode(OR) & HasRegisterParam(A)).?.capture(1) ~ + (Elidable & HasOpcodeIn(Set(ADD_16, ADC_16, SBC_16)) & HasRegisters(TwoRegisters(HL, t)) & DoesntMatterWhatItDoesWith(t)) ~~> { + (code, ctx) => + ctx.get[List[ZLine]](1) :+ code.last.copy(registers = TwoRegisters(HL, s)) + } + } + }, + // 55-59 + for5LargeRegisters(register => + (Is16BitLoad(register, ZRegister.MEM_ABS_16) & MatchParameter(0)).captureLine(1) ~ + (Linear & Not(Changes(register)) & DoesntChangeMemoryAt(1)).* ~ + (Elidable & Is16BitLoad(register, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> (_.init) + ), + // 60 + (HasOpcode(LD) & MatchSourceRegisterAndOffset(0) & MatchTargetRegisterAndOffset(1)) ~ + Where(ctx => ctx.get[RegisterAndOffset](0).register != ZRegister.MEM_ABS_8 && ctx.get[RegisterAndOffset](1).register != ZRegister.MEM_ABS_8) ~ + (Elidable & HasOpcode(LD) & MatchSourceRegisterAndOffset(1) & MatchTargetRegisterAndOffset(0)) ~~> (_.init) + ) + + val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + // 0-4 + for5LargeRegisters(register => { + (Elidable & HasOpcode(PUSH) & HasRegisterParam(register)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(register)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(register)) ~~> (_.tail.init) + }), + // 5 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.D)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.D)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> {code => + ZLine.ld8(ZRegister.D, ZRegister.E) :: (code.tail.init :+ ZLine.ld8(ZRegister.E, ZRegister.D)) + }, + // 6 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.E)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.E)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code => + ZLine.ld8(ZRegister.E, ZRegister.D) :: (code.tail.init :+ ZLine.ld8(ZRegister.D, ZRegister.E)) + }, + // 7 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.B)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.B)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> (code => + ZLine.ld8(ZRegister.B, ZRegister.C) :: (code.tail.init :+ ZLine.ld8(ZRegister.C, ZRegister.B)) + ), + // 8 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.C)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.C)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code => + ZLine.ld8(ZRegister.C, ZRegister.B) :: (code.tail.init :+ ZLine.ld8(ZRegister.B, ZRegister.C)) + }, + // 9 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.H)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.H)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => + ZLine.ld8(ZRegister.H, ZRegister.L) :: (code.tail.init :+ ZLine.ld8(ZRegister.L, ZRegister.H)) + }, + // 10 + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.L)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.L)) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => + ZLine.ld8(ZRegister.L, ZRegister.H) :: (code.tail.init :+ ZLine.ld8(ZRegister.H, ZRegister.L)) + }, + // 11-15 + for5LargeRegisters(register => { + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(register, ZRegister.IMM_16))) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(register) & DoesntMatterWhatItDoesWith(register)) ~ + (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(ReadsStackPointer)).* ~ + (Elidable & HasOpcode(POP) & HasRegisterParam(register)) ~~> { code => + code.drop(2).init :+ code.head + } + }), + + ) + + private def simplifiable16BitAddWithSplitTarget(targetH: ZRegister.Value, targetL: ZRegister.Value, target: ZRegister.Value, source: ZRegister.Value) = MultipleAssemblyRules(List( + (Is8BitLoad(targetH, ZRegister.IMM_8) & MatchImmediate(1)) ~ + (Linear & Not(Changes(target))).* ~ + (Is8BitLoad(targetL, ZRegister.IMM_8) & MatchImmediate(2)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Is16BitLoad(source, ZRegister.IMM_16) & MatchImmediate(0)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(target, source)) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + val value = (ctx.get[Constant](0) + ctx.get[Constant](1).asl(8) + ctx.get[Constant](2)).quickSimplify + code.init :+ ZLine.ldImm16(target, value) + }, + (Is8BitLoad(targetL, ZRegister.IMM_8) & MatchImmediate(2)) ~ + (Linear & Not(Changes(target))).* ~ + (Is8BitLoad(targetH, ZRegister.IMM_8) & MatchImmediate(1)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Is16BitLoad(source, ZRegister.IMM_16) & MatchImmediate(0)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(target, source)) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + val value = (ctx.get[Constant](0) + ctx.get[Constant](1).asl(8) + ctx.get[Constant](2)).quickSimplify + code.init :+ ZLine.ldImm16(target, value) + }, + (Is16BitLoad(source, ZRegister.IMM_16) & MatchImmediate(0)) ~ + (Linear & Not(Changes(targetL)) & Not(Changes(source))).* ~ + (Is8BitLoad(targetL, ZRegister.IMM_8) & MatchImmediate(2)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Is8BitLoad(targetH, ZRegister.IMM_8) & MatchImmediate(1)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(target, source)) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + val value = (ctx.get[Constant](0) + ctx.get[Constant](1).asl(8) + ctx.get[Constant](2)).quickSimplify + code.init :+ ZLine.ldImm16(target, value) + }, + (Is16BitLoad(source, ZRegister.IMM_16) & MatchImmediate(0)) ~ + (Linear & Not(Changes(targetH)) & Not(Changes(source))).* ~ + (Is8BitLoad(targetH, ZRegister.IMM_8) & MatchImmediate(1)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Is8BitLoad(targetL, ZRegister.IMM_8) & MatchImmediate(2)) ~ + (Linear & Not(Changes(target)) & Not(Changes(source))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(target, source)) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + val value = (ctx.get[Constant](0) + ctx.get[Constant](1).asl(8) + ctx.get[Constant](2)).quickSimplify + code.init :+ ZLine.ldImm16(target, value) + }, + )) + + val SimplifiableMaths = new RuleBasedAssemblyOptimization("Simplifiable maths", + needsFlowInfo = FlowInfoRequirement.BothFlows, + for6Registers(register => + (Elidable & HasOpcode(ADD) & MatchRegister(ZRegister.A, 0) & HasRegisterParam(register) & MatchRegister(register, 1) & + DoesntMatterWhatItDoesWithFlags) ~~> ((code, ctx) => List(ZLine.ldImm8(ZRegister.A, (ctx.get[Int](0) + ctx.get[Int](1)) & 0xff))), + ), + simplifiable16BitAddWithSplitTarget(ZRegister.H, ZRegister.L, ZRegister.HL, ZRegister.BC), + simplifiable16BitAddWithSplitTarget(ZRegister.H, ZRegister.L, ZRegister.HL, ZRegister.DE), + + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & MatchRegister(ZRegister.BC, 0) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.ldImm16(ZRegister.HL, ctx.get[Int](0) + ctx.get[Int](1))) + }, + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & MatchRegister(ZRegister.DE, 0) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.ldImm16(ZRegister.HL, ctx.get[Int](0) + ctx.get[Int](1))) + }, + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.HL)) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.ldImm16(ZRegister.HL, 2 * ctx.get[Int](1) & 0xffff)) + }, + + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & HasRegister(ZRegister.BC, 0) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + Nil + }, + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & HasRegister(ZRegister.DE, 0) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + Nil + }, + + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & HasRegister(ZRegister.BC, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.register(ZOpcode.INC_16, ZRegister.HL)) + }, + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & HasRegister(ZRegister.DE, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.register(ZOpcode.INC_16, ZRegister.HL)) + }, + + + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & MatchRegister(ZRegister.BC, 0) & MatchConstantInHL(1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.ldImm16(ZRegister.HL, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) + }, + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & MatchRegister(ZRegister.DE, 0) & MatchConstantInHL(1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => + List(ZLine.ldImm16(ZRegister.HL, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) + }, + + + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ + (Elidable & Is8BitLoadTo(ZRegister.L)) ~ + (Elidable & Is8BitLoadTo(ZRegister.H)) ~ + (HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & DoesntMatterWhatItDoesWith(ZRegister.D, ZRegister.E)) ~~> { code => + List( + change8BitLoadTarget(code(2), ZRegister.E), + change8BitLoadTarget(code(3), ZRegister.D), + code.last) + }, + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ + (Elidable & Is8BitLoadTo(ZRegister.H)) ~ + (Elidable & Is8BitLoadTo(ZRegister.L)) ~ + (HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & DoesntMatterWhatItDoesWith(ZRegister.D, ZRegister.E)) ~~> { code => + List( + change8BitLoadTarget(code(2), ZRegister.D), + change8BitLoadTarget(code(3), ZRegister.E), + code.last) + }, + + (Elidable & HasOpcodeIn(Set(ADD, OR, XOR, SUB)) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), + (Elidable & HasOpcode(AND) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), + (Elidable & HasOpcode(AND) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.ldImm8(ZRegister.A, 0))), + (Elidable & HasOpcode(AND) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.ldImm8(ZRegister.A, 0))), + + + (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ + (Elidable & HasOpcodeIn(Set(JP, JR)) & HasRegisters(IfFlagSet(ZFlag.S)) & DoesntMatterWhatItDoesWithFlags) ~ + Where(ctx => ctx.get[Constant](1).isInstanceOf[NumericConstant]) ~~> { (code, ctx) => + val value = (ctx.get[Int](0) | ctx.get[NumericConstant](1).value).toInt & 0xff + if (value.&(0x80) == 0) List(ZLine.ldImm8(ZRegister.A, value)) + else List(ZLine.ldImm8(ZRegister.A, value), code.last.copy(registers = NoRegisters)) + }, + + (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ + (Elidable & HasOpcodeIn(Set(JP, JR)) & HasRegisters(IfFlagClear(ZFlag.S)) & DoesntMatterWhatItDoesWithFlags) ~ + Where(ctx => ctx.get[Constant](1).isInstanceOf[NumericConstant]) ~~> { (code, ctx) => + val value = (ctx.get[Int](0) | ctx.get[NumericConstant](1).value).toInt & 0xff + if (value.&(0x80) != 0) List(ZLine.ldImm8(ZRegister.A, value)) + else List(ZLine.ldImm8(ZRegister.A, value), code.last.copy(registers = NoRegisters)) + }, + + (Elidable & HasOpcode(ADD) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) + }, + + (Elidable & HasOpcode(SUB) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, (NumericConstant(ctx.get[Int](0) & 0xff, 1) - ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.Or, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & HasOpcode(XOR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.Exor, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & HasOpcode(AND) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.And, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & HasOpcode(ADD) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ + (Elidable & HasOpcode(DAA) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.DecimalPlus, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & HasOpcode(SUB) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ + (Elidable & HasOpcode(DAA) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => + List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.DecimalMinus, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) + }, + + (Elidable & (Is8BitLoadTo(ZRegister.A) | HasOpcode(LD) & HasRegisters(TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)))) ~ + (Elidable & HasOpcode(SUB) & Has8BitImmediate(0)) ~ + (Is8BitLoadTo(ZRegister.A) | HasOpcode(LD) & HasRegisters(TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8))) ~ + (Elidable & HasOpcode(SBC)) ~~> { code => + List(code(2), code(3).copy(opcode = SUB)) + }, + + (Elidable & HasOpcode(DEC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ + (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ + (Elidable & HasOpcode(INC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), + + (Elidable & HasOpcode(INC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ + (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ + (Elidable & HasOpcode(DEC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), + + (Elidable & HasOpcode(DEC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ + (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ + (Elidable & HasOpcode(INC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), + + (Elidable & HasOpcode(INC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ + (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ + (Elidable & HasOpcode(DEC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), + + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.C)) ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE))) ~~> { code => + ZLine.registers(code.last.opcode, ZRegister.HL, ZRegister.BC) :: code.take(2) + }, + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.D)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.E)) ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC))) ~~> { code => + ZLine.registers(code.last.opcode, ZRegister.HL, ZRegister.DE) :: code.take(2) + }, + + (Elidable & HasOpcode(INC) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), + + (Elidable & HasOpcode(SUB) & Has8BitImmediate(0)) ~ + (Elidable & Is8BitLoadTo(ZRegister.A)) ~ + (Elidable & HasOpcode(SBC)) ~~> { code => + List(code(1), code.last.copy(opcode = SUB)) + } + + ) + + val FreeHL = new RuleBasedAssemblyOptimization("Free HL", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ + (Elidable & Is8BitLoadTo(ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL, ZRegister.A)) ~~> (code => + List( + code(1).copy(registers = TwoRegisters(ZRegister.A, code(1).registers.asInstanceOf[TwoRegisters].source)), + code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.MEM_ABS_8, ZRegister.A)), + )), + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)), + )), + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ + (Elidable & IsRegular8BitLoadFrom(ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.A)) ~~> (code => + List( + code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)), + code(1).copy(registers = TwoRegisters(code(1).registers.asInstanceOf[TwoRegisters].target, ZRegister.A)), + )), + + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + code.head.copy(registers = TwoRegisters(ZRegister.DE, ZRegister.IMM_16)) + )), + (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + code.head.copy(registers = TwoRegisters(ZRegister.BC, ZRegister.IMM_16)) + )), + + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & 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)) ~ + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & 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)) ~ + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + ZLine.ld8(ZRegister.B, ZRegister.D), + ZLine.ld8(ZRegister.C, ZRegister.E), + code(2).copy(registers = OneRegister(ZRegister.BC)) + )), + + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => + List( + ZLine.ld8(ZRegister.D, ZRegister.B), + ZLine.ld8(ZRegister.E, ZRegister.C), + code(2).copy(registers = OneRegister(ZRegister.DE)) + )), + + + // 2 bytes more, but 3 cycles fewer and frees BC + (Elidable & Is16BitLoad(ZRegister.BC, ZRegister.IMM_16) & MatchParameter(0)) ~ + (Linear & Not(Concerns(ZRegister.BC)) & Not(Concerns(ZRegister.HL))).*.capture(1) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.A)) ~ + (Elidable & Is8BitLoadTo(ZRegister.H) & Has8BitImmediate(0)) ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & + DoesntMatterWhatItDoesWithFlagsExceptCarry & + DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> { (code, ctx) => + val offset = ctx.get[Constant](0) + ctx.get[List[ZLine]](1) ++ List( + ZLine.imm8(ADD, offset.loByte), + ZLine.ld8(ZRegister.L, ZRegister.A), + ZLine.ldImm8(ZRegister.A, 0), + ZLine.imm8(ADC, offset.hiByte), + ZLine.ld8(ZRegister.H, ZRegister.A)) + }, + + + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.DE)) + }, + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.BC)) + }, + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.HL)) + }, + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.HL)) + }, + + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.DE)) + }, + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.BC)) + }, + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.HL)) + }, + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L)) ~ + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ + (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> {_ => + List(ZLine.register(PUSH, ZRegister.HL)) + }, + + (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ + (Elidable & HasOpcode(EX_DE_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> { _ => + List( + ZLine.ld8(ZRegister.D, ZRegister.B), + ZLine.ld8(ZRegister.E, ZRegister.C)) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, ctx.get[Constant](0))) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.H) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, (ctx.get[Constant](0) + 1).quickSimplify)) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.DE, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.E) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, ctx.get[Constant](0))) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.DE, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.D) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, (ctx.get[Constant](0) + 1).quickSimplify)) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.BC, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.C) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, ctx.get[Constant](0))) + }, + + (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(ZRegister.BC, ZRegister.MEM_ABS_16)) & MatchParameter(0)) ~ + (Elidable & Is8BitLoad(ZRegister.A, ZRegister.B) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> { (code, ctx) => + List(ZLine.ldAbs8(ZRegister.A, (ctx.get[Constant](0) + 1).quickSimplify)) + }, + + (Elidable & Is8BitLoad(ZRegister.D, ZRegister.B)) ~ + (Elidable & Is8BitLoad(ZRegister.E, ZRegister.C)) ~ + (Not(Concerns(ZRegister.DE)) & Not(Concerns(ZRegister.BC))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & DoesntMatterWhatItDoesWith(ZRegister.DE, ZRegister.BC)) ~~> { code => + code.drop(2).init :+ code.last.copy(registers = TwoRegisters(ZRegister.HL, ZRegister.BC)) + }, + + (Elidable & Is8BitLoad(ZRegister.B, ZRegister.D)) ~ + (Elidable & Is8BitLoad(ZRegister.C, ZRegister.E)) ~ + (Not(Concerns(ZRegister.DE)) & Not(Concerns(ZRegister.BC))).* ~ + (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & DoesntMatterWhatItDoesWith(ZRegister.DE, ZRegister.BC)) ~~> { code => + code.drop(2).init :+ code.last.copy(registers = TwoRegisters(ZRegister.HL, ZRegister.DE)) + }, + ) + + val UnusedCodeRemoval = new RuleBasedAssemblyOptimization("Unreachable code removal", + needsFlowInfo = FlowInfoRequirement.NoRequirement, + (HasOpcodeIn(Set(JP, JR)) & HasRegisters(NoRegisters)) ~ (Not(HasOpcode(LABEL)) & Elidable).+ ~~> (c => c.head :: Nil) + ) + + val UnusedLabelRemoval = new RuleBasedAssemblyOptimization("Unused label removal", + needsFlowInfo = FlowInfoRequirement.JustLabels, + (Elidable & HasOpcode(LABEL) & HasCallerCount(0)) ~~> (_ => Nil) + ) + + val BranchInPlaceRemoval = new RuleBasedAssemblyOptimization("Branch in place", + needsFlowInfo = FlowInfoRequirement.NoRequirement, + (HasOpcodeIn(Set(JP, JR)) & MatchJumpTarget(0) & Elidable) ~ + HasOpcodeIn(ZOpcodeClasses.NoopDiscards).* ~ + (HasOpcode(LABEL) & MatchJumpTarget(0)) ~~> (c => c.last :: Nil), + ) + + val SimplifiableShifting = new RuleBasedAssemblyOptimization("Simplifiable shifting", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RRCA), + ZLine.imm8(AND, 0x80)) + }, + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RRCA), + ZLine.implied(RRCA), + ZLine.imm8(AND, 0xc0)) + }, + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RRCA), + ZLine.implied(RRCA), + ZLine.implied(RRCA), + ZLine.imm8(AND, 0xe0)) + }, + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RLCA), + ZLine.imm8(AND, 1)) + }, + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RLCA), + ZLine.implied(RLCA), + ZLine.imm8(AND, 3)) + }, + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List( + ZLine.implied(RLCA), + ZLine.implied(RLCA), + ZLine.implied(RLCA), + ZLine.imm8(AND, 7)) + }, + ) + + val All: List[AssemblyOptimization[ZLine]] = List[AssemblyOptimization[ZLine]]( + BranchInPlaceRemoval, + FreeHL, + PointlessLoad, + PointlessStackStashing, + ReloadingKnownValueFromMemory, + SimplifiableMaths, + SimplifiableShifting, + UnusedCodeRemoval, + UnusedLabelRemoval, + UsingKnownValueFromAnotherRegister, + ) +} + + diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala index 6a5a0e18..326aab72 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodZ80Optimizations.scala @@ -7,6 +7,7 @@ import millfork.env.{CompoundConstant, Constant, MathOperator, NumericConstant} import millfork.node.ZRegister /** + * Optimizations valid for Z80 and EZ80 * @author Karol Stasiak */ object AlwaysGoodZ80Optimizations { @@ -27,245 +28,6 @@ object AlwaysGoodZ80Optimizations { def for6Registers(f: ZRegister.Value => AssemblyRuleSet) = MultipleAssemblyRules( List(ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L).map(f)) - val UsingKnownValueFromAnotherRegister = new RuleBasedAssemblyOptimization("Using known value from another register", - needsFlowInfo = FlowInfoRequirement.ForwardFlow, - for7Registers(register => - (Elidable & IsRegular8BitLoadFrom(register) & MatchRegister(register, 0)) ~~> ((code, ctx) => - code.map(x => x.copy( - parameter = NumericConstant(ctx.get[Int](0), 1), - registers = x.registers match { - case TwoRegisters(t, _) => TwoRegisters(t, ZRegister.IMM_8) - case TwoRegistersOffset(t@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), _, o) => TwoRegistersOffset(t, ZRegister.IMM_8, o) - case TwoRegistersOffset(t, ZRegister.MEM_IX_D | ZRegister.MEM_IY_D, _) => TwoRegisters(t, ZRegister.IMM_8) - } - ))) - ), - (Elidable & MatchSourceIxOffsetOf8BitLoad(0) & MatchValueAtMatchedIxOffset(0, 1)) ~~> ((code, ctx) => - code.map(x => x.copy( - parameter = NumericConstant(ctx.get[Int](1), 1), - registers = x.registers match { - case TwoRegisters(t, _) => TwoRegisters(t, ZRegister.IMM_8) - case TwoRegistersOffset(t@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), _, o) => TwoRegistersOffset(t, ZRegister.IMM_8, o) - case TwoRegistersOffset(t, ZRegister.MEM_IX_D | ZRegister.MEM_IY_D, _) => TwoRegisters(t, ZRegister.IMM_8) - } - )) - ), - for6Registers(register => - (Elidable & HasRegisterParam(register) & HasOpcodeIn(Set(AND, ADD, ADC, SUB, SBC, XOR, OR, CP)) & MatchRegister(register, 0)) ~~> ((code, ctx) => - code.map(x => x.copy( - parameter = NumericConstant(ctx.get[Int](0), 1), - registers = OneRegister(ZRegister.IMM_8) - ))) - ), - (Elidable & MatchIxOffset(0) & HasOpcodeIn(Set(AND, ADD, ADC, SUB, SBC, XOR, OR, CP)) & MatchValueAtMatchedIxOffset(0, 1)) ~~> ((code, ctx) => - code.map(x => x.copy( - parameter = NumericConstant(ctx.get[Int](1), 1), - registers = OneRegister(ZRegister.IMM_8) - )) - ), - ) - - val ReloadingKnownValueFromMemory = new RuleBasedAssemblyOptimization("Reloading known value from memory", - needsFlowInfo = FlowInfoRequirement.ForwardFlow, - for7Registers(register => - Is8BitLoad(ZRegister.MEM_HL, register) ~ - (Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~ - (Elidable & Is8BitLoad(register, ZRegister.MEM_HL)) ~~> { code => code.init } - ), - for7Registers(register => - Is8BitLoad(ZRegister.MEM_HL, register) ~ - (Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~ - (Elidable & IsRegular8BitLoadFrom(ZRegister.MEM_HL)) ~~> { code => - val last = code.last - code.init :+ last.copy(registers = TwoRegisters(last.registers.asInstanceOf[TwoRegisters].target, register)) - } - ), - (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init }, - - (Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init }, - - (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init }, - - (Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init }, - - (Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.HL))).* ~ - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { code => code.init }, - - (Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0) & MatchRegister(ZRegister.A, 2)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8))).* ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { (code, ctx) => - code.init :+ ZLine.ldImm8(ZRegister.A, ctx.get[Int](2)) - }, - - (Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0) & MatchConstantInHL(2)).captureLine(1) ~ - (Linear & DoesntChangeMemoryAt(1) & Not(Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16))).* ~ - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { (code, ctx) => - code.init :+ ZLine.ldImm16(ZRegister.HL, ctx.get[Constant](2)) - }, - ) - - val PointlessLoad = new RuleBasedAssemblyOptimization("Pointless load", - needsFlowInfo = FlowInfoRequirement.BackwardFlow, - // 0-6 - for7Registers(register => - (Elidable & Is8BitLoadTo(register) & DoesntMatterWhatItDoesWith(register)) ~~> (_ => Nil) - ), - // 7-11 - for5LargeRegisters(register => - (Elidable & Is16BitLoadTo(register) & DoesntMatterWhatItDoesWith(register)) ~~> (_ => Nil) - ), - // 12-18 - for7Registers(register => - (Is8BitLoad(register, ZRegister.IMM_8) & MatchImmediate(0)) ~ - (Linear & Not(Changes(register))).* ~ - (Elidable & Is8BitLoad(register, ZRegister.IMM_8) & MatchImmediate(0)) ~~> (_.init) - ), - // 19-23 - for5LargeRegisters(register => - (Is16BitLoad(register, ZRegister.IMM_16) & MatchImmediate(0)) ~ - (Linear & Not(Changes(register))).* ~ - (Elidable & Is16BitLoad(register, ZRegister.IMM_16) & MatchImmediate(0)) ~~> (_.init) - ), - // 24 - (Elidable & Is8BitLoadTo(ZRegister.MEM_HL)) ~ - (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.HL))).* ~ - Is8BitLoadTo(ZRegister.MEM_HL) ~~> (_.tail), - // 25 - (Elidable & Is8BitLoadTo(ZRegister.MEM_DE)) ~ - (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.DE))).* ~ - Is8BitLoadTo(ZRegister.MEM_DE) ~~> (_.tail), - // 26 - (Elidable & Is8BitLoadTo(ZRegister.MEM_BC)) ~ - (Linear & Not(ConcernsMemory) & Not(Changes(ZRegister.BC))).* ~ - Is8BitLoadTo(ZRegister.MEM_BC) ~~> (_.tail), - // 27 - (Elidable & MatchTargetIxOffsetOf8BitLoad(0) & MatchUnimportantIxOffset(0)) ~~> (_ => Nil), - // 28-34 - for7Registers(register => - (Elidable & Is8BitLoadTo(register) & NoOffset & MatchSourceRegisterAndOffset(1)) ~ - (Linear & Not(Concerns(register)) & DoesntChangeMatchedRegisterAndOffset(1)).* ~ - (Elidable & IsRegular8BitLoadFrom(register) & DoesntMatterWhatItDoesWith(register)) ~~> { code => - val last = code.last - val head = code.head - code.tail.init :+ ZLine(LD, (last.registers, head.registers) match { - case (TwoRegisters(t, _), TwoRegisters(_, s)) => TwoRegisters(t, s) - case (TwoRegistersOffset(t, _, o), TwoRegisters(_, s)) => TwoRegistersOffset(t, s, o) - case (TwoRegisters(t, _), TwoRegistersOffset(_, s, o)) => TwoRegistersOffset(t, s, o) - case _ => ??? - }, head.parameter) - } - ), - // 35-41 - for7Registers(register => - (Elidable & Is8BitLoad(register, register)) ~~> (_ => Nil) - ), - // 42-48 - for6Registers(register => - (Elidable & Is8BitLoadTo(register) & MatchSourceRegisterAndOffset(0) & MatchParameterOrNothing(1)) ~ - (Linear & Not(Concerns(register)) & DoesntChangeMatchedRegisterAndOffset(0)).* ~ - (Elidable & HasOpcodeIn(Set(ADD, ADC, XOR, OR, AND, CP, SUB, SBC)) & - HasRegisters(OneRegister(register)) & DoesntMatterWhatItDoesWith(register)) ~~> { (code, ctx) => - code.tail.init :+ code.last.copy(registers = ctx.get[RegisterAndOffset](0).toOneRegister, parameter = ctx.get[Constant](1)) - } - ), - - // 49-54 - MultipleAssemblyRules { - import ZRegister._ - val regs = Seq((BC, B, C), (DE, D, E), (HL, H, L)) - for { - (t, th, tl) <- regs - (s, sh, sl) <- regs - if t != HL - if t != s - } yield { - // TODO: make it a bit more universal - (Elidable & Is8BitLoad(th, sh)) ~ - (Elidable & Is8BitLoad(tl, sl)) ~ - (HasOpcode(OR) & HasRegisterParam(A)).?.capture(1) ~ - (Elidable & HasOpcodeIn(Set(ADD_16, ADC_16, SBC_16)) & HasRegisters(TwoRegisters(HL, t)) & DoesntMatterWhatItDoesWith(t)) ~~> { - (code, ctx) => - ctx.get[List[ZLine]](1) :+ code.last.copy(registers = TwoRegisters(HL, s)) - } - } - }, - // 55-59 - for5LargeRegisters(register => - (Is16BitLoad(register, ZRegister.MEM_ABS_16) & MatchParameter(0)).captureLine(1) ~ - (Linear & Not(Changes(register)) & DoesntChangeMemoryAt(1)).* ~ - (Elidable & Is16BitLoad(register, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> (_.init) - ), - // 60 - (HasOpcode(LD) & MatchSourceRegisterAndOffset(0) & MatchTargetRegisterAndOffset(1)) ~ - Where(ctx => ctx.get[RegisterAndOffset](0).register != ZRegister.MEM_ABS_8 && ctx.get[RegisterAndOffset](1).register != ZRegister.MEM_ABS_8) ~ - (Elidable & HasOpcode(LD) & MatchSourceRegisterAndOffset(1) & MatchTargetRegisterAndOffset(0)) ~~> (_.init) - ) - - val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing", - needsFlowInfo = FlowInfoRequirement.BackwardFlow, - // 0-4 - for5LargeRegisters(register => { - (Elidable & HasOpcode(PUSH) & HasRegisterParam(register)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(register))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(register)) ~~> (_.tail.init) - }), - // 5 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.D)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.D))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> {code => - ZLine.ld8(ZRegister.D, ZRegister.E) :: (code.tail.init :+ ZLine.ld8(ZRegister.E, ZRegister.D)) - }, - // 6 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.E)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.E))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code => - ZLine.ld8(ZRegister.E, ZRegister.D) :: (code.tail.init :+ ZLine.ld8(ZRegister.D, ZRegister.E)) - }, - // 7 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.B)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.B))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> (code => - ZLine.ld8(ZRegister.B, ZRegister.C) :: (code.tail.init :+ ZLine.ld8(ZRegister.C, ZRegister.B)) - ), - // 8 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.C)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.C))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code => - ZLine.ld8(ZRegister.C, ZRegister.B) :: (code.tail.init :+ ZLine.ld8(ZRegister.B, ZRegister.C)) - }, - // 9 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.H)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.H))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => - ZLine.ld8(ZRegister.H, ZRegister.L) :: (code.tail.init :+ ZLine.ld8(ZRegister.L, ZRegister.H)) - }, - // 10 - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.L)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH))) & Not(Changes(ZRegister.L)) ).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => - ZLine.ld8(ZRegister.L, ZRegister.H) :: (code.tail.init :+ ZLine.ld8(ZRegister.H, ZRegister.L)) - }, - // 11-15 - for5LargeRegisters(register => { - (Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(register, ZRegister.IMM_16))) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(register) & DoesntMatterWhatItDoesWith(register)) ~ - (Linear & Not(HasOpcodeIn(Set(POP,PUSH)))).* ~ - (Elidable & HasOpcode(POP) & HasRegisterParam(register)) ~~> { code => - code.drop(2).init :+ code.head - } - }), - - ) - private def simplifiable16BitAddWithSplitTarget(targetH: ZRegister.Value, targetL: ZRegister.Value, target: ZRegister.Value, source: ZRegister.Value) = MultipleAssemblyRules(List( (Is8BitLoad(targetH, ZRegister.IMM_8) & MatchImmediate(1)) ~ (Linear & Not(Changes(target))).* ~ @@ -309,199 +71,20 @@ object AlwaysGoodZ80Optimizations { }, )) - val SimplifiableMaths = new RuleBasedAssemblyOptimization("Simplifiable maths", + val SimplifiableMaths = new RuleBasedAssemblyOptimization("Simplifiable maths (Z80)", needsFlowInfo = FlowInfoRequirement.BothFlows, - for6Registers(register => - (Elidable & HasOpcode(ADD) & MatchRegister(ZRegister.A, 0) & HasRegisterParam(register) & MatchRegister(register, 1) & - DoesntMatterWhatItDoesWithFlags) ~~> ((code, ctx) => List(ZLine.ldImm8(ZRegister.A, (ctx.get[Int](0) + ctx.get[Int](1)) & 0xff))), - ), - simplifiable16BitAddWithSplitTarget(ZRegister.H, ZRegister.L, ZRegister.HL, ZRegister.BC), - simplifiable16BitAddWithSplitTarget(ZRegister.H, ZRegister.L, ZRegister.HL, ZRegister.DE), simplifiable16BitAddWithSplitTarget(ZRegister.IXH, ZRegister.IXL, ZRegister.IX, ZRegister.BC), simplifiable16BitAddWithSplitTarget(ZRegister.IXH, ZRegister.IXL, ZRegister.IX, ZRegister.DE), simplifiable16BitAddWithSplitTarget(ZRegister.IYH, ZRegister.IYL, ZRegister.IY, ZRegister.BC), simplifiable16BitAddWithSplitTarget(ZRegister.IYH, ZRegister.IYL, ZRegister.IY, ZRegister.DE), - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & MatchRegister(ZRegister.BC, 0) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.ldImm16(ZRegister.HL, ctx.get[Int](0) + ctx.get[Int](1))) - }, - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & MatchRegister(ZRegister.DE, 0) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.ldImm16(ZRegister.HL, ctx.get[Int](0) + ctx.get[Int](1))) - }, - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.HL)) & MatchRegister(ZRegister.HL, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.ldImm16(ZRegister.HL, 2 * ctx.get[Int](1) & 0xffff)) - }, - - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & HasRegister(ZRegister.BC, 0) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - Nil - }, - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & HasRegister(ZRegister.DE, 0) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - Nil - }, - - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & HasRegister(ZRegister.BC, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.register(ZOpcode.INC_16, ZRegister.HL)) - }, - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & HasRegister(ZRegister.DE, 1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.register(ZOpcode.INC_16, ZRegister.HL)) - }, - - - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & MatchRegister(ZRegister.BC, 0) & MatchConstantInHL(1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.ldImm16(ZRegister.HL, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) - }, - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & MatchRegister(ZRegister.DE, 0) & MatchConstantInHL(1) & DoesntMatterWhatItDoesWithFlags) ~~> { (code, ctx) => - List(ZLine.ldImm16(ZRegister.HL, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) - }, - - - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ - (Elidable & Is8BitLoadTo(ZRegister.L)) ~ - (Elidable & Is8BitLoadTo(ZRegister.H)) ~ - (HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & DoesntMatterWhatItDoesWith(ZRegister.D, ZRegister.E)) ~~> { code => - List( - change8BitLoadTarget(code(2), ZRegister.E), - change8BitLoadTarget(code(3), ZRegister.D), - code.last) - }, - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ - (Elidable & Is8BitLoadTo(ZRegister.H)) ~ - (Elidable & Is8BitLoadTo(ZRegister.L)) ~ - (HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE)) & DoesntMatterWhatItDoesWith(ZRegister.D, ZRegister.E)) ~~> { code => - List( - change8BitLoadTarget(code(2), ZRegister.D), - change8BitLoadTarget(code(3), ZRegister.E), - code.last) - }, - - (Elidable & HasOpcodeIn(Set(ADD, OR, XOR, SUB)) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), - (Elidable & HasOpcode(AND) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), - (Elidable & HasOpcode(AND) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.ldImm8(ZRegister.A, 0))), - (Elidable & HasOpcode(AND) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.ldImm8(ZRegister.A, 0))), - - - (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ - (Elidable & HasOpcodeIn(Set(JP, JR)) & HasRegisters(IfFlagSet(ZFlag.S)) & DoesntMatterWhatItDoesWithFlags) ~ - Where(ctx => ctx.get[Constant](1).isInstanceOf[NumericConstant]) ~~> { (code, ctx) => - val value = (ctx.get[Int](0) | ctx.get[NumericConstant](1).value).toInt & 0xff - if (value.&(0x80) == 0) List(ZLine.ldImm8(ZRegister.A, value)) - else List(ZLine.ldImm8(ZRegister.A, value), code.last.copy(registers = NoRegisters)) - }, - - (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ - (Elidable & HasOpcodeIn(Set(JP, JR)) & HasRegisters(IfFlagClear(ZFlag.S)) & DoesntMatterWhatItDoesWithFlags) ~ - Where(ctx => ctx.get[Constant](1).isInstanceOf[NumericConstant]) ~~> { (code, ctx) => - val value = (ctx.get[Int](0) | ctx.get[NumericConstant](1).value).toInt & 0xff - if (value.&(0x80) != 0) List(ZLine.ldImm8(ZRegister.A, value)) - else List(ZLine.ldImm8(ZRegister.A, value), code.last.copy(registers = NoRegisters)) - }, - - (Elidable & HasOpcode(ADD) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, (ctx.get[Constant](1) + ctx.get[Int](0)).quickSimplify)) - }, - - (Elidable & HasOpcode(SUB) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, (NumericConstant(ctx.get[Int](0) & 0xff, 1) - ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & HasOpcode(OR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.Or, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & HasOpcode(XOR) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.Exor, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & HasOpcode(AND) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.And, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & HasOpcode(ADD) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ - (Elidable & HasOpcode(DAA) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.DecimalPlus, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & HasOpcode(SUB) & Match8BitImmediate(1) & MatchRegister(ZRegister.A, 0)) ~ - (Elidable & HasOpcode(DAA) & DoesntMatterWhatItDoesWithFlags) ~~> {(code, ctx) => - List(ZLine.ldImm8(ZRegister.A, CompoundConstant(MathOperator.DecimalMinus, NumericConstant(ctx.get[Int](0) & 0xff, 1), ctx.get[Constant](1)).quickSimplify)) - }, - - (Elidable & (Is8BitLoadTo(ZRegister.A) | HasOpcode(LD) & HasRegisters(TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)))) ~ - (Elidable & HasOpcode(SUB) & Has8BitImmediate(0)) ~ - (Is8BitLoadTo(ZRegister.A) | HasOpcode(LD) & HasRegisters(TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8))) ~ - (Elidable & HasOpcode(SBC)) ~~> { code => - List(code(2), code(3).copy(opcode = SUB)) - }, - - (Elidable & HasOpcode(DEC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ - (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ - (Elidable & HasOpcode(INC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), - - (Elidable & HasOpcode(INC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ - (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ - (Elidable & HasOpcode(DEC) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), - - (Elidable & HasOpcode(DEC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ - (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ - (Elidable & HasOpcode(INC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), - - (Elidable & HasOpcode(INC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~ - (Elidable & Linear & DoesntConcernMatchedRegisterAndOffset(0)).* ~ - (Elidable & HasOpcode(DEC_16) & MatchSoleRegisterAndOffset(0) & DoesntMatterWhatItDoesWithFlags) ~~> (_.tail.init), - - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.B)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.C)) ~ - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.DE))) ~~> { code => - ZLine.registers(code.last.opcode, ZRegister.HL, ZRegister.BC) :: code.take(2) - }, - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.D)) ~ - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.E)) ~ - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC))) ~~> { code => - ZLine.registers(code.last.opcode, ZRegister.HL, ZRegister.DE) :: code.take(2) - }, - - (Elidable & HasOpcode(INC) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil), - (Elidable & HasOpcode(NEG)) ~ (Elidable & HasOpcode(ADD) & Has8BitImmediate(0xff) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => List(ZLine.implied(CPL))), ) - val FreeHL = new RuleBasedAssemblyOptimization("Free HL", + val FreeHL = new RuleBasedAssemblyOptimization("Free HL (Z80)", needsFlowInfo = FlowInfoRequirement.BackwardFlow, - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ - (Elidable & Is8BitLoadTo(ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL, ZRegister.A)) ~~> (code => - List( - code(1).copy(registers = TwoRegisters(ZRegister.A, code(1).registers.asInstanceOf[TwoRegisters].source)), - code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.MEM_ABS_8, ZRegister.A)), - )), - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ - (Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => - List( - code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)), - )), - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ - (Elidable & IsRegular8BitLoadFrom(ZRegister.MEM_HL) & DoesntMatterWhatItDoesWith(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.A)) ~~> (code => - List( - code.head.copy(opcode = LD, registers = TwoRegisters(ZRegister.A, ZRegister.MEM_ABS_8)), - code(1).copy(registers = TwoRegisters(code(1).registers.asInstanceOf[TwoRegisters].target, ZRegister.A)), - )), - - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => - List( - code.head.copy(registers = TwoRegisters(ZRegister.DE, ZRegister.IMM_16)) - )), - (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.IMM_16)) ~ - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => - List( - code.head.copy(registers = TwoRegisters(ZRegister.BC, ZRegister.IMM_16)) - )), (Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16)) ~ (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ @@ -534,64 +117,6 @@ object AlwaysGoodZ80Optimizations { } }), - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ - (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & 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)) ~ - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & 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)) ~ - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => - List( - ZLine.ld8(ZRegister.B, ZRegister.D), - ZLine.ld8(ZRegister.C, ZRegister.E), - code(2).copy(registers = OneRegister(ZRegister.BC)) - )), - - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ - (Elidable & HasOpcodeIn(Set(INC_16, DEC_16, PUSH, POP)) & HasRegisterParam(ZRegister.HL)) ~ - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> (code => - List( - ZLine.ld8(ZRegister.D, ZRegister.B), - ZLine.ld8(ZRegister.E, ZRegister.C), - code(2).copy(registers = OneRegister(ZRegister.DE)) - )), - - - // 2 bytes more, but 3 cycles fewer and frees BC - (Elidable & Is16BitLoad(ZRegister.BC, ZRegister.IMM_16) & MatchParameter(0)) ~ - (Linear & Not(Concerns(ZRegister.BC)) & Not(Concerns(ZRegister.HL))).*.capture(1) ~ - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.A)) ~ - (Elidable & Is8BitLoadTo(ZRegister.H) & Has8BitImmediate(0)) ~ - (Elidable & HasOpcode(ADD_16) & HasRegisters(TwoRegisters(ZRegister.HL, ZRegister.BC)) & - DoesntMatterWhatItDoesWithFlagsExceptCarry & - DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> { (code, ctx) => - val offset = ctx.get[Constant](0) - ctx.get[List[ZLine]](1) ++ List( - ZLine.imm8(ADD, offset.loByte), - ZLine.ld8(ZRegister.L, ZRegister.A), - ZLine.ldImm8(ZRegister.A, 0), - ZLine.imm8(ADC, offset.hiByte), - ZLine.ld8(ZRegister.H, ZRegister.A)) - }, - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ (Elidable & Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => @@ -616,150 +141,11 @@ object AlwaysGoodZ80Optimizations { List(ZLine.ld8(ZRegister.A, ZRegister.MEM_DE)) }, - - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.DE)) - }, - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.BC)) - }, - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.HL)) - }, - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.HL)) - }, - - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.E)) ~ - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.D)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.DE)) - }, - (Elidable & Is8BitLoad(ZRegister.L, ZRegister.C)) ~ - (Elidable & Is8BitLoad(ZRegister.H, ZRegister.B)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.BC)) - }, - (Elidable & Is8BitLoad(ZRegister.E, ZRegister.L)) ~ - (Elidable & Is8BitLoad(ZRegister.D, ZRegister.H)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.HL)) - }, - (Elidable & Is8BitLoad(ZRegister.C, ZRegister.L)) ~ - (Elidable & Is8BitLoad(ZRegister.B, ZRegister.H)) ~ - (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~~> {_ => - List(ZLine.register(PUSH, ZRegister.HL)) - }, - - - ) - - val UnusedCodeRemoval = new RuleBasedAssemblyOptimization("Unreachable code removal", - needsFlowInfo = FlowInfoRequirement.NoRequirement, - (HasOpcodeIn(Set(JP, JR)) & HasRegisters(NoRegisters)) ~ (Not(HasOpcode(LABEL)) & Elidable).+ ~~> (c => c.head :: Nil) - ) - - val UnusedLabelRemoval = new RuleBasedAssemblyOptimization("Unused label removal", - needsFlowInfo = FlowInfoRequirement.JustLabels, - (Elidable & HasOpcode(LABEL) & HasCallerCount(0)) ~~> (_ => Nil) - ) - - val BranchInPlaceRemoval = new RuleBasedAssemblyOptimization("Branch in place", - needsFlowInfo = FlowInfoRequirement.NoRequirement, - (HasOpcodeIn(Set(JP, JR)) & MatchJumpTarget(0) & Elidable) ~ - HasOpcodeIn(ZOpcodeClasses.NoopDiscards).* ~ - (HasOpcode(LABEL) & MatchJumpTarget(0)) ~~> (c => c.last :: Nil), - ) - - val SimplifiableShifting = new RuleBasedAssemblyOptimization("Simplifiable shifting", - needsFlowInfo = FlowInfoRequirement.BackwardFlow, - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RRC, ZRegister.A), - ZLine.imm8(AND, 0x80)) - }, - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RRC, ZRegister.A), - ZLine.register(RRC, ZRegister.A), - ZLine.imm8(AND, 0xc0)) - }, - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SLA) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RRC, ZRegister.A), - ZLine.register(RRC, ZRegister.A), - ZLine.register(RRC, ZRegister.A), - ZLine.imm8(AND, 0xe0)) - }, - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RLC, ZRegister.A), - ZLine.imm8(AND, 1)) - }, - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RLC, ZRegister.A), - ZLine.register(RLC, ZRegister.A), - ZLine.imm8(AND, 3)) - }, - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A)) ~ - (Elidable & HasOpcode(SRL) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => - List( - ZLine.register(RLC, ZRegister.A), - ZLine.register(RLC, ZRegister.A), - ZLine.register(RLC, ZRegister.A), - ZLine.imm8(AND, 7)) - }, ) val All: List[AssemblyOptimization[ZLine]] = List[AssemblyOptimization[ZLine]]( - BranchInPlaceRemoval, FreeHL, - PointlessLoad, - PointlessStackStashing, - ReloadingKnownValueFromMemory, SimplifiableMaths, - SimplifiableShifting, - UnusedCodeRemoval, - UnusedLabelRemoval, - UsingKnownValueFromAnotherRegister, ) } diff --git a/src/main/scala/millfork/assembly/z80/opt/LaterI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/LaterI80Optimizations.scala new file mode 100644 index 00000000..7059228a --- /dev/null +++ b/src/main/scala/millfork/assembly/z80/opt/LaterI80Optimizations.scala @@ -0,0 +1,31 @@ +package millfork.assembly.z80.opt + +import millfork.assembly.AssemblyOptimization +import millfork.assembly.z80.{ZLine, ZOpcode} +import millfork.node.ZRegister +import ZOpcode._ +import ZRegister._ + + +/** + * @author Karol Stasiak + */ +object LaterI80Optimizations { + val VariousSmallOptimizations = new RuleBasedAssemblyOptimization("Various small optimizations", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + + (Elidable & Is8BitLoadTo(A) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + List(ZLine.register(XOR, A)) + }, + (Elidable & HasOpcode(CP) & DoesntMatterWhatItDoesWithFlags) ~~> { _ => + Nil + }, + (Elidable & HasOpcode(CP) & Has8BitImmediate(0) & DoesntMatterWhatItDoesWithFlagsOtherThanSZ) ~~> { _ => + List(ZLine.register(OR, A)) + }, + ) + + val All: List[AssemblyOptimization[ZLine]] = List( + VariousSmallOptimizations + ) +} diff --git a/src/main/scala/millfork/assembly/z80/opt/LaterIntel8080Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/LaterIntel8080Optimizations.scala new file mode 100644 index 00000000..998a17f7 --- /dev/null +++ b/src/main/scala/millfork/assembly/z80/opt/LaterIntel8080Optimizations.scala @@ -0,0 +1,31 @@ +package millfork.assembly.z80.opt + +import millfork.assembly.AssemblyOptimization +import millfork.assembly.z80.{ZLine, ZOpcode} +import millfork.node.ZRegister +import ZOpcode._ +import ZRegister._ + +/** + * @author Karol Stasiak + */ +object LaterIntel8080Optimizations { + val UseExDeHl = new RuleBasedAssemblyOptimization("Use EX DE,HL", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + + (Elidable & Is8BitLoad(D, H)) ~ + (Elidable & Is8BitLoad(E, L) & DoesntMatterWhatItDoesWith(HL)) ~~> { _ => + List(ZLine.implied(EX_DE_HL)) + }, + + (Elidable & Is8BitLoad(H, D)) ~ + (Elidable & Is8BitLoad(L, E) & DoesntMatterWhatItDoesWith(DE)) ~~> { _ => + List(ZLine.implied(EX_DE_HL)) + }, + ) + + val All: List[AssemblyOptimization[ZLine]] = List( + UseExDeHl + ) + +} diff --git a/src/main/scala/millfork/assembly/z80/opt/LaterSharpOptimizations.scala b/src/main/scala/millfork/assembly/z80/opt/LaterSharpOptimizations.scala new file mode 100644 index 00000000..13bb2340 --- /dev/null +++ b/src/main/scala/millfork/assembly/z80/opt/LaterSharpOptimizations.scala @@ -0,0 +1,59 @@ +package millfork.assembly.z80.opt + +import millfork.assembly.AssemblyOptimization +import millfork.assembly.z80.ZLine +import millfork.assembly.z80.ZOpcode._ +import millfork.node.ZRegister._ + +/** + * @author Karol Stasiak + */ +object LaterSharpOptimizations { + val UseSwap = new RuleBasedAssemblyOptimization("Use SWAP", + needsFlowInfo = FlowInfoRequirement.BackwardFlow, + + (Elidable & HasOpcode(RRA)) ~ + (Elidable & HasOpcode(RRA)) ~ + (Elidable & HasOpcode(RRA)) ~ + (Elidable & HasOpcode(RRA)) ~ + (HasOpcode(AND) & Has8BitImmediate(0xf)) ~~> { code => + List(ZLine.register(SWAP, A), code.last) + }, + + (Elidable & HasOpcode(RR) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RR) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RR) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RR) & HasRegisterParam(A)) ~ + (HasOpcode(AND) & Has8BitImmediate(0xf)) ~~> { code => + List(ZLine.register(SWAP, A), code.last) + }, + + (Elidable & HasOpcode(RRCA)) ~ + (Elidable & HasOpcode(RRCA)) ~ + (Elidable & HasOpcode(RRCA)) ~ + (Elidable & HasOpcode(RRCA)) ~ + (HasOpcode(AND) & Has8BitImmediate(0xf)) ~~> { code => + List(ZLine.register(SWAP, A), code.last) + }, + + (Elidable & HasOpcode(RRC) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RRC) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RRC) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(RRC) & HasRegisterParam(A)) ~ + (HasOpcode(AND) & Has8BitImmediate(0xf)) ~~> { code => + List(ZLine.register(SWAP, A), code.last) + }, + + (Elidable & HasOpcode(SRL) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(A)) ~ + (Elidable & HasOpcode(SRL) & HasRegisterParam(A)) ~ + (HasOpcode(AND) & Has8BitImmediate(0xf)) ~~> { code => + List(ZLine.register(SWAP, A), code.last) + }, + ) + + val All: List[AssemblyOptimization[ZLine]] = List( + UseSwap + ) +} diff --git a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala index 9b523b71..9a2957c2 100644 --- a/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/z80/opt/RuleBasedAssemblyOptimization.scala @@ -610,6 +610,17 @@ case object DoesntMatterWhatItDoesWithFlags extends AssemblyLinePattern { override def toString: String = "[¯\\_(ツ)_/¯:F]" } +case object DoesntMatterWhatItDoesWithFlagsOtherThanSZ extends AssemblyLinePattern { + + override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = + FlowInfoRequirement.assertBackward(needsFlowInfo) + + override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean = + ZFlag.AllButSZ.forall(r => flowInfo.importanceAfter.getFlag(r) != Important) + + override def toString: String = "[¯\\_(ツ)_/¯:NPVH]" +} + case object DoesntMatterWhatItDoesWithFlagsExceptCarry extends AssemblyLinePattern { override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = @@ -701,6 +712,27 @@ case class Reads(register: ZRegister.Value) extends TrivialAssemblyLinePattern { override def apply(line: ZLine): Boolean = line.readsRegister(register) } +case object ReadsStackPointer extends TrivialAssemblyLinePattern { + override def apply(line: ZLine): Boolean = { + import ZOpcode._ + line.opcode match { + case LD_16 | ADD_16 | ADC_16 | SBC_16 => + line.registers match { + case TwoRegisters(_, ZRegister.SP) => true + case _ => false + } + case EX_SP => true + case INC_16 | DEC_16 => + line.registers match { + case OneRegister(ZRegister.SP) => true + case _ => false + } + case LD_HLSP | PUSH | POP => true + case _ => false + } + } +} + case class Changes(register: ZRegister.Value) extends TrivialAssemblyLinePattern { override def apply(line: ZLine): Boolean = line.changesRegister(register) } diff --git a/src/main/scala/millfork/assembly/z80/opt/Z80OptimizationPresets.scala b/src/main/scala/millfork/assembly/z80/opt/Z80OptimizationPresets.scala index 1c25613e..ef07f81b 100644 --- a/src/main/scala/millfork/assembly/z80/opt/Z80OptimizationPresets.scala +++ b/src/main/scala/millfork/assembly/z80/opt/Z80OptimizationPresets.scala @@ -11,17 +11,42 @@ object Z80OptimizationPresets { val GoodForZ80: List[AssemblyOptimization[ZLine]] = { List.fill(5)( List.fill(5)( - AlwaysGoodZ80Optimizations.All ++ + AlwaysGoodI80Optimizations.All ++ + AlwaysGoodZ80Optimizations.All ++ List( EmptyParameterStoreRemoval, EmptyMemoryStoreRemoval) ).flatten ++ - List(WordVariableToRegisterOptimization, ByteVariableToRegisterOptimization, CompactStackFrame) + List(WordVariableToRegisterOptimization, ByteVariableToRegisterOptimization, CompactStackFrame) ++ + LaterIntel8080Optimizations.All ).flatten } - val GoodForIntel8080: List[AssemblyOptimization[ZLine]] = Nil // TODO + val GoodForIntel8080: List[AssemblyOptimization[ZLine]] = { + List.fill(5)( + List.fill(5)( + AlwaysGoodI80Optimizations.All ++ + List( + EmptyParameterStoreRemoval, + EmptyMemoryStoreRemoval, + ) + ).flatten ++ + List(WordVariableToRegisterOptimization, ByteVariableToRegisterOptimization) ++ + LaterIntel8080Optimizations.All + ).flatten + } - val GoodForSharp: List[AssemblyOptimization[ZLine]] = Nil // TODO + val GoodForSharp: List[AssemblyOptimization[ZLine]] = { + List.fill(5)( + List.fill(5)( + AlwaysGoodI80Optimizations.All ++ + List( + EmptyParameterStoreRemoval, + EmptyMemoryStoreRemoval) + ).flatten ++ + List(WordVariableToRegisterOptimization, ByteVariableToRegisterOptimization) ++ + LaterSharpOptimizations.All + ).flatten + } } diff --git a/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala b/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala index f4def3a3..cca9864c 100644 --- a/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala +++ b/src/test/scala/millfork/test/emu/EmuBenchmarkRun.scala @@ -35,11 +35,11 @@ object EmuZ80BenchmarkRun { println(f"After inlining: $t2%7d") println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") - println(f"Running unoptimized") + println(f"Running Z80 unoptimized") verifier(m0) - println(f"Running optimized") + println(f"Running Z80 optimized") verifier(m1) - println(f"Running optimized inlined") + println(f"Running Z80 optimized inlined") verifier(m2) } } @@ -47,38 +47,38 @@ object EmuZ80BenchmarkRun { object EmuIntel8080BenchmarkRun { def apply(source: String)(verifier: MemoryBank => Unit): Unit = { val (Timings(t0, _), m0) = EmuUnoptimizedIntel8080Run.apply2(source) -// val (Timings(t1, _), m1) = EmuOptimizedIntel8080Run.apply2(source) -// val (Timings(t2, _), m2) = EmuOptimizedInlinedIntel8080Run.apply2(source) + val (Timings(t1, _), m1) = EmuOptimizedIntel8080Run.apply2(source) + val (Timings(t2, _), m2) = EmuOptimizedInlinedIntel8080Run.apply2(source) println(f"Before optimization: $t0%7d") -// println(f"After optimization: $t1%7d") -// println(f"After inlining: $t2%7d") -// println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") -// println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") - println(f"Running unoptimized") + println(f"After optimization: $t1%7d") + println(f"After inlining: $t2%7d") + println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") + println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") + println(f"Running 8080 unoptimized") verifier(m0) -// println(f"Running optimized") -// verifier(m1) -// println(f"Running optimized inlined") -// verifier(m2) + println(f"Running 8080 optimized") + verifier(m1) + println(f"Running 8080 optimized inlined") + verifier(m2) } } object EmuSharpBenchmarkRun { def apply(source: String)(verifier: MemoryBank => Unit): Unit = { val (Timings(t0, _), m0) = EmuUnoptimizedSharpRun.apply2(source) -// val (Timings(t1, _), m1) = EmuOptimizedSharpRun.apply2(source) -// val (Timings(t2, _), m2) = EmuOptimizedInlinedSharpRun.apply2(source) + val (Timings(t1, _), m1) = EmuOptimizedSharpRun.apply2(source) + val (Timings(t2, _), m2) = EmuOptimizedInlinedSharpRun.apply2(source) println(f"Before optimization: $t0%7d") -// println(f"After optimization: $t1%7d") -// println(f"After inlining: $t2%7d") -// println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") -// println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") - println(f"Running unoptimized") + println(f"After optimization: $t1%7d") + println(f"After inlining: $t2%7d") + println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%") + println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%") + println(f"Running LR35902 unoptimized") verifier(m0) -// println(f"Running optimized") -// verifier(m1) -// println(f"Running optimized inlined") -// verifier(m2) + println(f"Running LR35902 optimized") + verifier(m1) + println(f"Running LR35902 optimized inlined") + verifier(m2) } }