1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00
millfork/src/main/scala/millfork/assembly/z80/opt/EmptyMemoryStoreRemoval.scala
2023-01-27 18:13:21 +01:00

70 lines
2.9 KiB
Scala

package millfork.assembly.z80.opt
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine}
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
import millfork.env._
import millfork.error.ConsoleLogger
import millfork.node.ZRegister
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
object EmptyMemoryStoreRemoval extends AssemblyOptimization[ZLine] {
override def name = "Removing pointless stores to automatic variables"
override def minimumRequiredLines: Int = 2
override def optimize(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[ZLine] = {
val vs = VariableStatus(f, code, optimizationContext, _ => true, allowParams = true).getOrElse(return code)
if (vs.localVariables.isEmpty) {
return code
}
import ZRegister._
val toRemove = mutable.Set[Int]()
val badVariables = mutable.Set[String]()
for((v, lifetime) <- vs.variablesWithLifetimes if lifetime.nonEmpty) {
val firstaccess = lifetime.head
val lastaccess = lifetime.last
if (firstaccess >= 0 && lastaccess >= 0) {
val firstVariableAccess = code(firstaccess)
val lastVariableAccess = code(lastaccess)
import millfork.assembly.z80.ZOpcode._
// TODO: this might be buggy; needs more testing.
if ((firstVariableAccess match {
case ZLine(LD, TwoRegisters(MEM_HL, _), _, Elidability.Elidable, _) => true
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), _, Elidability.Elidable, _) => true
case _ => false
}) && (lastVariableAccess match {
case ZLine(LD, TwoRegisters(MEM_HL, _), _, Elidability.Elidable, _) => true
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), _, Elidability.Elidable, _) => true
case ZLine(INC | DEC, OneRegister(MEM_HL), _, Elidability.Elidable, _) =>
val importances = vs.codeWithFlow(lastaccess)._1.importanceAfter
Seq(importances.sf, importances.zf).forall(_ == Unimportant)
case ZLine(SLA | SLL | SRA | SRL | RL | RR | RLC | RRC, OneRegister(MEM_HL), _, Elidability.Elidable, _) =>
val importances = vs.codeWithFlow(lastaccess)._1.importanceAfter
Seq(importances.sf, importances.zf, importances.cf).forall(_ == Unimportant)
case _ => false
})) {
badVariables += v.name
toRemove += lastaccess
}
}
}
if (toRemove.isEmpty) {
code
} else {
optimizationContext.log.debug(s"Removing pointless store(s) to automatic variables ${badVariables.mkString(", ")}")
// val range = toRemove.min to toRemove.max
// range.map{ i =>
// if (toRemove(i)) f"${code(i)}%-42s <-- REMOVE"
// else code(i).toString
// }.foreach(println)
code.zipWithIndex.filter(x => !toRemove(x._2)).map(_._1)
}
}
}