Run RemoveValidIf pass for updated CIRCT

This commit is contained in:
abejgonzalez
2023-02-05 21:44:51 -08:00
parent 06db605902
commit df3232f7d9
10 changed files with 59 additions and 423 deletions

View File

@@ -1,71 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl.Mappers._
import firrtl._
import firrtl.annotations.{CircuitTarget, ModuleTarget, SingleTargetAnnotation}
import firrtl.ir._
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
case class KeepNameAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] {
def duplicate(n: ModuleTarget) = this.copy(n)
}
case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String)
extends SingleTargetAnnotation[CircuitTarget] {
def duplicate(n: CircuitTarget) = this.copy(target = n)
}
class AddSuffixToModuleNames extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.LowForm
override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized
override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters
override def invalidates(a: Transform): Boolean = false
def determineRenamerandAnnos(state: CircuitState): (AnnotationSeq, (String) => String) = {
// remove determine suffix annotation
val newAnnos = state.annotations.filterNot(_.isInstanceOf[ModuleNameSuffixAnnotation])
val suffixes = state.annotations.collect({ case ModuleNameSuffixAnnotation(_, suffix) => suffix })
require(suffixes.length <= 1)
val suffix = suffixes.headOption.getOrElse("")
// skip renaming ExtModules and top-level module
val excludeSet = state.circuit.modules.flatMap {
case e: ExtModule => Some(e.name)
case m if (m.name == state.circuit.main) => Some(m.name)
case _ => None
}.toSet
val renamer = { (name: String) => if (excludeSet(name)) name else name + suffix }
(newAnnos, renamer)
}
def renameInstanceModules(renamer: (String) => String)(stmt: Statement): Statement = {
stmt match {
case m: DefInstance => new DefInstance(m.info, m.name, renamer(m.module))
case s => s.map(renameInstanceModules(renamer)) // if is statement, recurse
}
}
def run(state: CircuitState, renamer: (String) => String): (Circuit, RenameMap) = {
val myRenames = RenameMap()
val c = state.circuit
val modulesx = c.modules.map {
case m if (renamer(m.name) != m.name) =>
myRenames.record(ModuleTarget(c.main, m.name), ModuleTarget(c.main, renamer(m.name)))
m.map(renamer).map(renameInstanceModules(renamer))
case m => m.map(renameInstanceModules(renamer))
}
(Circuit(c.info, modulesx, c.main), myRenames)
}
def execute(state: CircuitState): CircuitState = {
val (newAnnos, renamer) = determineRenamerandAnnos(state)
val (ret, renames) = run(state, renamer)
state.copy(circuit = ret, annotations = newAnnos, renames = Some(renames))
}
}

View File

@@ -1,32 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl._
import firrtl.annotations.NoTargetAnnotation
import firrtl.ir._
import firrtl.options.Dependency
import firrtl.passes.memlib.ReplSeqMem
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
case class LinkExtModulesAnnotation(mustLink: Seq[ExtModule]) extends NoTargetAnnotation
class AvoidExtModuleCollisions extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.HighForm
override def optionalPrerequisites: Seq[TransformDependency] = Seq(Dependency[RemoveUnusedModules])
override def optionalPrerequisiteOf: Seq[TransformDependency] = {
Forms.HighEmitters :+ Dependency[ReplSeqMem]
}
override def invalidates(a: Transform): Boolean = false
def execute(state: CircuitState): CircuitState = {
val mustLink = state.annotations.flatMap {
case LinkExtModulesAnnotation(mustLink) => mustLink
case _ => Nil
}
val newAnnos = state.annotations.filterNot(_.isInstanceOf[LinkExtModulesAnnotation])
state.copy(circuit = state.circuit.copy(modules = state.circuit.modules ++ mustLink), annotations = newAnnos)
}
}

View File

