All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.scalanative.optimizer.pass.BasicBlocksFusion.scala Maven / Gradle / Ivy

The newest version!
package scala.scalanative
package optimizer
package pass

import analysis.ControlFlow
import analysis.ControlFlow.Block

import nir._
import Inst._
import scala.collection.mutable

class BasicBlocksFusion extends Pass {
  import BasicBlocksFusion._

  override def onInsts(insts: Seq[Inst]) = {
    val cfg = ControlFlow.Graph(insts)

    fuseBlocks(insts, cfg)
  }

  private def fuseBlocks(insts: Seq[Inst], cfg: ControlFlow.Graph): Seq[Inst] = {
    val workList = mutable.Stack.empty[Block]
    val visited  = mutable.Set.empty[Block]
    var result   = Seq.empty[Inst]

    workList.push(cfg.entry)
    while (workList.nonEmpty) {
      val block = workList.pop()

      if (!visited(block)) {
        visited += block

        val (addedCode, addedWork) = fusedBlockCode(block, cfg.entry)

        result ++= addedCode
        workList.pushAll(addedWork)
      }
    }

    result
  }

  /* This produces the fused block code, starting from the given block.
   * It also returns what are the next blocks, because fused blocks can't be
   * re-processed (it would create multiple definitions for the same variable)
   */
  private def fusedBlockCode(block: Block,
                             entryBlock: Block): (Seq[Inst], Seq[Block]) = {
    val (blockCode, blockCf) = (block.insts.dropRight(1), block.insts.last)

    val (codeEnding, succWork) = blockCf match {
      // We only fuse if we have a Jump instruction
      // All other cases should reduce to a Jump after CfChainsSimplification
      case Jump(Next.Label(_, args))
          if (block.succ.size == 1 && block.succ.head.pred.size == 1 && block.succ.head.name != entryBlock.name) =>
        val nextBlock          = block.succ.head
        val (recCode, recWork) = fusedBlockCode(nextBlock, entryBlock)
        val params             = nextBlock.params.map(_.name)

        // Replace the parameters of the fused block with the supplied arguments
        val paramDef = params.zip(args).map {
          case (param, arg) =>
            Let(param, Op.Copy(arg))
        }

        // need to drop the first instruction of recCode, as it is the block label
        (paramDef ++ recCode.tail, recWork)

      // Any other case can't be fused
      case _ => (Seq(blockCf), block.succ)
    }

    // Rebuild the code from the label, followed by the code of the block,
    // and then the ending (either fusion or normal Cf)
    ((block.label +: blockCode) ++ codeEnding, succWork)
  }

}

object BasicBlocksFusion extends PassCompanion {
  def apply(config: tools.Config, top: analysis.ClassHierarchy.Top) =
    new BasicBlocksFusion
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy