From 0a4bcaa4053aca16f21f899ba76b1b751cfb47b3 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Tue, 30 Oct 2018 19:30:03 -0700 Subject: Instance Annotations (#926) Formerly #865 Major Code Changes/Features Added: Added Target trait as replacement for Named Added TargetToken as token in building Target Added GenericTarget as a catch-all Target Added CircuitTarget, ModuleTarget, ReferenceTarget, and InstanceTarget Added ResolvePaths annotation Added EliminateTargetPaths (and helper class DuplicationHelper) Updated Dedup to work with instance annotations Updated RenameMap to work with instance annotations DCE & ConstantProp extend ResolveAnnotationPaths --- .../transforms/EliminateTargetPaths.scala | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala (limited to 'src/main/scala/firrtl/annotations/transforms') diff --git a/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala b/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala new file mode 100644 index 00000000..8f604c9f --- /dev/null +++ b/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala @@ -0,0 +1,167 @@ +// See LICENSE for license details. + +package firrtl.annotations.transforms + +import firrtl.Mappers._ +import firrtl.analyses.InstanceGraph +import firrtl.annotations.TargetToken.{Instance, OfModule} +import firrtl.annotations.analysis.DuplicationHelper +import firrtl.annotations._ +import firrtl.ir._ +import firrtl.{CircuitForm, CircuitState, FIRRTLException, HighForm, RenameMap, Transform, WDefInstance} + +import scala.collection.mutable + + +/** Group of targets that should become local targets + * @param targets + */ +case class ResolvePaths(targets: Seq[CompleteTarget]) extends Annotation { + override def update(renames: RenameMap): Seq[Annotation] = { + val newTargets = targets.flatMap(t => renames.get(t).getOrElse(Seq(t))) + Seq(ResolvePaths(newTargets)) + } +} + +case class NoSuchTargetException(message: String) extends FIRRTLException(message) + +/** For a set of non-local targets, modify the instance/module hierarchy of the circuit such that + * the paths in each non-local target can be removed + * + * In other words, if targeting a specific instance of a module, duplicate that module with a unique name + * and instantiate the new module instead. + * + * Consumes [[ResolvePaths]] + * + * E.g. for non-local target A/b:B/c:C/d, rename the following + * A/b:B/c:C/d -> C_/d + * A/b:B/c:C -> B_/c:C_ + * A/b:B -> A/b:B_ + * B/x -> (B/x, B_/x) // where x is any reference in B + * C/x -> (C/x, C_/x) // where x is any reference in C + */ +class EliminateTargetPaths extends Transform { + + def inputForm: CircuitForm = HighForm + + def outputForm: CircuitForm = HighForm + + /** Replaces old ofModules with new ofModules by calling dupMap methods + * Updates oldUsedOfModules, newUsedOfModules + * @param originalModule Original name of this module + * @param newModule New name of this module + * @param s + * @return + */ + private def onStmt(dupMap: DuplicationHelper, + oldUsedOfModules: mutable.HashSet[String], + newUsedOfModules: mutable.HashSet[String]) + (originalModule: String, newModule: String) + (s: Statement): Statement = s match { + case d@DefInstance(_, name, module) => + val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value + newUsedOfModules += ofModule + oldUsedOfModules += module + d.copy(module = ofModule) + case d@WDefInstance(_, name, module, _) => + val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value + newUsedOfModules += ofModule + oldUsedOfModules += module + d.copy(module = ofModule) + case other => other map onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(originalModule, newModule) + } + + /** Returns a modified circuit and [[RenameMap]] containing the associated target remapping + * @param cir + * @param targets + * @return + */ + def run(cir: Circuit, targets: Seq[IsMember]): (Circuit, RenameMap) = { + + val dupMap = DuplicationHelper(cir.modules.map(_.name).toSet) + + // For each target, record its path and calculate the necessary modifications to circuit + targets.foreach { t => dupMap.expandHierarchy(t) } + + // Records original list of used ofModules + val oldUsedOfModules = mutable.HashSet[String]() + oldUsedOfModules += cir.main + + // Records new list of used ofModules + val newUsedOfModules = mutable.HashSet[String]() + newUsedOfModules += cir.main + + // Contains new list of module declarations + val duplicatedModuleList = mutable.ArrayBuffer[DefModule]() + + // Foreach module, calculate the unique names of its duplicates + // Then, update the ofModules of instances that it encapsulates + cir.modules.foreach { m => + dupMap.getDuplicates(m.name).foreach { newName => + val newM = m match { + case e: ExtModule => e.copy(name = newName) + case o: Module => + o.copy(name = newName, body = onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(m.name, newName)(o.body)) + } + duplicatedModuleList += newM + } + } + + // Calculate the final module list + // A module is in the final list if: + // 1) it is a module that is instantiated (new or old) + // 2) it is an old module that was not instantiated and is still not instantiated + val finalModuleList = duplicatedModuleList.filter(m => + newUsedOfModules.contains(m.name) || (!newUsedOfModules.contains(m.name) && !oldUsedOfModules.contains(m.name)) + ) + + // Records how targets have been renamed + val renameMap = RenameMap() + + // Foreach target, calculate the pathless version and only rename targets that are instantiated + targets.foreach { t => + val newTsx = dupMap.makePathless(t) + val newTs = newTsx.filter(c => newUsedOfModules.contains(c.moduleOpt.get)) + if(newTs.nonEmpty) { + renameMap.record(t, newTs) + } + } + + // Return modified circuit and associated renameMap + (cir.copy(modules = finalModuleList), renameMap) + } + + override protected def execute(state: CircuitState): CircuitState = { + + val annotations = state.annotations.collect { case a: ResolvePaths => a } + + // Collect targets that are not local + val targets = annotations.flatMap(_.targets.collect { case x: IsMember => x }) + + // Check validity of paths in targets + val instanceOfModules = new InstanceGraph(state.circuit).getChildrenInstanceOfModule + val targetsWithInvalidPaths = mutable.ArrayBuffer[IsMember]() + targets.foreach { t => + val path = t match { + case m: ModuleTarget => Nil + case i: InstanceTarget => i.asPath + case r: ReferenceTarget => r.path + } + path.foldLeft(t.module) { case (module, (inst: Instance, of: OfModule)) => + val childrenOpt = instanceOfModules.get(module) + if(childrenOpt.isEmpty || !childrenOpt.get.contains((inst, of))) { + targetsWithInvalidPaths += t + } + of.value + } + } + if(targetsWithInvalidPaths.nonEmpty) { + val string = targetsWithInvalidPaths.mkString(",") + throw NoSuchTargetException(s"""Some targets have illegal paths that cannot be resolved/eliminated: $string""") + } + + val (newCircuit, renameMap) = run(state.circuit, targets) + + state.copy(circuit = newCircuit, renames = Some(renameMap)) + } +} -- cgit v1.2.3