mirror of
https://github.com/KarolS/millfork.git
synced 2024-05-31 18:41:30 +00:00
Various 6502 optimization fixes
This commit is contained in:
parent
1bc1ab3539
commit
e9cfec54b5
|
@ -1,10 +1,11 @@
|
||||||
package millfork.assembly.mos.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
import millfork.assembly.mos.{AddrMode, AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||||
import millfork.env.NormalFunction
|
import millfork.env.NormalFunction
|
||||||
import millfork.error.Logger
|
import millfork.error.Logger
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
import scala.util.control.TailCalls.{TailRec, done, tailcall}
|
import scala.util.control.TailCalls.{TailRec, done, tailcall}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,19 +36,19 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||||
override def name = "Changing index registers"
|
override def name = "Changing index registers"
|
||||||
|
|
||||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||||
|
|
||||||
|
val addressingModesUsingX = Set(AbsoluteX, ZeroPageX, IndexedX)
|
||||||
|
val addressingModesUsingY = Set(AbsoluteY, ZeroPageY, IndexedY, LongIndexedY, IndexedSY)
|
||||||
val usesX = code.exists(l =>
|
val usesX = code.exists(l =>
|
||||||
OpcodeClasses.ReadsXAlways(l.opcode) ||
|
OpcodeClasses.ReadsXAlways(l.opcode) ||
|
||||||
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
|
||||||
OpcodeClasses.ChangesX(l.opcode) ||
|
OpcodeClasses.ChangesX(l.opcode) ||
|
||||||
OpcodeClasses.ChangesY(l.opcode) ||
|
addressingModesUsingX(l.addrMode)
|
||||||
Set(AbsoluteX, AbsoluteY, ZeroPageY, ZeroPageX, IndexedX, IndexedY, LongIndexedY, IndexedSY)(l.addrMode)
|
|
||||||
)
|
)
|
||||||
val usesY = code.exists(l =>
|
val usesY = code.exists(l => {
|
||||||
OpcodeClasses.ReadsXAlways(l.opcode) ||
|
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
||||||
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
|
||||||
OpcodeClasses.ChangesX(l.opcode) ||
|
|
||||||
OpcodeClasses.ChangesY(l.opcode) ||
|
OpcodeClasses.ChangesY(l.opcode) ||
|
||||||
Set(AbsoluteX, AbsoluteY, ZeroPageY, ZeroPageX, IndexedX, IndexedY, LongIndexedY, IndexedSY)(l.addrMode)
|
addressingModesUsingY(l.addrMode)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
if (!usesX && !usesY) {
|
if (!usesX && !usesY) {
|
||||||
return code
|
return code
|
||||||
|
@ -101,21 +102,25 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection OptionEqualsSome
|
//noinspection OptionEqualsSome
|
||||||
private def canOptimize(code: List[AssemblyLine], dir: IndexDirection, loaded: Option[IndexReg]): Boolean = code match {
|
@tailrec
|
||||||
|
private def canOptimize(code: List[AssemblyLine], dir: IndexDirection, loaded: Option[IndexReg]): Boolean = {
|
||||||
|
val notX = loaded != Some(X)
|
||||||
|
val notY = loaded != Some(Y)
|
||||||
|
code match {
|
||||||
|
|
||||||
case AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | BIT, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => false
|
case AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | BIT, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => false
|
||||||
case AssemblyLine0(LDY | STY, AbsoluteX | ZeroPageX, _) :: xs => false
|
case AssemblyLine0(LDY | STY, AbsoluteX | ZeroPageX, _) :: xs => false
|
||||||
case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs => false
|
case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs => false
|
||||||
|
|
||||||
case AssemblyLine0(_, AbsoluteY, _) :: xs if loaded != Some(Y) => false
|
case AssemblyLine0(_, AbsoluteY, _) :: xs if notY => false
|
||||||
case AssemblyLine0(_, ZeroPageY, _) :: xs if loaded != Some(Y) => false
|
case AssemblyLine0(_, ZeroPageY, _) :: xs if notY => false
|
||||||
case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || notY => false
|
||||||
case AssemblyLine0(_, LongIndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
case AssemblyLine0(_, LongIndexedY, _) :: xs if dir == Y2X || notY => false
|
||||||
case AssemblyLine0(_, IndexedSY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
case AssemblyLine0(_, IndexedSY, _) :: xs if dir == Y2X || notY => false
|
||||||
case AssemblyLine0(_, AbsoluteX, _) :: xs if loaded != Some(X) => false
|
case AssemblyLine0(_, AbsoluteX, _) :: xs if notX => false
|
||||||
case AssemblyLine0(_, LongAbsoluteX, _) :: xs if loaded != Some(X) => false
|
case AssemblyLine0(_, LongAbsoluteX, _) :: xs if notX => false
|
||||||
case AssemblyLine0(_, ZeroPageX, _) :: xs if loaded != Some(X) => false
|
case AssemblyLine0(_, ZeroPageX, _) :: xs if notX => false
|
||||||
case AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y || loaded != Some(X) => false
|
case AssemblyLine0(_, IndexedX | ImmediateWithAbsoluteX | ImmediateWithZeroPageX, _) :: xs if dir == X2Y || notX => false
|
||||||
case AssemblyLine0(_, AbsoluteIndexedX, _) :: xs if dir == X2Y => false
|
case AssemblyLine0(_, AbsoluteIndexedX, _) :: xs if dir == X2Y => false
|
||||||
case AssemblyLine0(SHX | SHY | AHX | TAS | LAS, _, _) :: xs => false
|
case AssemblyLine0(SHX | SHY | AHX | TAS | LAS, _, _) :: xs => false
|
||||||
case AssemblyLine(TXY, _, _, e, _) :: xs => (e == Elidability.Elidable || e == Elidability.Volatile) && loaded == Some(X) && canOptimize(xs, dir, Some(Y))
|
case AssemblyLine(TXY, _, _, e, _) :: xs => (e == Elidability.Elidable || e == Elidability.Volatile) && loaded == Some(X) && canOptimize(xs, dir, Some(Y))
|
||||||
|
@ -155,11 +160,12 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||||
(e == Elidability.Elidable || e == Elidability.Volatile || dir == X2Y) && loaded == Some(Y) && canOptimize(xs, dir, Some(Y))
|
(e == Elidability.Elidable || e == Elidability.Volatile || dir == X2Y) && loaded == Some(Y) && canOptimize(xs, dir, Some(Y))
|
||||||
|
|
||||||
case AssemblyLine0(SAX | TXS | SBX, _, _) :: xs => dir == Y2X && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
case AssemblyLine0(SAX | TXS | SBX, _, _) :: xs => dir == Y2X && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
||||||
case AssemblyLine0(TSX, _, _) :: xs => dir == Y2X && loaded != Some(Y) && canOptimize(xs, dir, Some(X))
|
case AssemblyLine0(TSX, _, _) :: xs => dir == Y2X && notY && canOptimize(xs, dir, Some(X))
|
||||||
|
|
||||||
case _ :: xs => canOptimize(xs, dir, loaded)
|
case _ :: xs => canOptimize(xs, dir, loaded)
|
||||||
|
|
||||||
case Nil => true
|
case Nil => true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def switchX2Y(code: List[AssemblyLine])(implicit log: Logger): TailRec[List[AssemblyLine]] = code match {
|
private def switchX2Y(code: List[AssemblyLine])(implicit log: Logger): TailRec[List[AssemblyLine]] = code match {
|
||||||
|
|
|
@ -145,8 +145,8 @@ object LaterOptimizations {
|
||||||
//noinspection ZeroIndexToHead
|
//noinspection ZeroIndexToHead
|
||||||
private def InterleavedLoads(load: Opcode.Value, store: Opcode.Value) = {
|
private def InterleavedLoads(load: Opcode.Value, store: Opcode.Value) = {
|
||||||
(Elidable & HasOpcode(load) & MatchAddrMode(0) & MatchParameter(1)).capture(12) ~
|
(Elidable & HasOpcode(load) & MatchAddrMode(0) & MatchParameter(1)).capture(12) ~
|
||||||
(Elidable & HasOpcode(store)).+.capture(10) ~
|
(Elidable & HasOpcode(store) & MatchAddrMode(20) & MatchParameter(21)).+.capture(10) ~
|
||||||
(Elidable & HasOpcode(load) & MatchAddrMode(2) & MatchParameter(3) & DoesNotConcernMemoryAt(0, 1)).capture(13) ~
|
(Elidable & HasOpcode(load) & MatchAddrMode(2) & MatchParameter(3) & DoesNotConcernMemoryAt(0, 1) & DoesNotConcernMemoryAt(20, 21)).capture(13) ~
|
||||||
(Elidable & HasOpcode(store) & DoesNotConcernMemoryAt(0, 1) & DoesNotConcernMemoryAt(2, 3)).+.capture(11) ~
|
(Elidable & HasOpcode(store) & DoesNotConcernMemoryAt(0, 1) & DoesNotConcernMemoryAt(2, 3)).+.capture(11) ~
|
||||||
(Elidable & HasOpcode(load) & MatchAddrMode(0) & MatchParameter(1)) ~
|
(Elidable & HasOpcode(load) & MatchAddrMode(0) & MatchParameter(1)) ~
|
||||||
WhereNoMemoryAccessOverlapBetweenTwoLineLists(10, 11) ~~> { (_, ctx) =>
|
WhereNoMemoryAccessOverlapBetweenTwoLineLists(10, 11) ~~> { (_, ctx) =>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package millfork.assembly.mos.opt
|
package millfork.assembly.mos.opt
|
||||||
|
|
||||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses, State}
|
import millfork.assembly.mos.{AddrMode, AssemblyLine, AssemblyLine0, OpcodeClasses, State}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ConsoleLogger
|
import millfork.error.ConsoleLogger
|
||||||
import millfork.node.NiceFunctionProperty
|
import millfork.node.NiceFunctionProperty
|
||||||
|
@ -12,10 +12,10 @@ object VariableLifetime {
|
||||||
|
|
||||||
// This only works for non-stack variables.
|
// This only works for non-stack variables.
|
||||||
def apply(variableName: String, code: List[AssemblyLine], expandToIncludeIndexing: Boolean = false, expandToIncludeUsesOfLoadedIndices: Option[Set[(NiceFunctionProperty, String)]] = None): Range = {
|
def apply(variableName: String, code: List[AssemblyLine], expandToIncludeIndexing: Boolean = false, expandToIncludeUsesOfLoadedIndices: Option[Set[(NiceFunctionProperty, String)]] = None): Range = {
|
||||||
val flags = code.map(_.parameter match {
|
val flags = code.map(line => line.parameter match {
|
||||||
case MemoryAddressConstant(MemoryVariable(n, _, _)) if n == variableName => true
|
case MemoryAddressConstant(MemoryVariable(n, _, _)) if n == variableName => true
|
||||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)) if n == variableName => true
|
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)) if n == variableName => true
|
||||||
case _ => false
|
case p => line.addrMode == AddrMode.IndexedX && p.refersTo(variableName)
|
||||||
})
|
})
|
||||||
if (flags.forall(!_)) return Range(0, 0)
|
if (flags.forall(!_)) return Range(0, 0)
|
||||||
var min = flags.indexOf(true)
|
var min = flags.indexOf(true)
|
||||||
|
|
|
@ -245,11 +245,11 @@ object HelperCheckers {
|
||||||
case LD | LD_16 | ADD_16 | ADC_16 | SBC_16 => l.registers match {
|
case LD | LD_16 | ADD_16 | ADC_16 | SBC_16 => l.registers match {
|
||||||
case TwoRegisters(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE, _) => true
|
case TwoRegisters(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE, _) => true
|
||||||
case TwoRegisters(_, MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true
|
case TwoRegisters(_, MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true
|
||||||
case TwoRegisters(_, _) => false
|
case _ => false
|
||||||
}
|
}
|
||||||
case ADD | SUB | SBC | ADC | XOR | CP | OR | AND => l.registers match {
|
case ADD | SUB | SBC | ADC | XOR | CP | OR | AND => l.registers match {
|
||||||
case OneRegister(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true
|
case OneRegister(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true
|
||||||
case OneRegister(_) => false
|
case _ => false
|
||||||
}
|
}
|
||||||
case CHANGED_MEM => true
|
case CHANGED_MEM => true
|
||||||
case POP | PUSH => false
|
case POP | PUSH => false
|
||||||
|
|
|
@ -565,7 +565,7 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||||
} else if (de != "") {
|
} else if (de != "") {
|
||||||
tailcall(inlineVars(hl, bc, de, xs)).map(ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) :: _)
|
tailcall(inlineVars(hl, bc, de, xs)).map(ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) :: _)
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException()
|
tailcall(inlineVars(hl, bc, de, xs)).map(x :: _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user