mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-01 06:29:53 +00:00
6502: optimize variable pointers
This commit is contained in:
parent
2a233930e8
commit
ffff51dee9
@ -2662,6 +2662,101 @@ object AlwaysGoodOptimizations {
|
||||
val last = code.last
|
||||
code.init :+ last.copy(parameter = NumericConstant(addr, 2), addrMode = if (last.addrMode == IndexedZ) Absolute else AbsoluteY)
|
||||
},
|
||||
|
||||
(HasOpcode(STX) & MatchX(1) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(5)) ~
|
||||
(HasOpcode(STA) & MatchA(0) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(4)) ~
|
||||
Where(ctx => {
|
||||
ctx.addObject(3, ZeroPage)
|
||||
(ctx.get[Constant](4) + 1).quickSimplify == ctx.get[Constant](5)
|
||||
}) ~
|
||||
(Linear & DoesNotConcernMemoryAt(3, 4) & DoesNotConcernMemoryAt(3, 5)).* ~
|
||||
Where(ctx => {
|
||||
val lo = ctx.get[Int](0) & 0xff
|
||||
val hi = ctx.get[Int](1) & 0xff
|
||||
ctx.addObject(2, hi * 256 + lo)
|
||||
true
|
||||
}) ~
|
||||
(Elidable & MatchParameter(4) & HasAddrModeIn(IndexedZ, IndexedY) & MatchAddrMode(9)) ~
|
||||
Where(ctx => {
|
||||
ctx.get[AddrMode.Value](9) == IndexedY || !ctx.compilationOptions.flag(CompilationFlag.Emit65CE02Opcodes)
|
||||
}) ~~> { (code, ctx) =>
|
||||
val addr = ctx.get[Int](2)
|
||||
val last = code.last
|
||||
code.init :+ last.copy(parameter = NumericConstant(addr, 2), addrMode = if (last.addrMode == IndexedZ) Absolute else AbsoluteY)
|
||||
},
|
||||
|
||||
(HasOpcode(LDA) & MatchImmediate(0)) ~
|
||||
(HasOpcode(LDX) & MatchImmediate(1)) ~
|
||||
(HasOpcode(STX) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(5)) ~
|
||||
(HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(4)) ~
|
||||
Where(ctx => {
|
||||
ctx.addObject(3, ZeroPage)
|
||||
(ctx.get[Constant](4) + 1).quickSimplify == ctx.get[Constant](5)
|
||||
}) ~
|
||||
(Linear & DoesNotConcernMemoryAt(3, 4) & DoesNotConcernMemoryAt(3, 5)).* ~
|
||||
Where(ctx => {
|
||||
val lo = ctx.get[Constant](0)
|
||||
val hi = ctx.get[Constant](1)
|
||||
ctx.addObject(2, (hi.asl(8) + lo).quickSimplify)
|
||||
true
|
||||
}) ~
|
||||
(Elidable & MatchParameter(4) & HasAddrModeIn(IndexedZ, IndexedY) & MatchAddrMode(9)) ~
|
||||
Where(ctx => {
|
||||
ctx.get[AddrMode.Value](9) == IndexedY || !ctx.compilationOptions.flag(CompilationFlag.Emit65CE02Opcodes)
|
||||
}) ~~> { (code, ctx) =>
|
||||
val addr = ctx.get[Constant](2)
|
||||
val last = code.last
|
||||
code.init :+ last.copy(parameter = addr, addrMode = if (last.addrMode == IndexedZ) Absolute else AbsoluteY)
|
||||
},
|
||||
|
||||
(HasOpcode(LDA) & MatchImmediate(0)) ~
|
||||
(HasOpcode(LDX) & MatchImmediate(1)) ~
|
||||
(HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(4)) ~
|
||||
(HasOpcode(STX) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(5)) ~
|
||||
Where(ctx => {
|
||||
ctx.addObject(3, ZeroPage)
|
||||
(ctx.get[Constant](4) + 1).quickSimplify == ctx.get[Constant](5)
|
||||
}) ~
|
||||
(Linear & DoesNotConcernMemoryAt(3, 4) & DoesNotConcernMemoryAt(3, 5)).* ~
|
||||
Where(ctx => {
|
||||
val lo = ctx.get[Constant](0)
|
||||
val hi = ctx.get[Constant](1)
|
||||
ctx.addObject(2, (hi.asl(8) + lo).quickSimplify)
|
||||
true
|
||||
}) ~
|
||||
(Elidable & MatchParameter(4) & HasAddrModeIn(IndexedZ, IndexedY) & MatchAddrMode(9)) ~
|
||||
Where(ctx => {
|
||||
ctx.get[AddrMode.Value](9) == IndexedY || !ctx.compilationOptions.flag(CompilationFlag.Emit65CE02Opcodes)
|
||||
}) ~~> { (code, ctx) =>
|
||||
val addr = ctx.get[Constant](2)
|
||||
val last = code.last
|
||||
code.init :+ last.copy(parameter = addr, addrMode = if (last.addrMode == IndexedZ) Absolute else AbsoluteY)
|
||||
},
|
||||
|
||||
(HasOpcode(LDA) & MatchImmediate(0)) ~
|
||||
(HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(4)) ~
|
||||
(HasOpcode(LDA) & MatchImmediate(1) & HasAddrModeIn(Absolute, ZeroPage)) ~
|
||||
(HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & MatchParameter(5)) ~
|
||||
Where(ctx => {
|
||||
ctx.addObject(3, ZeroPage)
|
||||
(ctx.get[Constant](4) + 1).quickSimplify == ctx.get[Constant](5)
|
||||
}) ~
|
||||
(Linear & DoesNotConcernMemoryAt(3, 4) & DoesNotConcernMemoryAt(3, 5)).* ~
|
||||
Where(ctx => {
|
||||
val lo = ctx.get[Constant](0)
|
||||
val hi = ctx.get[Constant](1)
|
||||
ctx.addObject(2, (hi.asl(8) + lo).quickSimplify)
|
||||
true
|
||||
}) ~
|
||||
(Elidable & MatchParameter(4) & HasAddrModeIn(IndexedZ, IndexedY) & MatchAddrMode(9)) ~
|
||||
Where(ctx => {
|
||||
ctx.get[AddrMode.Value](9) == IndexedY || !ctx.compilationOptions.flag(CompilationFlag.Emit65CE02Opcodes)
|
||||
}) ~~> { (code, ctx) =>
|
||||
val addr = ctx.get[Constant](2)
|
||||
val last = code.last
|
||||
code.init :+ last.copy(parameter = addr, addrMode = if (last.addrMode == IndexedZ) Absolute else AbsoluteY)
|
||||
},
|
||||
|
||||
)
|
||||
|
||||
val ReplacingArithmeticsWithBitOps = new RuleBasedAssemblyOptimization("Replacing arithmetics with bit ops",
|
||||
|
@ -237,7 +237,20 @@ object ZeropageRegisterOptimizations {
|
||||
AssemblyLine.zeropage(ctx.get[Opcode.Value](1), ctx.zreg(zregIndex)),
|
||||
AssemblyLine.implied(TSX)))
|
||||
}
|
||||
})
|
||||
}),
|
||||
MultipleAssemblyRules((0 to 1).map { zregIndex =>
|
||||
(Elidable & HasOpcode(PHA) & DoesntMatterWhatItDoesWithReg(zregIndex)) ~
|
||||
(Linear & Not(ConcernsS) & Not(RefersToOrUses("__reg", zregIndex))).*.capture(21) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersToOrUses("__reg", zregIndex)) ~
|
||||
(Elidable & HasOpcode(PLA)) ~
|
||||
(HasOpcodeIn(LDY, LDX, CLC, SEC, CLD, SED)).*.capture(22) ~
|
||||
(Elidable & HasOpcodeIn(ORA, EOR, ADC, AND) & HasAddrModeIn(Absolute, ZeroPage) & RefersToOrUses("__reg", zregIndex) & DoesntMatterWhatItDoesWithReg(zregIndex)) ~~> { (code, ctx) =>
|
||||
List(AssemblyLine.zeropage(STA, ctx.zreg(zregIndex)).pos(code.head.source)) ++
|
||||
ctx.get[List[AssemblyLine]](21) ++
|
||||
ctx.get[List[AssemblyLine]](22) ++
|
||||
List(code.last)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
val PointlessLoad = new RuleBasedAssemblyOptimization("Pointless load from zeropage register",
|
||||
@ -311,6 +324,53 @@ object ZeropageRegisterOptimizations {
|
||||
})
|
||||
)
|
||||
|
||||
private val simplifiableIndexingFiller: AssemblyPattern =
|
||||
(Elidable & HasOpcode(LDY) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.N, State.Z) | Linear & Not(ConcernsY) & Not(RefersToOrUses("__reg"))).*
|
||||
|
||||
private val finalIndexingOperation: AssemblyLinePattern =
|
||||
HasY(0) & HasAddrMode(IndexedY) & RefersToOrUses("__reg", 0) & DoesntMatterWhatItDoesWith(State.Y) & DoesntMatterWhatItDoesWithReg(0) & DoesntMatterWhatItDoesWithReg(1)
|
||||
|
||||
val SimplifiablePointerIndexing = new RuleBasedAssemblyOptimization("Simplifiable pointer indexing",
|
||||
needsFlowInfo = FlowInfoRequirement.BothFlows,
|
||||
|
||||
(Elidable & HasOpcode(ADC) & HasClear(State.D) & HasClear(State.C) & HasAddrModeIn(Absolute, ZeroPage, Immediate) & Not(RefersToOrUses("__reg"))) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 0)) ~
|
||||
(Elidable & HasOpcode(BCC) & MatchParameter(1)) ~
|
||||
(Elidable & HasOpcode(INC) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 1)) ~
|
||||
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & IsNotALabelUsedManyTimes & DoesntMatterWhatItDoesWith(State.A, State.V, State.C, State.N, State.Z)) ~
|
||||
(simplifiableIndexingFiller ~ finalIndexingOperation).capture(2) ~~> { (code, ctx) =>
|
||||
code(1) :: code.head.copy(opcode = LDY) :: ctx.get[List[AssemblyLine]](2).filter(l => l.opcode != LDY)
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(ADC) & HasClear(State.D) & HasClear(State.C) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 0)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 0)) ~
|
||||
(Elidable & HasOpcode(BCC) & MatchParameter(1)) ~
|
||||
(Elidable & HasOpcode(INC) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 1)) ~
|
||||
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & IsNotALabelUsedManyTimes & DoesntMatterWhatItDoesWith(State.A, State.V, State.C, State.N, State.Z)) ~
|
||||
(simplifiableIndexingFiller ~ finalIndexingOperation).capture(2) ~~> { (code, ctx) =>
|
||||
AssemblyLine.implied(TAY).pos(code.head.source) :: ctx.get[List[AssemblyLine]](2).filter(l => l.opcode != LDY)
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(ADC) & HasClear(State.D) & HasClear(State.C) & HasAddrModeIn(Absolute, ZeroPage, Immediate) & Not(RefersToOrUses("__reg"))) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 0)) ~
|
||||
(Elidable & HasOpcode(TXA)) ~
|
||||
(Elidable & HasOpcode(ADC) & HasImmediate(0)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWith(State.A, State.V, State.C, State.N, State.Z)) ~
|
||||
(simplifiableIndexingFiller ~ finalIndexingOperation).capture(2) ~~> { (code, ctx) =>
|
||||
code(1) :: code(4).copy(opcode = STX) :: code.head.copy(opcode = LDY) :: ctx.get[List[AssemblyLine]](2).filter(l => l.opcode != LDY)
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(ADC) & HasClear(State.D) & HasClear(State.C) & HasAddrModeIn(Absolute, ZeroPage, Immediate) & Not(RefersToOrUses("__reg"))) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 0)) ~
|
||||
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Absolute, ZeroPage, Immediate) & Not(RefersTo("__reg"))) ~
|
||||
(Elidable & HasOpcode(ADC) & HasImmediate(0)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWith(State.A, State.V, State.C, State.N, State.Z)) ~
|
||||
(simplifiableIndexingFiller ~ finalIndexingOperation).capture(2) ~~> { (code, ctx) =>
|
||||
code(1) :: code(2) :: code(4) :: code.head.copy(opcode = LDY) :: ctx.get[List[AssemblyLine]](2).filter(l => l.opcode != LDY)
|
||||
},
|
||||
|
||||
)
|
||||
|
||||
val SimplifiableAddingOfOneBit = new RuleBasedAssemblyOptimization("Simplifiable adding of one bit",
|
||||
needsFlowInfo = FlowInfoRequirement.BothFlows,
|
||||
(Elidable & HasOpcode(AND) & HasImmediate(1)) ~
|
||||
@ -347,6 +407,7 @@ object ZeropageRegisterOptimizations {
|
||||
DeadRegStoreFromFlow,
|
||||
PointlessLoad,
|
||||
SimplifiableAddingOfOneBit,
|
||||
SimplifiablePointerIndexing,
|
||||
StashInRegInsteadOfStack,
|
||||
)
|
||||
|
||||
|
8
src/main/scala/millfork/env/Constant.scala
vendored
8
src/main/scala/millfork/env/Constant.scala
vendored
@ -333,7 +333,13 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
|
||||
((l + b) - a).quickSimplify
|
||||
case (_, CompoundConstant(MathOperator.Plus, a, b)) if operator == MathOperator.Minus =>
|
||||
((l - a) - b).quickSimplify
|
||||
case (CompoundConstant(MathOperator.Shl, SubbyteConstant(c1, 1), NumericConstant(8, _)), SubbyteConstant(c2, 0)) if operator == MathOperator.Or && c1 == c2 => c1
|
||||
|
||||
case (CompoundConstant(MathOperator.Shl, SubbyteConstant(c1, 1), NumericConstant(8, _)), SubbyteConstant(c2, 0))
|
||||
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
|
||||
case (CompoundConstant(MathOperator.Times, SubbyteConstant(c1, 1), NumericConstant(256, _)), SubbyteConstant(c2, 0))
|
||||
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
|
||||
case (CompoundConstant(MathOperator.Times, NumericConstant(256, _), SubbyteConstant(c1, 1)), SubbyteConstant(c2, 0))
|
||||
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
|
||||
|
||||
case (_, CompoundConstant(MathOperator.DecimalMinus, a, b)) if operator == MathOperator.DecimalPlus =>
|
||||
CompoundConstant(MathOperator.DecimalMinus, CompoundConstant(MathOperator.DecimalPlus, l, a), b).quickSimplify
|
||||
|
Loading…
Reference in New Issue
Block a user