@@ -1,62 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl._
import firrtl.annotations.{ModuleTarget, ReferenceTarget, SingleTargetAnnotation}
import firrtl.ir._
import firrtl.options.Dependency
import firrtl.passes.memlib.ReplSeqMem
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
case class ConvertToExtModAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] {
def duplicate(n: ModuleTarget) = this.copy(n)
}
// Converts some modules to external modules, based on a given function. If
// that function returns "true" then the module is converted into an ExtModule,
// otherwise it's left alone.
class ConvertToExtMod extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.HighForm
override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty
override def optionalPrerequisiteOf: Seq[TransformDependency] = {
Forms.HighEmitters ++ Seq(Dependency[RemoveUnusedModules], Dependency[ReplSeqMem])
}
override def invalidates(a: Transform): Boolean = false
def run(state: CircuitState, makeExt: Set[String]): (Circuit, RenameMap) = {
val renames = RenameMap()
val c = state.circuit
renames.setCircuit(c.main)
val modulesx = c.modules.map {
case m: ExtModule => m
case m: Module =>
val removing = collection.mutable.HashSet[String]()
def findDeadNames(statement: Statement): Unit = {
statement match {
case hn: IsDeclaration => removing += hn.name
case x => x.foreachStmt(findDeadNames)
}
}
if (makeExt(m.name)) {
m.foreachStmt(findDeadNames)
removing.foreach { name =>
renames.record(ReferenceTarget(c.main, m.name, Nil, name, Nil), Nil)
}
new ExtModule(m.info, m.name, m.ports, m.name, Seq.empty)
} else {
m
}
}
(Circuit(c.info, modulesx, c.main), renames)
}
def execute(state: CircuitState): CircuitState = {
val makeExt = state.annotations.collect({ case ConvertToExtModAnnotation(tgt) => tgt.module }).toSet
val newAnnos = state.annotations.filterNot(_.isInstanceOf[ConvertToExtModAnnotation])
val (ret, renames) = run(state, makeExt)
state.copy(circuit = ret, annotations = newAnnos, renames = Some(renames))
}
}

View File

@@ -1,40 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl._
import firrtl.ir._
import firrtl.passes.Pass
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass {
def run(c: Circuit): Circuit = {
val modulesx = c.modules.map {
case m: ExtModule => m
case m: Module => {
enumerate(m)
m
}
}
Circuit(c.info, modulesx, c.main)
}
}
class EnumerateModules(enumerate: (Module) => Unit)
extends Transform
with SeqTransformBased
with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.LowForm
override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized
override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters
override def invalidates(a: Transform): Boolean = false
def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate))
def execute(state: CircuitState): CircuitState = {
runTransforms(state)
}
}

View File

@@ -0,0 +1,26 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl.Mappers._
import firrtl._
import firrtl.annotations.{CircuitTarget, ModuleTarget, SingleTargetAnnotation}
import firrtl.ir._
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
import firrtl.options.{Dependency}
class ExtraLowTransforms extends Transform with DependencyAPIMigration {
// this PropagatePresetAnnotations is needed to run the RemoveValidIf pass (that is removed from CIRCT).
// additionally, since that pass isn't explicitly a prereq of the LowFormEmitter it
// needs to wrapped in this xform
override def prerequisites: Seq[TransformDependency] = Forms.LowForm :+
Dependency[firrtl.transforms.PropagatePresetAnnotations]
override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized
override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters
override def invalidates(a: Transform): Boolean = false
def execute(state: CircuitState): CircuitState = {
state
}
}

View File

@@ -5,9 +5,7 @@ import firrtl._
import firrtl.annotations._
import firrtl.ir._
import firrtl.options.{Dependency, InputAnnotationFileAnnotation, StageMain}
import firrtl.passes.memlib.ReplSeqMemAnnotation
import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage, OutputFileAnnotation, RunFirrtlTransformAnnotation}
import firrtl.transforms.BlackBoxResourceFileNameAnno
import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage, RunFirrtlTransformAnnotation}
import logger.LazyLogging
private class GenerateModelStageMain(annotations: AnnotationSeq) extends LazyLogging {
@@ -38,15 +36,23 @@ private class GenerateModelStageMain(annotations: AnnotationSeq) extends LazyLog
}
def executeStageMain(): Unit = {
val annos = new FirrtlStage().execute(Array.empty, annotations)
val appendedAnnotations = annotations.filter(_ match {
case CompilerNameAnnotation(_) => true
case _ => false
}).map(_ match {
case CompilerNameAnnotation("low") => Some(RunFirrtlTransformAnnotation(Dependency[ExtraLowTransforms]))
case _ => None
}).flatten
val annos = new FirrtlStage().execute(Array.empty, annotations ++ appendedAnnotations)
annos.collectFirst { case FirrtlCircuitAnnotation(circuit) => circuit } match {
case Some(circuit) =>
dumpAnnos(annos)
case _ =>
throw new Exception(s"executeTop failed while executing FIRRTL!\n")
throw new Exception(s"executeStageMain failed while executing FIRRTL!\n")
}
}
}
// main run class
object GenerateModelStageMain extends StageMain(new TapeoutStage())

