1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-10-03 20:55:36 +00:00

6502: optimize variable pointers

This commit is contained in:
Karol Stasiak 2019-06-14 15:19:29 +02:00
parent 2a233930e8
commit ffff51dee9
3 changed files with 164 additions and 2 deletions

View File

@ -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",

View File

@ -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,
)

View File

@ -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