From 3d056a7eeef660ea5fe7ee42625fe5f16249aba9 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Tue, 27 Feb 2018 12:02:15 +0100 Subject: [PATCH] Optimization improvements --- .../assembly/opt/LaterOptimizations.scala | 16 ++++++ .../opt/VariableToRegisterOptimization.scala | 54 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala b/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala index ddccee15..f6358b78 100644 --- a/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala +++ b/src/main/scala/millfork/assembly/opt/LaterOptimizations.scala @@ -33,6 +33,22 @@ object LaterOptimizations { TwoDifferentLoadsWhoseFlagsWillNotBeChecked(LDA, Not(ChangesA), LDY, TAY), TwoDifferentLoadsWhoseFlagsWillNotBeChecked(LDX, Not(ChangesX), LDA, TXA), TwoDifferentLoadsWhoseFlagsWillNotBeChecked(LDY, Not(ChangesY), LDA, TYA), + + (HasOpcodeIn(Set(LDA, STA)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(ChangesA) & Not(HasOpcode(LDX)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TAX)), + + (HasOpcodeIn(Set(LDA, STA)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(ChangesA) & Not(HasOpcode(LDY)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TAY)), + + (HasOpcodeIn(Set(LDX, STX)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(ChangesX) & Not(HasOpcode(LDA)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TXA)), + + (HasOpcodeIn(Set(LDY, STY)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(ChangesY) & Not(HasOpcode(LDA)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TYA)), ) private def a2x(line: AssemblyLine) = line.opcode match { diff --git a/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala b/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala index 5d91dffc..0758f3aa 100644 --- a/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala +++ b/src/main/scala/millfork/assembly/opt/VariableToRegisterOptimization.scala @@ -53,6 +53,8 @@ object VariableToRegisterOptimization extends AssemblyOptimization { AHX, SHY, SHX, LAS, TAS, TRB, TSB) + private val opcodesCommutative = Set(AND, ORA, EOR, ADC) + private val LdxAddrModes = Set(ZeroPage, Absolute, Immediate, AbsoluteY, ZeroPageY) private val LdyAddrModes = Set(ZeroPage, Absolute, Immediate, AbsoluteX, ZeroPageX) @@ -288,6 +290,20 @@ object VariableToRegisterOptimization extends AssemblyOptimization { // if a register is populated with something else than a variable, then no variable cannot be assigned to that register None + case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs + if opcodesCommutative(op) => + if (th.name == vx || th.name == vy) { + if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, xs).map(_ + 2) + else None + } else canBeInlined(xCandidate, yCandidate, xs) + + case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(CLC, _, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs + if opcodesCommutative(op) => + if (th.name == vx || th.name == vy) { + if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, xs).map(_ + 2) + else None + } else canBeInlined(xCandidate, yCandidate, xs) + case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: (AssemblyLine(TAX, _, _, elidable2), _) :: xs if xCandidate.isDefined => // a variable cannot be inlined if there is TAX not after LDA of that variable @@ -416,6 +432,20 @@ object VariableToRegisterOptimization extends AssemblyOptimization { None } + case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs + if opcodesCommutative(op) => + if (th.name == candidate) { + if (elidable && elidable2) canBeInlinedToAccumulator(options, start = false, synced = true, candidate, xs).map(_ + 3) + else None + } else canBeInlinedToAccumulator(options, start = false, synced = synced, candidate, xs) + + case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(CLC, _, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs + if opcodesCommutative(op) => + if (th.name == candidate) { + if (elidable && elidable2) canBeInlinedToAccumulator(options, start = false, synced = true, candidate, xs).map(_ + 3) + else None + } else canBeInlinedToAccumulator(options, start = false, synced = synced, candidate, xs) + case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), imp) :: xs if th.name == candidate => // removing LDA saves 3 cycles @@ -505,6 +535,30 @@ object VariableToRegisterOptimization extends AssemblyOptimization { if th.name == vx => AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == va => + l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + + case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == va => + l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + + case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == vx => + AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + + case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == vx => + AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + + case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == vy => + AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + + case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs + if opcodesCommutative(op) && th.name == vy => + AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs) + case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs if th.name == va => if (imp.z == Unimportant && imp.n == Unimportant) {