View File

@@ -1,76 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl._
import firrtl.annotations._
import firrtl.options.Dependency
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
import firrtl.annotations.TargetToken.{Instance, OfModule}
case class ReParentCircuitAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] {
def duplicate(n: ModuleTarget) = this.copy(n)
}
class ReParentCircuit extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.HighForm
override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty
override def optionalPrerequisiteOf: Seq[TransformDependency] = {
Forms.HighEmitters :+ Dependency[RemoveUnusedModules]
}
override def invalidates(a: Transform): Boolean = false
def execute(state: CircuitState): CircuitState = {
val c = state.circuit
val newTopName = state.annotations.collectFirst { case ReParentCircuitAnnotation(tgt) =>
tgt.module
}
val newCircuit = c.copy(main = newTopName.getOrElse(c.main))
val mainRename = newTopName.map { s =>
val rmap = RenameMap()
rmap.record(CircuitTarget(c.main), CircuitTarget(s))
rmap
}
val newAnnotations = newTopName
.map({ topName =>
// Update InstanceTargets and ReferenceTargets
// Yes, these are identical functions, but the copy methods force separate implementations
def updateInstance(t: InstanceTarget): Option[InstanceTarget] = {
val idx = t.path.lastIndexWhere(_._2.value == topName)
if (idx == -1) Some(t.copy(circuit = topName))
else Some(t.copy(circuit = topName, module = topName, path = t.path.drop(idx + 1)))
}
def updateReference(t: ReferenceTarget): Option[ReferenceTarget] = {
val idx = t.path.lastIndexWhere(_._2.value == topName)
if (idx == -1) Some(t.copy(circuit = topName))
else Some(t.copy(circuit = topName, module = topName, path = t.path.drop(idx + 1)))
}
AnnotationSeq(
state.annotations.toSeq
.map({
case x: SingleTargetAnnotation[InstanceTarget] if x.target.isInstanceOf[InstanceTarget] =>
updateInstance(x.target).map(y => x.duplicate(y))
case x: SingleTargetAnnotation[ReferenceTarget] if x.target.isInstanceOf[ReferenceTarget] =>
updateReference(x.target).map(y => x.duplicate(y))
case x: MultiTargetAnnotation =>
val newTargets: Seq[Seq[Option[Target]]] = x.targets.map(_.map({
case y: InstanceTarget => updateInstance(y)
case y: ReferenceTarget => updateReference(y)
case y => Some(y)
}))
if (newTargets.flatten.forall(_.isDefined)) Some(x.duplicate(newTargets.map(_.map(_.get)))) else None
case x => Some(x)
})
.filter(_.isDefined)
.map(_.get)
)
})
.getOrElse(state.annotations)
state.copy(circuit = newCircuit, renames = mainRename, annotations = newAnnotations)
}
}

View File

@@ -1,67 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import firrtl._
import firrtl.annotations.ModuleTarget
import firrtl.ir._
import firrtl.options.Dependency
import firrtl.passes.memlib.ReplSeqMem
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
// Removes all the unused modules in a circuit by recursing through every
// instance (starting at the main module)
class RemoveUnusedModules extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.HighForm
override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty
override def optionalPrerequisiteOf: Seq[TransformDependency] = {
Forms.HighEmitters :+ Dependency[ReplSeqMem]
}
override def invalidates(a: Transform): Boolean = false
def execute(state: CircuitState): CircuitState = {
val modulesByName = state.circuit.modules.map {
case m: Module => (m.name, Some(m))
case m: ExtModule => (m.name, None)
}.toMap
def getUsedModules(om: Option[Module]): Set[String] = {
om match {
case Some(m) => {
def someStatements(statement: Statement): Seq[Statement] =
statement match {
case b: Block =>
b.stmts.map { someStatements(_) }
.foldLeft(Seq[Statement]())(_ ++ _)
case when: Conditionally =>
someStatements(when.conseq) ++ someStatements(when.alt)
case i: DefInstance => Seq(i)
case _ => Seq()
}
someStatements(m.body).map {
case s: DefInstance => Set(s.module) | getUsedModules(modulesByName(s.module))
case _ => Set[String]()
}.foldLeft(Set(m.name))(_ | _)
}
case None => Set.empty[String]
}
}
val usedModuleSet = getUsedModules(modulesByName(state.circuit.main))
val usedModuleSeq = state.circuit.modules.filter { usedModuleSet contains _.name }
val usedModuleNames = usedModuleSeq.map(_.name)
val renames = state.renames.getOrElse(RenameMap())
state.circuit.modules.filterNot { usedModuleSet contains _.name }.foreach { x =>
renames.record(ModuleTarget(state.circuit.main, x.name), Nil)
}
val newCircuit = Circuit(state.circuit.info, usedModuleSeq, state.circuit.main)
state.copy(circuit = newCircuit, renames = Some(renames))
}
}

