mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-10 11:54:30 +00:00
6502: More optimizations.
This commit is contained in:
parent
87c5d698bc
commit
86ce1d42f3
@ -158,6 +158,7 @@ object OptimizationPresets {
|
||||
AlwaysGoodOptimizations.PointlessStackStore,
|
||||
AlwaysGoodOptimizations.SimplifiableStackOperation,
|
||||
LaterOptimizations.UseBit,
|
||||
LaterOptimizations.ReplaceableLoad,
|
||||
)
|
||||
|
||||
val Good: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](
|
||||
|
@ -2067,6 +2067,18 @@ object AlwaysGoodOptimizations {
|
||||
(Elidable & (HasOpcode(TYA) & DoesntMatterWhatItDoesWith(State.A) | HasOpcode(CPY) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.C, State.V))) ~~> { code =>
|
||||
code.tail.init :+ code.head
|
||||
},
|
||||
(Elidable & HasOpcodeIn(DEX, INX) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
(Not(ConcernsX)).*.capture(1) ~
|
||||
Where(ctx => ctx.isExternallyLinearBlock(1)) ~
|
||||
(Elidable & (HasOpcode(TXA) & DoesntMatterWhatItDoesWith(State.A) | HasOpcode(CPX) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.C, State.V))) ~~> { code =>
|
||||
code.tail.init :+ code.head
|
||||
},
|
||||
(Elidable & HasOpcodeIn(DEY, INY) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
(Not(ConcernsY)).*.capture(1) ~
|
||||
Where(ctx => ctx.isExternallyLinearBlock(1)) ~
|
||||
(Elidable & (HasOpcode(TYA) & DoesntMatterWhatItDoesWith(State.A) | HasOpcode(CPY) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.C, State.V))) ~~> { code =>
|
||||
code.tail.init :+ code.head
|
||||
},
|
||||
(Elidable & HasAddrMode(Implied) & HasOpcodeIn(DEC, INC) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
(Linear & Not(ConcernsA)).* ~
|
||||
(Elidable & (
|
||||
|
@ -503,6 +503,48 @@ object LaterOptimizations {
|
||||
)),
|
||||
)
|
||||
|
||||
val ReplaceableLoad = new RuleBasedAssemblyOptimization("Replaceable load",
|
||||
needsFlowInfo = FlowInfoRequirement.BothFlows,
|
||||
(Elidable & HasOpcode(LDA) & MatchImmediate(1) & MatchA(0) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcode(LDX) & MatchImmediate(1) & MatchX(0) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcode(LDY) & MatchImmediate(1) & MatchY(0) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcode(LDA) & MatchImmediate(1) & MatchX(0)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => List(AssemblyLine.implied(TXA))),
|
||||
(Elidable & HasOpcode(LDA) & MatchImmediate(1) & MatchY(0)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => List(AssemblyLine.implied(TYA))),
|
||||
(Elidable & HasOpcode(LDX) & MatchImmediate(1) & MatchA(0)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => List(AssemblyLine.implied(TAX))),
|
||||
(Elidable & HasOpcode(LDY) & MatchImmediate(1) & MatchA(0)) ~
|
||||
Where(ctx => ctx.get[Constant](1).quickSimplify.isLowestByteAlwaysEqual(ctx.get[Int](0))) ~~> (_ => List(AssemblyLine.implied(TAY))),
|
||||
|
||||
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Absolute, ZeroPage, Immediate)) ~
|
||||
(Elidable & HasOpcode(TAX)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & DoesntMatterWhatItDoesWith(State.A)) ~~>{ code =>
|
||||
List(code.head.copy(opcode = LDX), code.last.copy(opcode = STX))
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Absolute, ZeroPage, Immediate)) ~
|
||||
(Elidable & HasOpcode(TAY)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & DoesntMatterWhatItDoesWith(State.A)) ~~>{ code =>
|
||||
List(code.head.copy(opcode = LDY), code.last.copy(opcode = STY))
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(LDX) & HasAddrModeIn(Absolute, ZeroPage, Immediate)) ~
|
||||
(Elidable & HasOpcode(TXA)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & DoesntMatterWhatItDoesWith(State.A)) ~~>{ code =>
|
||||
List(code.head, code.last.copy(opcode = STX))
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(LDY) & HasAddrModeIn(Absolute, ZeroPage, Immediate)) ~
|
||||
(Elidable & HasOpcode(TYA)) ~
|
||||
(Elidable & HasOpcode(STA) & HasAddrModeIn(Absolute, ZeroPage) & DoesntMatterWhatItDoesWith(State.A)) ~~>{ code =>
|
||||
List(code.head, code.last.copy(opcode = STY))
|
||||
},
|
||||
)
|
||||
|
||||
val All = List(
|
||||
DoubleLoadToDifferentRegisters,
|
||||
DoubleLoadToTheSameRegister,
|
||||
@ -510,6 +552,7 @@ object LaterOptimizations {
|
||||
LoadingBranchesOptimization,
|
||||
PointlessLoadAfterStore,
|
||||
PointessLoadingForShifting,
|
||||
ReplaceableLoad,
|
||||
LoadingAfterShifting,
|
||||
UseBit,
|
||||
UseXInsteadOfStack,
|
||||
|
@ -52,7 +52,13 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
case Nil => Nil
|
||||
case head :: tail =>
|
||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
||||
val ctx = new AssemblyMatchingContext(optimizationContext.options, optimizationContext.labelMap, optimizationContext.zreg, optimizationContext.niceFunctionProperties)
|
||||
val ctx = new AssemblyMatchingContext(
|
||||
optimizationContext.options,
|
||||
optimizationContext.labelMap,
|
||||
optimizationContext.zreg,
|
||||
optimizationContext.niceFunctionProperties,
|
||||
head._1.labelUseCount(_)
|
||||
)
|
||||
rule.pattern.matchTo(ctx, code) match {
|
||||
case Some(rest: List[(FlowInfo, AssemblyLine)]) =>
|
||||
val matchedChunkToOptimize: List[AssemblyLine] = code.take(code.length - rest.length).map(_._2)
|
||||
@ -85,7 +91,8 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||
val labelMap: Map[String, Int],
|
||||
val zeropageRegister: Option[ThingInMemory],
|
||||
val niceFunctionProperties: Set[(NiceFunctionProperty, String)]) {
|
||||
val niceFunctionProperties: Set[(NiceFunctionProperty, String)],
|
||||
val labeUseCount: String => Int) {
|
||||
@inline
|
||||
def log: Logger = compilationOptions.log
|
||||
@inline
|
||||
@ -202,8 +209,7 @@ class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||
}
|
||||
// if a jump leads inside the block, then it's internal
|
||||
// if a jump leads outside the block, then it's external
|
||||
jumps --= labels
|
||||
jumps.isEmpty
|
||||
jumps == labels && labels.forall(l => labeUseCount(l) <= 1)
|
||||
}
|
||||
|
||||
def zreg(i: Int): Constant = {
|
||||
|
Loading…
Reference in New Issue
Block a user