mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-11 12:29:46 +00:00
Z80: Improve optimizations
This commit is contained in:
parent
72f8806c54
commit
7fe32ca564
@ -36,7 +36,7 @@ object AlwaysGoodI80Optimizations {
|
|||||||
List(ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L, ZRegister.MEM_HL).map(f))
|
List(ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L, ZRegister.MEM_HL).map(f))
|
||||||
|
|
||||||
val UsingKnownValueFromAnotherRegister = new RuleBasedAssemblyOptimization("Using known value from another register",
|
val UsingKnownValueFromAnotherRegister = new RuleBasedAssemblyOptimization("Using known value from another register",
|
||||||
needsFlowInfo = FlowInfoRequirement.ForwardFlow,
|
needsFlowInfo = FlowInfoRequirement.BothFlows,
|
||||||
for7Registers(register =>
|
for7Registers(register =>
|
||||||
(Elidable & IsRegular8BitLoadFrom(register) & MatchRegister(register, 0)) ~~> ((code, ctx) =>
|
(Elidable & IsRegular8BitLoadFrom(register) & MatchRegister(register, 0)) ~~> ((code, ctx) =>
|
||||||
code.map(x => x.copy(
|
code.map(x => x.copy(
|
||||||
@ -71,6 +71,23 @@ object AlwaysGoodI80Optimizations {
|
|||||||
registers = OneRegister(ZRegister.IMM_8)
|
registers = OneRegister(ZRegister.IMM_8)
|
||||||
))
|
))
|
||||||
),
|
),
|
||||||
|
|
||||||
|
MultipleAssemblyRules(for {
|
||||||
|
(useful, useless, both, extractUseful) <- Seq[(ZRegister.Value, ZRegister.Value, ZRegister.Value, Constant => Constant)](
|
||||||
|
(B, C, BC, _.hiByte),
|
||||||
|
(C, B, BC, _.loByte),
|
||||||
|
(D, E, DE, _.hiByte),
|
||||||
|
(E, D, DE, _.loByte),
|
||||||
|
(H, L, HL, _.hiByte),
|
||||||
|
(L, H, HL, _.loByte)
|
||||||
|
)
|
||||||
|
} yield {
|
||||||
|
(Elidable & HasOpcode(LD_16) & HasRegisters(TwoRegisters(both, IMM_16)) & MatchParameter(0)) ~
|
||||||
|
(Linear & Not(Concerns(useful)) & Not(Concerns(useless))).* ~
|
||||||
|
(Elidable & HasOpcodeIn(Set(ADD, ADC, SUB, SBC, XOR, OR, AND, CP)) & HasRegisterParam(useful) & DoesntMatterWhatItDoesWith(useless)) ~~> { (code, ctx) =>
|
||||||
|
code.tail.init :+ code.last.copy(registers = OneRegister(IMM_8), parameter = extractUseful(ctx.get[Constant](0)))
|
||||||
|
}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
val ReloadingKnownValueFromMemory = new RuleBasedAssemblyOptimization("Reloading known value from memory",
|
val ReloadingKnownValueFromMemory = new RuleBasedAssemblyOptimization("Reloading known value from memory",
|
||||||
@ -296,6 +313,13 @@ object AlwaysGoodI80Optimizations {
|
|||||||
(HasOpcode(LD) & MatchSourceRealRegister(0) & MatchTargetRealRegister(1)) ~
|
(HasOpcode(LD) & MatchSourceRealRegister(0) & MatchTargetRealRegister(1)) ~
|
||||||
(Linear & Not(ChangesMatchedRegister(0)) & Not(ChangesMatchedRegister(1))).* ~
|
(Linear & Not(ChangesMatchedRegister(0)) & Not(ChangesMatchedRegister(1))).* ~
|
||||||
(Elidable & HasOpcode(LD) & MatchSourceRealRegister(1) & MatchTargetRealRegister(0)) ~~> (_.init),
|
(Elidable & HasOpcode(LD) & MatchSourceRealRegister(1) & MatchTargetRealRegister(0)) ~~> (_.init),
|
||||||
|
|
||||||
|
// 68
|
||||||
|
(Elidable & HasOpcode(LD) & Match8BitImmediate(1) & MatchTargetRegisterAndOffset(2)) ~
|
||||||
|
Where(ctx => ctx.get[RegisterAndOffset](2).isOneOfSeven) ~
|
||||||
|
(Elidable & HasOpcode(LD) & MatchSourceRegisterAndOffset(2) & MatchTargetRealRegister(3) & DoesntMatterWhatItDoesWithMatchedRegisterOffset(2)) ~~> {(code, ctx) =>
|
||||||
|
List(code.head.copy(registers = TwoRegisters(ctx.get[ZRegister.Value](3), IMM_8)))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing",
|
val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing",
|
||||||
|
@ -259,6 +259,10 @@ object CoarseFlowAnalyzer {
|
|||||||
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt))
|
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt))
|
||||||
case ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), xx) =>
|
case ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), xx) =>
|
||||||
currentStatus = currentStatus.setHL(SingleStatus(xx))
|
currentStatus = currentStatus.setHL(SingleStatus(xx))
|
||||||
|
case ZLine0(LD_16, TwoRegisters(ZRegister.DE, ZRegister.IMM_16), xx) if xx.isProvablyDivisibleBy256 =>
|
||||||
|
currentStatus = currentStatus.copy(d = AnyStatus, e = Status.SingleZero)
|
||||||
|
case ZLine0(LD_16, TwoRegisters(ZRegister.BC, ZRegister.IMM_16), xx) if xx.isProvablyDivisibleBy256 =>
|
||||||
|
currentStatus = currentStatus.copy(b = AnyStatus, c = Status.SingleZero)
|
||||||
case ZLine0(LD, TwoRegisters(ZRegister.A, ZRegister.I | ZRegister.R), _) =>
|
case ZLine0(LD, TwoRegisters(ZRegister.A, ZRegister.I | ZRegister.R), _) =>
|
||||||
currentStatus = currentStatus.copy(a = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus, nf = AnyStatus)
|
currentStatus = currentStatus.copy(a = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus, nf = AnyStatus)
|
||||||
case ZLine0(LD, TwoRegisters(t, ZRegister.IMM_8), NumericConstant(value, _)) =>
|
case ZLine0(LD, TwoRegisters(t, ZRegister.IMM_8), NumericConstant(value, _)) =>
|
||||||
|
@ -145,8 +145,8 @@ case class CpuImportance(a: Importance = UnknownImportance,
|
|||||||
case ZRegister.E => this.copy(e = Unimportant)
|
case ZRegister.E => this.copy(e = Unimportant)
|
||||||
case ZRegister.DE => this.copy(d = Unimportant, e = Unimportant)
|
case ZRegister.DE => this.copy(d = Unimportant, e = Unimportant)
|
||||||
case ZRegister.MEM_DE => this.copy(d = Important, e = Important)
|
case ZRegister.MEM_DE => this.copy(d = Important, e = Important)
|
||||||
case ZRegister.H => this.copy(h = Unimportant)
|
case ZRegister.H => this.copy(h = Unimportant, hlNumeric = this.l)
|
||||||
case ZRegister.L => this.copy(l = Unimportant)
|
case ZRegister.L => this.copy(l = Unimportant, hlNumeric = this.h)
|
||||||
case ZRegister.HL => this.copy(h = Unimportant, l = Unimportant, hlNumeric = Unimportant)
|
case ZRegister.HL => this.copy(h = Unimportant, l = Unimportant, hlNumeric = Unimportant)
|
||||||
case ZRegister.MEM_HL => this.copy(h = Important, l = Important)
|
case ZRegister.MEM_HL => this.copy(h = Important, l = Important)
|
||||||
case ZRegister.IXH => this.copy(ixh = Unimportant)
|
case ZRegister.IXH => this.copy(ixh = Unimportant)
|
||||||
@ -469,7 +469,7 @@ object ReverseFlowAnalyzer {
|
|||||||
currentImportance = currentImportance.copy(cf = Unimportant, hf = Unimportant, nf = Unimportant)
|
currentImportance = currentImportance.copy(cf = Unimportant, hf = Unimportant, nf = Unimportant)
|
||||||
|
|
||||||
case ZLine0(LD_HLSP, _, _) =>
|
case ZLine0(LD_HLSP, _, _) =>
|
||||||
currentImportance = currentImportance.copy(h = Unimportant, l = Unimportant)
|
currentImportance = currentImportance.copy(h = Unimportant, l = Unimportant, hlNumeric = Unimportant)
|
||||||
|
|
||||||
case ZLine0(RIM, _, _) =>
|
case ZLine0(RIM, _, _) =>
|
||||||
currentImportance = currentImportance.copy(a = Unimportant)
|
currentImportance = currentImportance.copy(a = Unimportant)
|
||||||
|
@ -559,12 +559,18 @@ case class MatchImmediate(i: Int) extends AssemblyLinePattern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class RegisterAndOffset(register: ZRegister.Value, offset: Int) {
|
case class RegisterAndOffset(register: ZRegister.Value, offset: Int) {
|
||||||
|
|
||||||
def toOneRegister: ZRegisters = register match {
|
def toOneRegister: ZRegisters = register match {
|
||||||
case ZRegister.MEM_IX_D | ZRegister.MEM_IY_D => OneRegisterOffset(register, offset)
|
case ZRegister.MEM_IX_D | ZRegister.MEM_IY_D => OneRegisterOffset(register, offset)
|
||||||
case _ =>
|
case _ =>
|
||||||
if (offset != 0) ???
|
if (offset != 0) ???
|
||||||
OneRegister(register)
|
OneRegister(register)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isOneOfSeven: Boolean = register match {
|
||||||
|
case ZRegister.A | ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.H | ZRegister.L => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class MatchSourceRegisterAndOffset(i: Int) extends AssemblyLinePattern {
|
case class MatchSourceRegisterAndOffset(i: Int) extends AssemblyLinePattern {
|
||||||
@ -745,6 +751,21 @@ case class DoesntMatterWhatItDoesWith(registers: ZRegister.Value*) extends Assem
|
|||||||
override def hitRate: Double = 0.058
|
override def hitRate: Double = 0.058
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class DoesntMatterWhatItDoesWithMatchedRegisterOffset(i: Int) extends AssemblyLinePattern {
|
||||||
|
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
|
||||||
|
FlowInfoRequirement.assertBackward(needsFlowInfo)
|
||||||
|
|
||||||
|
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean = {
|
||||||
|
val ro = ctx.get[RegisterAndOffset](i)
|
||||||
|
ro.isOneOfSeven && flowInfo.importanceAfter.getRegister(ro.register) != Important
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override def toString: String = "[¯\\_(ツ)_/¯:" + i + "]"
|
||||||
|
|
||||||
|
override def hitRate: Double = 0.058
|
||||||
|
}
|
||||||
|
|
||||||
case object DoesntMatterWhatItDoesWithFlags extends AssemblyLinePattern {
|
case object DoesntMatterWhatItDoesWithFlags extends AssemblyLinePattern {
|
||||||
|
|
||||||
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
|
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
|
||||||
|
@ -18,7 +18,10 @@ class VariableStatus(val paramVariables: Set[String],
|
|||||||
val localVariables: List[Variable],
|
val localVariables: List[Variable],
|
||||||
val variablesWithLifetimes: List[(Variable, Range)],
|
val variablesWithLifetimes: List[(Variable, Range)],
|
||||||
val variablesWithLifetimesMap: Map[String, Range],
|
val variablesWithLifetimesMap: Map[String, Range],
|
||||||
val codeWithFlow: List[(FlowInfo, ZLine)])
|
val codeWithFlow: List[(FlowInfo, ZLine)]) {
|
||||||
|
|
||||||
|
override def toString = s"VariableStatus(paramVariables=$paramVariables, stillUsedVariables=$stillUsedVariables, variablesWithAddressesTaken=$variablesWithAddressesTaken, localVariables=$localVariables, variablesWithLifetimesMap=$variablesWithLifetimesMap)"
|
||||||
|
}
|
||||||
|
|
||||||
object VariableStatus {
|
object VariableStatus {
|
||||||
def apply(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext, typFilter: Type => Boolean): Option[VariableStatus] = {
|
def apply(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext, typFilter: Type => Boolean): Option[VariableStatus] = {
|
||||||
@ -49,20 +52,26 @@ object VariableStatus {
|
|||||||
case _ => None
|
case _ => None
|
||||||
}.toSet
|
}.toSet
|
||||||
val variablesWithAddressesTaken = code.zipWithIndex.flatMap {
|
val variablesWithAddressesTaken = code.zipWithIndex.flatMap {
|
||||||
case (ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)), _) =>
|
case (l@ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)), _) =>
|
||||||
|
// println(th.name -> l)
|
||||||
Some(th.name)
|
Some(th.name)
|
||||||
case (ZLine0(_, _, SubbyteConstant(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _)), _) =>
|
case (l@ZLine0(_, _, SubbyteConstant(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _)), _) =>
|
||||||
|
// println(th.name -> l)
|
||||||
Some(th.name)
|
Some(th.name)
|
||||||
case (ZLine0(_,
|
case (l@ZLine0(_,
|
||||||
TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL),
|
TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL),
|
||||||
_), i) =>
|
_), i) =>
|
||||||
flow(i)._1.statusBefore.hl match {
|
flow(i)._1.statusBefore.hl match {
|
||||||
case SingleStatus(MemoryAddressConstant(th)) =>
|
case SingleStatus(MemoryAddressConstant(th)) =>
|
||||||
if (flow(i)._1.importanceAfter.hlNumeric != Unimportant) Some(th.name)
|
if (flow(i)._1.importanceAfter.hlNumeric != Unimportant) {
|
||||||
else None
|
// println(th.name -> l)
|
||||||
|
Some(th.name)
|
||||||
|
}else None
|
||||||
case SingleStatus(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) =>
|
case SingleStatus(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) =>
|
||||||
if (flow(i)._1.importanceAfter.hlNumeric != Unimportant) Some(th.name)
|
if (flow(i)._1.importanceAfter.hlNumeric != Unimportant) {
|
||||||
else None
|
// println(th.name -> l)
|
||||||
|
Some(th.name)
|
||||||
|
} else None
|
||||||
case _ => None // TODO: ???
|
case _ => None // TODO: ???
|
||||||
}
|
}
|
||||||
case _ => None
|
case _ => None
|
||||||
|
@ -2,7 +2,7 @@ package millfork.assembly.z80.opt
|
|||||||
|
|
||||||
import millfork.{CompilationFlag, NonOverlappingIntervals}
|
import millfork.{CompilationFlag, NonOverlappingIntervals}
|
||||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||||
import millfork.assembly.z80.{TwoRegisters, ZFlag, ZLine, ZLine0}
|
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZFlag, ZLine, ZLine0}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ConsoleLogger
|
import millfork.error.ConsoleLogger
|
||||||
import millfork.node.ZRegister
|
import millfork.node.ZRegister
|
||||||
@ -263,6 +263,22 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
|||||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||||
canBeInlined(vname, synced = true, target, xs).map(add(target == BC, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
canBeInlined(vname, synced = true, target, xs).map(add(target == BC, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||||
|
|
||||||
|
case (_, ZLine(OR, OneRegister(A), _, Elidability.Elidable, _)) ::
|
||||||
|
(f, ZLine(SBC_16, TwoRegisters(HL, BC | DE), _, Elidability.Elidable, _)) :: xs if target == HL =>
|
||||||
|
val i = f.importanceAfter
|
||||||
|
if (i.h == Unimportant &&
|
||||||
|
i.l == Unimportant &&
|
||||||
|
i.a == Unimportant &&
|
||||||
|
i.hf == Unimportant &&
|
||||||
|
i.nf == Unimportant &&
|
||||||
|
i.pf == Unimportant &&
|
||||||
|
i.sf == Unimportant &&
|
||||||
|
i.zf == Unimportant) {
|
||||||
|
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(3, -1)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
case (_, x) :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, t), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs
|
case (_, x) :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, t), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs
|
||||||
if th.name == vname && t == target && x.changesRegister(t) =>
|
if th.name == vname && t == target && x.changesRegister(t) =>
|
||||||
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(16, 3)))
|
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(16, 3)))
|
||||||
@ -300,6 +316,24 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
|||||||
// if (code.nonEmpty) println(code.head)
|
// if (code.nonEmpty) println(code.head)
|
||||||
code match {
|
code match {
|
||||||
|
|
||||||
|
case (_, ZLine(OR, OneRegister(A), _, _, _)) ::
|
||||||
|
(_, l@ZLine(SBC_16, TwoRegisters(HL, BC), _, _, _)) ::
|
||||||
|
xs if hl != "" =>
|
||||||
|
tailcall(inlineVars(hl, bc, de, xs)).map(
|
||||||
|
ZLine.ld8(A, L).pos(l.source) ::
|
||||||
|
ZLine.register(SUB, C).pos(l.source) ::
|
||||||
|
ZLine.ld8(A, H).pos(l.source) ::
|
||||||
|
ZLine.register(SBC, B).pos(l.source) :: _)
|
||||||
|
|
||||||
|
case (_, ZLine(OR, OneRegister(A), _, _, _)) ::
|
||||||
|
(_, l@ZLine(SBC_16, TwoRegisters(HL, DE), _, _, _)) ::
|
||||||
|
xs if hl != "" =>
|
||||||
|
tailcall(inlineVars(hl, bc, de, xs)).map(
|
||||||
|
ZLine.ld8(A, L).pos(l.source) ::
|
||||||
|
ZLine.register(SUB, E).pos(l.source) ::
|
||||||
|
ZLine.ld8(A, H).pos(l.source) ::
|
||||||
|
ZLine.register(SBC, D).pos(l.source) :: _)
|
||||||
|
|
||||||
case (_, load@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _, s1)) ::
|
case (_, load@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _, s1)) ::
|
||||||
(f, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _, s2)) ::
|
(f, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _, s2)) ::
|
||||||
xs if bc != "" =>
|
xs if bc != "" =>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user