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

Optimization improvements and fixes

This commit is contained in:
Karol Stasiak 2018-05-14 02:20:36 +02:00
parent fae7bb31c9
commit a671ac1d06
4 changed files with 134 additions and 17 deletions

View File

@ -131,6 +131,7 @@ object OptimizationPresets {
LaterOptimizations.IncreaseWithLimit,
SingleAssignmentVariableOptimization,
LocalVariableReadOptimization,
LaterOptimizations.UseBit,
)
val Good: List[AssemblyOptimization] = List[AssemblyOptimization](

View File

@ -123,6 +123,10 @@ object AlwaysGoodOptimizations {
(Elidable & HasA(0xff) & HasOpcode(AND)) ~~> (code => code.map(_.copy(opcode = LDA))),
(Elidable & HasA(0) & HasOpcode(AND)) ~~> (code => List(AssemblyLine.immediate(LDA, 0))),
(Elidable & HasX(0) & HasOpcode(XAA)) ~~> (code => List(AssemblyLine.immediate(LDA, 0))),
(Elidable & HasImmediate(0) & HasOpcode(AND)) ~~> (code => List(AssemblyLine.immediate(LDA, 0))),
(Elidable & HasImmediate(0) & HasOpcode(XAA)) ~~> (code => List(AssemblyLine.immediate(LDA, 0))),
(Elidable & HasImmediate(0xff) & HasOpcode(ORA)) ~~> (code => List(AssemblyLine.immediate(LDA, 0xff))),
(Elidable & HasImmediate(0xff) & HasOpcode(EOR)) ~~> (code => List(AssemblyLine.immediate(LDA, 0xff))),
)
val MathOperationOnTwoIdenticalMemoryOperands = new RuleBasedAssemblyOptimization("Math operation on two identical memory operands",
@ -171,7 +175,7 @@ object AlwaysGoodOptimizations {
(Linear & DoesntChangeIndexingInAddrMode(0) & DoesntChangeIndexingInAddrMode(2) &
DoesNotConcernMemoryAt(0, 1) & DoesntChangeMemoryAt(2, 3)).* ~
(Elidable & HasOpcode(ld2) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(st2) & MatchAddrMode(2) & MatchParameter(3)) ~~> (code => code.init),
(Elidable & HasOpcode(st2) & MatchAddrMode(2) & MatchParameter(3)) ~~> (code => code.init)
}
private def pointlessImmediateStoreToTheSameVariable(match1: AssemblyLinePattern, st1: Opcode.Value, match2: AssemblyLinePattern, st2: Opcode.Value) = {
@ -806,12 +810,18 @@ object AlwaysGoodOptimizations {
HasOpcode(RTS) ~~> ((code, ctx) => ctx.get[List[AssemblyLine]](1) ++ (AssemblyLine.implied(RTS) :: code.tail)),
)
val PointlessRegisterTransfersBeforeCompare = new RuleBasedAssemblyOptimization("Pointless register transfers before compare",
val PointlessRegisterTransfersBeforeCompare = new RuleBasedAssemblyOptimization("Pointless register transfers and loads before compare",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
HasOpcodeIn(Set(DEX, INX, LDX, LAX)) ~
(HasOpcode(TXA) & Elidable & DoesntMatterWhatItDoesWith(State.A)) ~~> (code => code.init),
HasOpcodeIn(Set(DEY, INY, LDY)) ~
(HasOpcode(TYA) & Elidable & DoesntMatterWhatItDoesWith(State.A)) ~~> (code => code.init),
(HasOpcodeIn(Set(DEC, INC, ASL, ROL, ROR, LSR, SLO, SRE, RLA, RRA, ISC, DCP)) & MatchAddrMode(0) & MatchParameter(1)) ~
(HasOpcode(LDA) & Elidable & DoesntMatterWhatItDoesWith(State.A) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init),
(HasOpcodeIn(Set(DEC, INC, ASL, ROL, ROR, LSR, SLO, SRE, RLA, RRA, ISC, DCP)) & MatchAddrMode(0) & MatchParameter(1)) ~
(HasOpcode(LDX) & Elidable & DoesntMatterWhatItDoesWith(State.X) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init),
(HasOpcodeIn(Set(DEC, INC, ASL, ROL, ROR, LSR, SLO, SRE, RLA, RRA, ISC, DCP)) & MatchAddrMode(0) & MatchParameter(1)) ~
(HasOpcode(LDY) & Elidable & DoesntMatterWhatItDoesWith(State.Y) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init),
)
private def stashing(tai: Opcode.Value, tia: Opcode.Value, readsI: AssemblyLinePattern, concernsI: AssemblyLinePattern, discardIF: Opcode.Value, withRts: Boolean, withBeq: Boolean) = {
@ -983,6 +993,12 @@ object AlwaysGoodOptimizations {
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(HasOpcode(LABEL) & MatchParameter(2)) ~
(Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(Set(LDA, STA)) & MatchAddrMode(0) & MatchParameter(1)) ~
(HasOpcodeIn(ShortBranching) & MatchParameter(3)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(HasOpcode(LABEL) & MatchParameter(3) & HasCallerCount(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
)
val RearrangableLoadFromTheSameLocation = new RuleBasedAssemblyOptimization("Rearrangable load from the same location",
@ -1031,6 +1047,9 @@ object AlwaysGoodOptimizations {
(Elidable & HasOpcodeIn(Set(CLC, SEC)) & DoesntMatterWhatItDoesWith(State.C)) ~~> (_ => Nil),
(Elidable & HasOpcodeIn(Set(CLD, SED)) & DoesntMatterWhatItDoesWith(State.D)) ~~> (_ => Nil),
(Elidable & HasOpcodeIn(Set(CLV)) & DoesntMatterWhatItDoesWith(State.V)) ~~> (_ => Nil),
(Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_ => Nil),
(Elidable & HasOpcode(AND) & HasImmediate(0xff) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_ => Nil),
(Elidable & HasOpcode(ANC) & HasImmediate(0xff) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C)) ~~> (_ => Nil),
)
val SimplifiableStackOperation = new RuleBasedAssemblyOptimization("Simplifiable stack operation",

View File

@ -460,7 +460,46 @@ object LaterOptimizations {
code.tail.init ++ List(AssemblyLine.implied(DEX), code.last.copy(addrMode = IndexedX))
},
(Elidable & HasOpcode(LDY) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsY)).* ~
(Elidable & HasAddrMode(IndexedY) & MatchX(1) & DoesntMatterWhatItDoesWith(State.Y)) ~~> { (code, ctx)=>
val lastLine = code.last
code.tail.init ++ List(lastLine.copy(addrMode = IndexedX, parameter = lastLine.parameter - ctx.get[Int](1)))
},
(Elidable & HasOpcode(LDY) & HasImmediate(0) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsY)).*.capture(2) ~
(Elidable & HasAddrMode(IndexedY) & DoesntMatterWhatItDoesWith(State.Y, State.X)).capture(0) ~
Linear.*.capture(3) ~
(Elidable & HasOpcode(LDX) & MatchImmediate(1) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~~> { (code, ctx) =>
val mainLine = ctx.get[List[AssemblyLine]](0).head
ctx.get[List[AssemblyLine]](2) ++ List(
code.last,
mainLine.copy(addrMode = IndexedX, parameter = mainLine.parameter - ctx.get[Int](1))) ++
ctx.get[List[AssemblyLine]](3)
},
)
val UseBit = new RuleBasedAssemblyOptimization("Using BIT instruction",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Set(Absolute, ZeroPage))) ~
(Elidable & HasOpcode(AND) & HasImmediate(0x40)) ~
(Elidable & HasOpcode(BNE) & DoesntMatterWhatItDoesWith(State.A, State.V, State.Z, State.N)) ~~> (code => List(
code.head.copy(opcode = BIT),
code.last.copy(opcode = BVS)
)),
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Set(Absolute, ZeroPage))) ~
(Elidable & HasOpcode(AND) & HasImmediate(0x40)) ~
(Elidable & HasOpcode(BEQ) & DoesntMatterWhatItDoesWith(State.A, State.V, State.Z, State.N)) ~~> (code => List(
code.head.copy(opcode = BIT),
code.last.copy(opcode = BVC)
)),
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Set(Absolute, ZeroPage))) ~
(Elidable & HasOpcodeIn(Set(BMI, BPL)) & DoesntMatterWhatItDoesWith(State.A, State.V, State.Z, State.N)) ~~> (code => List(
code.head.copy(opcode = BIT),
code.last
)),
)
val All = List(
@ -471,6 +510,7 @@ object LaterOptimizations {
PointlessLoadAfterStore,
PointessLoadingForShifting,
LoadingAfterShifting,
UseBit,
UseXInsteadOfStack,
UseYInsteadOfStack,
UseZeropageAddressingMode)

View File

@ -178,7 +178,7 @@ object UndocumentedOptimizations {
)
private def extraRmw(legal: Opcode.Value, illegal: Opcode.Value) =
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Set(IndexedY, AbsoluteY, IndexedY)) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LDA) & HasAddrModeIn(Set(IndexedX, IndexedY, AbsoluteY, IndexedY)) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(legal) & HasAddrMode(Implied)) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.A, State.N, State.Z, State.C, State.V)) ~~> { (code, ctx) =>
code.head.copy(opcode = illegal) :: Nil
@ -213,17 +213,30 @@ object UndocumentedOptimizations {
trivialSequence2(ASL, ORA, Not(ConcernsC), SLO),
trivialCommutativeSequence(ASL, ORA, SLO),
extraRmw(ASL, SLO),
(Elidable & HasOpcode(ASL) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(ASL) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory)).* ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
code.tail.init ++ List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SLO, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(2) ~
(Elidable & HasOpcode(ASL) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA) & Not(ReadsC) & Not(ReadsNOrZ)).*.capture(3) ~
(Elidable & HasOpcode(ASL) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SLO, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA) & Not(ChangesC)).*.capture(2) ~
(Elidable & HasOpcode(ASL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SRE, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SLO, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
ctx.get[List[AssemblyLine]](3)
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA)).*.capture(2) ~
(Elidable & HasOpcode(ASL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SLO, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
ctx.get[List[AssemblyLine]](3)
},
@ -240,15 +253,28 @@ object UndocumentedOptimizations {
trivialSequence2(LSR, EOR, Not(ConcernsC), SRE),
trivialCommutativeSequence(LSR, EOR, SRE),
extraRmw(LSR, SRE),
(Elidable & HasOpcode(LSR) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LSR) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory)).* ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
code.tail.init ++ List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SRE, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(2) ~
(Elidable & HasOpcode(LSR) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA) & Not(ReadsC) & Not(ReadsNOrZ)).*.capture(3) ~
(Elidable & HasOpcode(LSR) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SRE, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA) & Not(ChangesC)).*.capture(2) ~
(Elidable & HasOpcode(LSR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SRE, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
ctx.get[List[AssemblyLine]](3)
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA)).*.capture(2) ~
(Elidable & HasOpcode(LSR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0), AssemblyLine(SRE, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
@ -262,14 +288,41 @@ object UndocumentedOptimizations {
trivialSequence2(ROL, AND, Not(ConcernsC), RLA),
trivialCommutativeSequence(ROL, AND, RLA),
extraRmw(ROL, RLA),
(Elidable & HasOpcode(ROL) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory)).* ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
code.tail.init ++ List(AssemblyLine.immediate(LDA, 0xff), AssemblyLine(RLA, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(ROL) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (code, ctx) =>
List(AssemblyLine.immediate(LDA, 0xff), AssemblyLine(RLA, ctx.get[AddrMode.Value](0), ctx.get[Constant](1)))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA) & Not(ConcernsC)).*.capture(2) ~
(Elidable & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0xff), AssemblyLine(RLA, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
ctx.get[List[AssemblyLine]](3)
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ConcernsA) & Not(ConcernsC)).*.capture(2) ~
(Elidable & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.Z, State.N)) ~
(Linear & Not(ConcernsMemory) & Not(ChangesA)).*.capture(3) ~
(Elidable & HasOpcode(STA) & MatchAddrMode(0) & MatchParameter(1)) ~~> { (_, ctx) =>
List(AssemblyLine.immediate(LDA, 0xff), AssemblyLine(RLA, ctx.get[AddrMode.Value](0), ctx.get[Constant](1))) ++
ctx.get[List[AssemblyLine]](2) ++
ctx.get[List[AssemblyLine]](3)
},
)
val UseRra = new RuleBasedAssemblyOptimization("Using undocumented instruction RRA",
needsFlowInfo = FlowInfoRequirement.BothFlows,
// TODO: is it ok? carry flag and stuff?
trivialSequence1(ROR, ADC, Not(ConcernsC), RRA),
trivialSequence2(ROR, ADC, Not(ConcernsC), RRA),
trivialCommutativeSequence(ROR, ADC, RRA),
// trivialSequence1(ROR, ADC, Not(ConcernsC), RRA),
// trivialSequence2(ROR, ADC, Not(ConcernsC), RRA),
// trivialCommutativeSequence(ROR, ADC, RRA),
extraRmw(ROR, RRA),
)
@ -293,6 +346,10 @@ object UndocumentedOptimizations {
(Elidable & HasOpcode(CMP) & MatchAddrMode(2) & MatchParameter(3) & DoesntMatterWhatItDoesWith(State.C, State.N, State.A)) ~~> { code =>
List(code(2).copy(opcode = LDA), code(1).copy(opcode = DCP))
},
(Elidable & HasOpcode(DEC) & Not(HasAddrMode(Immediate)) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(LDA) & Not(HasAddrMode(Immediate)) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.C, State.N, State.A)) ~~> { code =>
List(AssemblyLine.immediate(LDA, 0), code(1).copy(opcode = DCP))
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & HasAddrModeIn(Set(ZeroPage, Absolute))) ~
(Elidable & HasOpcode(BNE) & MatchParameter(2)) ~
(Elidable & HasOpcode(DEC) & MatchAddrMode(30) & MatchParameter(31) & DoesntChangeMemoryAt(0, 1)) ~