View File

@@ -1,69 +0,0 @@
// See LICENSE for license details.
package barstools.tapeout.transforms
import chisel3.experimental.RunFirrtlTransform
import firrtl.PrimOps.Not
import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation}
import firrtl.ir._
import firrtl.passes.Pass
import firrtl.stage.Forms
import firrtl.stage.TransformManager.TransformDependency
import firrtl.{CircuitState, DependencyAPIMigration, Transform}
case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
override def duplicate(n: ModuleName): Annotation = ResetInverterAnnotation(n)
}
object ResetN extends Pass {
private val Bool = UIntType(IntWidth(1))
// Only works on Modules with a Bool port named reset
def invertReset(mod: Module): Module = {
// Check that it actually has reset
require(mod.ports.exists(p => p.name == "reset" && p.tpe == Bool), "Can only invert reset on a module with reset!")
// Rename "reset" to "reset_n"
val portsx = mod.ports.map {
case Port(info, "reset", Input, Bool) =>
Port(info, "reset_n", Input, Bool)
case other => other
}
val newReset = DefNode(NoInfo, "reset", DoPrim(Not, Seq(Reference("reset_n", Bool)), Seq.empty, Bool))
val bodyx = Block(Seq(newReset, mod.body))
mod.copy(ports = portsx, body = bodyx)
}
def run(c: Circuit): Circuit = {
c.copy(modules = c.modules.map {
case mod: Module if mod.name == c.main => invertReset(mod)
case other => other
})
}
}
class ResetInverterTransform extends Transform with DependencyAPIMigration {
override def prerequisites: Seq[TransformDependency] = Forms.LowForm
override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized
override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters
override def invalidates(a: Transform): Boolean = false
override def execute(state: CircuitState): CircuitState = {
state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match {
case Nil => state
case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) =>
state.copy(circuit = ResetN.run(state.circuit))
case annotations =>
throw new Exception(s"There should be only one InvertReset annotation: got ${annotations.mkString(" -- ")}")
}
}
}
trait ResetInverter {
self: chisel3.Module =>
def invert[T <: chisel3.Module](module: T): Unit = {
chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform {
def transformClass: Class[_ <: Transform] = classOf[ResetInverterTransform]
def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed)
})
}
}

View File

@@ -4,6 +4,7 @@ package barstools.tapeout.transforms.stage
import barstools.tapeout.transforms.GenerateModelStageMain
import chisel3.stage.ChiselCli
import firrtl.stage.{RunFirrtlTransformAnnotation}
import firrtl.AnnotationSeq
import firrtl.annotations.{Annotation, NoTargetAnnotation}
import firrtl.options.{HasShellOptions, Shell, ShellOption, Stage, Unserializable}
@@ -27,12 +28,32 @@ object OutAnnoAnnotation extends HasShellOptions {
)
}
case class CompilerNameAnnotation(name: String) extends NoTargetAnnotation with TapeoutOption
// duplicate of firrtl.stage.CompilerAnnotation but needed so that you can have a
// CompilerAnnotation to match on when adding new transforms
object DuplicateCompilerAnnotation extends HasShellOptions {
val options: Seq[ShellOption[_]] = Seq(
new ShellOption[String](
longOption = "duplicate-compiler",
shortOption = Some("DX"),
toAnnotationSeq = (s: String) => {
Seq(
CompilerNameAnnotation(s))
},
helpText = "duplicate-compiler",
helpValueName = Some("same as --compiler FIRRTL flag")
)
)
}
trait TapeoutCli {
this: Shell =>
parser.note("Tapeout specific options")
Seq(
OutAnnoAnnotation
OutAnnoAnnotation,
DuplicateCompilerAnnotation
).foreach(_.addOptions(parser))
}