diff --git a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala index 0dd8772b..4b1d2371 100644 --- a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala @@ -1839,8 +1839,8 @@ object AlwaysGoodOptimizations { val ifSet = Elidable & HasOpcode(LDA) & HasImmediate(if (zeroIfSet) 0 else nonZero) val ifClear = Elidable & HasOpcode(LDA) & HasImmediate(if (zeroIfSet) nonZero else 0) val jump = Elidable & HasOpcodeIn(Set(JMP, if (firstSet) BCS else BCC, if (zeroIfSet) BEQ else BNE)) & MatchParameter(1) - val elseLabel = Elidable & HasOpcode(LABEL) & MatchParameter(0) - val afterLabel = Elidable & HasOpcode(LABEL) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.N, State.V, State.Z) + val elseLabel = (Elidable & HasOpcode(LABEL) & MatchParameter(0)).capture(10) + val afterLabel = Elidable & HasOpcode(LABEL) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.N, State.V, State.Z) & IsNotALabelUsedManyTimes val store = Elidable & (Not(ReadsC) & Linear | HasOpcodeIn(RTS, JSR, RTI, RTL, BSR)) val secondReturn = (Elidable & (HasOpcodeIn(RTS, RTI) | NoopDiscardsFlags)).*.capture(6) val where = Where { ctx => @@ -1851,13 +1851,22 @@ object AlwaysGoodOptimizations { if (firstSet) test ~ ifSet ~ store.*.capture(4) ~ jump ~ elseLabel ~ ifClear ~ store.*.capture(5) ~ afterLabel ~ secondReturn ~ where else test ~ ifClear ~ store.*.capture(4) ~ jump ~ elseLabel ~ ifSet ~ store.*.capture(5) ~ afterLabel ~ secondReturn ~ where pattern ~~> { (_, ctx) => + val elseLabelUseCount = ctx.get[Constant](0) match { + case MemoryAddressConstant(Label(label)) => ctx.labelUseCount(label) + case _ => 9999 + } List( AssemblyLine.immediate(LDA, 0), AssemblyLine.implied(if (shift >= 4) ROR else ROL)) ++ (if (shift >= 4) List.fill(7 - shift)(AssemblyLine.implied(LSR)) else List.fill(shift)(AssemblyLine.implied(ASL))) ++ (if (zeroIfSet) List(AssemblyLine.immediate(EOR, nonZero)) else Nil) ++ ctx.get[List[AssemblyLine]](5) ++ - ctx.get[List[AssemblyLine]](6) + ctx.get[List[AssemblyLine]](6) ++ ( + if (elseLabelUseCount == 1) Nil + else ctx.get[List[AssemblyLine]](10) ++ List( + AssemblyLine.immediate(LDA, if (firstSet) (if (zeroIfSet) nonZero else 0) else (if (zeroIfSet) 0 else nonZero)) + ) ++ ctx.get[List[AssemblyLine]](5) ++ ctx.get[List[AssemblyLine]](6) + ) } } diff --git a/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala index ed66f42e..0cd6d938 100644 --- a/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/UndocumentedOptimizations.scala @@ -178,9 +178,13 @@ object UndocumentedOptimizations { val UseArr = new RuleBasedAssemblyOptimization("Using undocumented instruction ARR", needsFlowInfo = FlowInfoRequirement.BothFlows, (HasClear(State.D) & Elidable & HasOpcode(AND) & HasAddrMode(Immediate)) ~ - (Elidable & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { code => + (Elidable & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.V, State.N, State.Z)) ~~> { code => List(AssemblyLine.immediate(ARR, code.head.parameter)) }, + (HasClear(State.D) & Elidable & HasOpcode(LDA) & HasAddrMode(Immediate) & HasImmediate(0)) ~ + (Elidable & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.V, State.N, State.Z)) ~~> { code => + List(AssemblyLine.immediate(ARR, 0)) + }, ) private def extraRmw(legal: Opcode.Value, illegal: Opcode.Value) = diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index e6c42bca..cf96707c 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -816,4 +816,33 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { m.readByte(0xc000) should equal(51) } } + + test("Test bug #41") { + val code = + """ + |struct Entity { + | byte x, + | byte y + |} + | + |array(Entity) entities [2] + | + |byte output @$c000 + | + |void main() { + | if test(0, 200) { + | output = 1 + | } + |} + | + |inline bool test(byte i, byte y) { + | return y >= entities[i].y && y <= entities[i].y + 8 + |} + | + |""".stripMargin + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code) { m => + + } + EmuUndocumentedRun(code) + } }