mirror of
https://github.com/KarolS/millfork.git
synced 2025-04-18 22:41:02 +00:00
Various 6502 optimization fixes
This commit is contained in:
parent
1bc1ab3539
commit
e9cfec54b5
@ -1,10 +1,11 @@
|
||||
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.env.NormalFunction
|
||||
import millfork.error.Logger
|
||||
|
||||
import scala.annotation.tailrec
|
||||
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 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 =>
|
||||
OpcodeClasses.ReadsXAlways(l.opcode) ||
|
||||
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
||||
OpcodeClasses.ChangesX(l.opcode) ||
|
||||
OpcodeClasses.ChangesY(l.opcode) ||
|
||||
Set(AbsoluteX, AbsoluteY, ZeroPageY, ZeroPageX, IndexedX, IndexedY, LongIndexedY, IndexedSY)(l.addrMode)
|
||||
addressingModesUsingX(l.addrMode)
|
||||
)
|
||||
val usesY = code.exists(l =>
|
||||
OpcodeClasses.ReadsXAlways(l.opcode) ||
|
||||
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
||||
OpcodeClasses.ChangesX(l.opcode) ||
|
||||
val usesY = code.exists(l => {
|
||||
OpcodeClasses.ReadsYAlways(l.opcode) ||
|
||||
OpcodeClasses.ChangesY(l.opcode) ||
|
||||
Set(AbsoluteX, AbsoluteY, ZeroPageY, ZeroPageX, IndexedX, IndexedY, LongIndexedY, IndexedSY)(l.addrMode)
|
||||
addressingModesUsingY(l.addrMode)
|
||||
}
|
||||
)
|
||||
if (!usesX && !usesY) {
|
||||
return code
|
||||
@ -101,21 +102,25 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||
}
|
||||
|
||||
//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(LDY | STY, AbsoluteX | ZeroPageX, _) :: xs => false
|
||||
case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs => false
|
||||
|
||||
case AssemblyLine0(_, AbsoluteY, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, ZeroPageY, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, LongIndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, IndexedSY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, AbsoluteX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, LongAbsoluteX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, ZeroPageX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y || loaded != Some(X) => false
|
||||
case AssemblyLine0(_, AbsoluteY, _) :: xs if notY => false
|
||||
case AssemblyLine0(_, ZeroPageY, _) :: xs if notY => false
|
||||
case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || notY => false
|
||||
case AssemblyLine0(_, LongIndexedY, _) :: xs if dir == Y2X || notY => false
|
||||
case AssemblyLine0(_, IndexedSY, _) :: xs if dir == Y2X || notY => false
|
||||
case AssemblyLine0(_, AbsoluteX, _) :: xs if notX => false
|
||||
case AssemblyLine0(_, LongAbsoluteX, _) :: xs if notX => false
|
||||
case AssemblyLine0(_, ZeroPageX, _) :: xs if notX => false
|
||||
case AssemblyLine0(_, IndexedX | ImmediateWithAbsoluteX | ImmediateWithZeroPageX, _) :: xs if dir == X2Y || notX => false
|
||||
case AssemblyLine0(_, AbsoluteIndexedX, _) :: xs if dir == X2Y => 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))
|
||||
@ -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))
|
||||
|
||||
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 Nil => true
|
||||
}
|
||||
}
|
||||
|
||||
private def switchX2Y(code: List[AssemblyLine])(implicit log: Logger): TailRec[List[AssemblyLine]] = code match {
|
||||
|
@ -145,8 +145,8 @@ object LaterOptimizations {
|
||||
//noinspection ZeroIndexToHead
|
||||
private def InterleavedLoads(load: Opcode.Value, store: Opcode.Value) = {
|
||||
(Elidable & HasOpcode(load) & MatchAddrMode(0) & MatchParameter(1)).capture(12) ~
|
||||
(Elidable & HasOpcode(store)).+.capture(10) ~
|
||||
(Elidable & HasOpcode(load) & MatchAddrMode(2) & MatchParameter(3) & DoesNotConcernMemoryAt(0, 1)).capture(13) ~
|
||||
(Elidable & HasOpcode(store) & MatchAddrMode(20) & MatchParameter(21)).+.capture(10) ~
|
||||
(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(load) & MatchAddrMode(0) & MatchParameter(1)) ~
|
||||
WhereNoMemoryAccessOverlapBetweenTwoLineLists(10, 11) ~~> { (_, ctx) =>
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.error.ConsoleLogger
|
||||
import millfork.node.NiceFunctionProperty
|
||||
@ -12,10 +12,10 @@ object VariableLifetime {
|
||||
|
||||
// This only works for non-stack variables.
|
||||
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 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)
|
||||
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 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 OneRegister(MEM_HL | MEM_IX_D | MEM_IY_D | MEM_BC | MEM_DE) => true
|
||||
case OneRegister(_) => false
|
||||
case _ => false
|
||||
}
|
||||
case CHANGED_MEM => true
|
||||
case POP | PUSH => false
|
||||
|
@ -565,7 +565,7 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
} else if (de != "") {
|
||||
tailcall(inlineVars(hl, bc, de, xs)).map(ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) :: _)
|
||||
} else {
|
||||
throw new IllegalStateException()
|
||||
tailcall(inlineVars(hl, bc, de, xs)).map(x :: _)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user