1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

6502: More optimizations.

This commit is contained in:
Karol Stasiak 2018-08-06 19:19:13 +02:00
parent 87c5d698bc
commit 86ce1d42f3
4 changed files with 66 additions and 4 deletions

View File

@ -158,6 +158,7 @@ object OptimizationPresets {
AlwaysGoodOptimizations.PointlessStackStore,
AlwaysGoodOptimizations.SimplifiableStackOperation,
LaterOptimizations.UseBit,
LaterOptimizations.ReplaceableLoad,
)
val Good: List[AssemblyOptimization[AssemblyLine]] = List[AssemblyOptimization[AssemblyLine]](

View File

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

View File

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

View File

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