millfork/src/main/scala/millfork/assembly/opt/SuperOptimizer.scala

76 lines
2.6 KiB
Scala

package millfork.assembly.opt
import millfork.{CompilationFlag, CompilationOptions, OptimizationPresets}
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
import millfork.env.NormalFunction
import millfork.error.ErrorReporting
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
object SuperOptimizer extends AssemblyOptimization {
def optimize(m: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
val oldVerbosity = ErrorReporting.verbosity
ErrorReporting.verbosity = -1
var allOptimizers = OptimizationPresets.Good ++ LaterOptimizations.All
if (options.flag(CompilationFlag.EmitIllegals)) {
allOptimizers ++= UndocumentedOptimizations.All
}
if (options.flag(CompilationFlag.EmitCmosOpcodes)) {
allOptimizers ++= CmosOptimizations.All
}
allOptimizers ++= List(
VariableToRegisterOptimization,
ChangeIndexRegisterOptimizationPreferringX2Y,
ChangeIndexRegisterOptimizationPreferringY2X,
UnusedLabelRemoval)
val seenSoFar = mutable.Set[CodeView]()
val queue = mutable.Queue[(List[AssemblyOptimization], List[AssemblyLine])]()
val leaves = mutable.ListBuffer[(List[AssemblyOptimization], List[AssemblyLine])]()
seenSoFar += viewCode(code)
queue.enqueue(Nil -> code)
while(queue.nonEmpty) {
val (optsSoFar, codeSoFar) = queue.dequeue()
var isLeaf = true
allOptimizers.par.foreach { o =>
val optimized = o.optimize(m, codeSoFar, options)
val view = viewCode(optimized)
seenSoFar.synchronized{
if (!seenSoFar(view)) {
isLeaf = false
seenSoFar += view
queue.enqueue((o :: optsSoFar) -> optimized)
}
}
}
if (isLeaf) {
// println(codeSoFar.map(_.sizeInBytes).sum + " B: " + optsSoFar.reverse.map(_.name).mkString(" -> "))
leaves += optsSoFar -> codeSoFar
}
}
val result = leaves.minBy(_._2.map(_.cost).sum)
ErrorReporting.verbosity = oldVerbosity
ErrorReporting.debug(s"Visited ${leaves.size} leaves")
ErrorReporting.debug(s"${code.map(_.sizeInBytes).sum} B -> ${result._2.map(_.sizeInBytes).sum} B: ${result._1.reverse.map(_.name).mkString(" -> ")}")
result._1.reverse.foldLeft(code){(c, opt) =>
val n = opt.optimize(m, c, options)
// println(c.mkString("","",""))
// println(n.mkString("","",""))
n
}
result._2
}
override val name = "Superoptimizer"
def viewCode(code: List[AssemblyLine]): CodeView = {
CodeView(code.map(l => l.opcode -> l.addrMode))
}
}
case class CodeView(content: List[(Opcode.Value, AddrMode.Value)])