diff --git a/src/main/scala/millfork/OptimizationPresets.scala b/src/main/scala/millfork/OptimizationPresets.scala index 3dfb8fb2..8128235a 100644 --- a/src/main/scala/millfork/OptimizationPresets.scala +++ b/src/main/scala/millfork/OptimizationPresets.scala @@ -133,6 +133,7 @@ object OptimizationPresets { AlwaysGoodOptimizations.CommonBranchBodyOptimization, AlwaysGoodOptimizations.CommonExpressionInConditional, AlwaysGoodOptimizations.CommonIndexSubexpressionElimination, + AlwaysGoodOptimizations.ConstantPointer, AlwaysGoodOptimizations.ConstantFlowAnalysis, AlwaysGoodOptimizations.ConstantIndexPropagation, AlwaysGoodOptimizations.DoubleJumpSimplification, diff --git a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala index 88c3e953..c5e83201 100644 --- a/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/opt/AlwaysGoodOptimizations.scala @@ -1395,4 +1395,53 @@ object AlwaysGoodOptimizations { ) } + // this grows the code by one byte, but shaves 1 cycle and allows for optimizing some stores away + val ConstantPointer = new RuleBasedAssemblyOptimization("Constant pointer optimization", + needsFlowInfo = FlowInfoRequirement.ForwardFlow, + + (HasOpcode(STA) & MatchA(0) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchParameter(4)) ~ + Where(ctx => { + val lo = ctx.get[Constant](4) + ctx.addObject(5, lo + 1) + ctx.addObject(3, ZeroPage) + true + }) ~ + (Linear & DoesNotConcernMemoryAt(3,4) & DoesNotConcernMemoryAt(3,5)).* ~ + (HasOpcode(STA) & MatchA(1) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchParameter(5)) ~ + Where(ctx => { + val lo = ctx.get[Int](0) & 0xff + val hi = ctx.get[Int](1) & 0xff + ctx.addObject(2, hi * 256 + lo) + true + }) ~ + (Linear & DoesNotConcernMemoryAt(3,4) & DoesNotConcernMemoryAt(3,5)).* ~ + (Elidable & MatchParameter(6) & HasAddrModeIn(Set(ZeroPageIndirect, IndexedY))) ~~> { (code, ctx) => + val addr = ctx.get[Int](2) + val last = code.last + code.init :+ last.copy(parameter = NumericConstant(addr, 2), addrMode = if (last.addrMode == ZeroPageIndirect) Absolute else AbsoluteY) + }, + + (HasOpcode(STA) & MatchA(0) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchParameter(4)) ~ + Where(ctx => { + val lo = ctx.get[Constant](4) + ctx.addObject(5, lo + 1) + ctx.addObject(3, ZeroPage) + true + }) ~ + (Linear & DoesNotConcernMemoryAt(3,4) & DoesNotConcernMemoryAt(3,5)).* ~ + (HasOpcode(STX) & MatchX(1) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchParameter(5)) ~ + Where(ctx => { + val lo = ctx.get[Int](0) & 0xff + val hi = ctx.get[Int](1) & 0xff + ctx.addObject(2, hi * 256 + lo) + true + }) ~ + (Linear & DoesNotConcernMemoryAt(3,4) & DoesNotConcernMemoryAt(3,5)).* ~ + (Elidable & MatchParameter(6) & HasAddrModeIn(Set(ZeroPageIndirect, IndexedY))) ~~> { (code, ctx) => + val addr = ctx.get[Int](2) + val last = code.last + code.init :+ last.copy(parameter = NumericConstant(addr, 2), addrMode = if (last.addrMode == ZeroPageIndirect) Absolute else AbsoluteY) + }, + ) + } diff --git a/src/main/scala/millfork/env/Constant.scala b/src/main/scala/millfork/env/Constant.scala index 19d7d90c..a16c13e3 100644 --- a/src/main/scala/millfork/env/Constant.scala +++ b/src/main/scala/millfork/env/Constant.scala @@ -158,6 +158,7 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co val l = lhs.quickSimplify val r = rhs.quickSimplify (l, r) match { + case (CompoundConstant(MathOperator.Shl, HalfWordConstant(c1, true), NumericConstant(8, _)), HalfWordConstant(c2, false)) if operator == MathOperator.Or && c1 == c2 => c1 case (NumericConstant(lv, ls), NumericConstant(rv, rs)) => var size = ls max rs val value = operator match { @@ -233,6 +234,7 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co val That = that val MinusThat = -that this match { + case CompoundConstant(Plus, CompoundConstant(Shl, HalfWordConstant(c1, true), NumericConstant(8, _)), HalfWordConstant(c2, false)) if c1 == c2 => c1 case CompoundConstant(Plus, NumericConstant(MinusThat, _), r) => r case CompoundConstant(Plus, l, NumericConstant(MinusThat, _)) => l case CompoundConstant(Plus, NumericConstant(x, _), r) => CompoundConstant(Plus, r, NumericConstant(x + that, minimumSize(x + that))) diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index 25e47b55..68c19d10 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -408,4 +408,24 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { | } """.stripMargin).readByte(0xc000) should equal(1) } + + test("Constant pointers") { + EmuBenchmarkRun( + """ + |byte output0 @$c000 + |byte output1 @$c001 + |void main() { + | pointer p + | p = output0.addr + | p[0] = 33 + | p = op() + | p[0] = 34 + |} + |word op () { return output1.addr } + """.stripMargin + ){m => + m.readByte(0xc000) should equal(33) + m.readByte(0xc001) should equal(34) + } + } } diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala index eb666ae9..03ca0d3c 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala @@ -15,7 +15,7 @@ object EmuOptimizedInlinedRun extends EmuRun( OptimizationPresets.Good, false) { override def inline: Boolean = true - override def blastProcessing: Boolean = true + override def blastProcessing: Boolean = false }