aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/RenameMap.scala54
-rw-r--r--src/main/scala/firrtl/annotations/TargetUtils.scala46
-rw-r--r--src/main/scala/firrtl/passes/LowerTypes.scala42
3 files changed, 125 insertions, 17 deletions
diff --git a/src/main/scala/firrtl/RenameMap.scala b/src/main/scala/firrtl/RenameMap.scala
index df98f72f..82c00ca5 100644
--- a/src/main/scala/firrtl/RenameMap.scala
+++ b/src/main/scala/firrtl/RenameMap.scala
@@ -4,7 +4,9 @@ package firrtl
import annotations._
import firrtl.RenameMap.IllegalRenameException
+import firrtl.analyses.InstanceKeyGraph
import firrtl.annotations.TargetToken.{Field, Index, Instance, OfModule}
+import TargetUtils.{instKeyPathToTarget, unfoldInstanceTargets}
import scala.collection.mutable
@@ -21,6 +23,58 @@ object RenameMap {
rm
}
+ /** RenameMap factory for simple renaming of instances
+ *
+ * @param graph [[InstanceKeyGraph]] from *before* renaming
+ * @param renames Mapping of old instance name to new within Modules
+ */
+ private[firrtl] def fromInstanceRenames(
+ graph: InstanceKeyGraph,
+ renames: Map[OfModule, Map[Instance, Instance]]
+ ): RenameMap = {
+ def renameAll(it: InstanceTarget): InstanceTarget = {
+ var prevMod = OfModule(it.module)
+ val pathx = it.path.map {
+ case (inst, of) =>
+ val instx = renames
+ .get(prevMod)
+ .flatMap(_.get(inst))
+ .getOrElse(inst)
+ prevMod = of
+ instx -> of
+ }
+ // Sanity check, the last one should always be a rename (or we wouldn't be calling this method)
+ val instx = renames(prevMod)(Instance(it.instance))
+ it.copy(path = pathx, instance = instx.value)
+ }
+ val underlying = new mutable.HashMap[CompleteTarget, Seq[CompleteTarget]]
+ val instOf: String => Map[String, String] =
+ graph.getChildInstances.toMap
+ // Laziness here is desirable, we only access each key once, some we don't access
+ .mapValues(_.map(k => k.name -> k.module).toMap)
+ for ((OfModule(module), instMapping) <- renames) {
+ val modLookup = instOf(module)
+ val parentInstances = graph.findInstancesInHierarchy(module)
+ for {
+ // For every instance of the Module where the renamed instance resides
+ parent <- parentInstances
+ parentTarget = instKeyPathToTarget(parent)
+ // Create the absolute InstanceTarget to be renamed
+ (Instance(from), _) <- instMapping // The to is given by renameAll
+ instMod = modLookup(from)
+ fromTarget = parentTarget.instOf(from, instMod)
+ // Ensure all renames apply to the InstanceTarget
+ toTarget = renameAll(fromTarget)
+ // RenameMap only allows 1 hit when looking up InstanceTargets, so rename all possible
+ // paths to this instance
+ (fromx, tox) <- unfoldInstanceTargets(fromTarget).zip(unfoldInstanceTargets(toTarget))
+ } yield {
+ underlying(fromx) = List(tox)
+ }
+ }
+ new RenameMap(underlying)
+ }
+
/** Initialize a new RenameMap */
def apply(): RenameMap = new RenameMap
diff --git a/src/main/scala/firrtl/annotations/TargetUtils.scala b/src/main/scala/firrtl/annotations/TargetUtils.scala
new file mode 100644
index 00000000..164c430b
--- /dev/null
+++ b/src/main/scala/firrtl/annotations/TargetUtils.scala
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package firrtl.annotations
+
+import firrtl._
+import firrtl.analyses.InstanceKeyGraph
+import firrtl.analyses.InstanceKeyGraph.InstanceKey
+import firrtl.annotations.TargetToken._
+
+object TargetUtils {
+
+ /** Turns an instance path into a corresponding [[IsModule]]
+ *
+ * @note First InstanceKey is treated as the [[CircuitTarget]]
+ * @param path Instance path
+ * @param start Module in instance path to be starting [[ModuleTarget]]
+ * @return [[IsModule]] corresponding to Instance path
+ */
+ def instKeyPathToTarget(path: Seq[InstanceKey], start: Option[String] = None): IsModule = {
+ val head = path.head
+ val startx = start.getOrElse(head.module)
+ val top: IsModule = CircuitTarget(head.module).module(startx) // ~Top|Start
+ val pathx = path.dropWhile(_.module != startx)
+ if (pathx.isEmpty) top
+ else pathx.tail.foldLeft(top) { case (acc, key) => acc.instOf(key.name, key.module) }
+ }
+
+ /** Calculates all [[InstanceTarget]]s that refer to the given [[IsModule]]
+ *
+ * {{{
+ * ~Top|Top/a:A/b:B/c:C unfolds to:
+ * * ~Top|Top/a:A/b:B/c:C
+ * * ~Top|A/b:B/c:C
+ * * ~Top|B/c:C
+ * }}}
+ * @note [[ModuleTarget]] arguments return an empty Iterable
+ */
+ def unfoldInstanceTargets(ismod: IsModule): Iterable[InstanceTarget] = {
+ // concretely use List which is fast in practice
+ def rec(im: IsModule): List[InstanceTarget] = im match {
+ case inst: InstanceTarget => inst :: rec(inst.stripHierarchy(1))
+ case _ => Nil
+ }
+ rec(ismod)
+ }
+}
diff --git a/src/main/scala/firrtl/passes/LowerTypes.scala b/src/main/scala/firrtl/passes/LowerTypes.scala
index 592caf5d..0bd44a8c 100644
--- a/src/main/scala/firrtl/passes/LowerTypes.scala
+++ b/src/main/scala/firrtl/passes/LowerTypes.scala
@@ -8,8 +8,10 @@ import firrtl.annotations.{
MemoryInitAnnotation,
MemoryRandomInitAnnotation,
ModuleTarget,
- ReferenceTarget
+ ReferenceTarget,
+ TargetToken
}
+import TargetToken.{Instance, OfModule}
import firrtl.{
CircuitForm,
CircuitState,
@@ -73,16 +75,18 @@ object LowerTypes extends Transform with DependencyAPIMigration {
val memInitByModule = memInitAnnos.map(_.asInstanceOf[MemoryInitAnnotation]).groupBy(_.target.encapsulatingModule)
val c = CircuitTarget(state.circuit.main)
- val resultAndRenames = state.circuit.modules.map(m => onModule(c, m, memInitByModule.getOrElse(m.name, Seq())))
+ val refRenameMap = RenameMap()
+ val resultAndRenames =
+ state.circuit.modules.map(m => onModule(c, m, memInitByModule.getOrElse(m.name, Seq()), refRenameMap))
val result = state.circuit.copy(modules = resultAndRenames.map(_._1))
// memory init annotations could have been modified
val newAnnos = otherAnnos ++ resultAndRenames.flatMap(_._3)
- // chain module renames in topological order
- val moduleRenames = resultAndRenames.map { case (m, r, _) => m.name -> r }.toMap
- val moduleOrderBottomUp = InstanceKeyGraph(result).moduleOrder.reverseIterator
- val renames = moduleOrderBottomUp.map(m => moduleRenames(m.name)).reduce((a, b) => a.andThen(b))
+ // Build RenameMap for instances
+ val moduleRenames = resultAndRenames.map { case (m, r, _) => OfModule(m.name) -> r }.toMap
+ val instRenameMap = RenameMap.fromInstanceRenames(InstanceKeyGraph(state.circuit), moduleRenames)
+ val renames = instRenameMap.andThen(refRenameMap)
state.copy(circuit = result, renames = Some(renames), annotations = newAnnos)
}
@@ -90,9 +94,9 @@ object LowerTypes extends Transform with DependencyAPIMigration {
private def onModule(
c: CircuitTarget,
m: DefModule,
- memoryInit: Seq[MemoryInitAnnotation]
- ): (DefModule, RenameMap, Seq[MemoryInitAnnotation]) = {
- val renameMap = RenameMap()
+ memoryInit: Seq[MemoryInitAnnotation],
+ renameMap: RenameMap
+ ): (DefModule, Map[Instance, Instance], Seq[MemoryInitAnnotation]) = {
val ref = c.module(m.name)
// first we lower the ports in order to ensure that their names are independent of the module body
@@ -105,7 +109,9 @@ object LowerTypes extends Transform with DependencyAPIMigration {
implicit val memInit: Seq[MemoryInitAnnotation] = memoryInit
val newMod = mLoweredPorts.mapStmt(onStatement)
- (newMod, renameMap, memInit)
+ val instRenames = symbols.getInstanceRenames.toMap
+
+ (newMod, instRenames, memInit)
}
// We lower ports in a separate pass in order to ensure that statements inside the module do not influence port names.
@@ -221,6 +227,7 @@ private class LoweringTable(
private val namespace = mutable.HashSet[String]() ++ table.getSymbolNames
// Serialized old access string to new ground type reference.
private val nameToExprs = mutable.HashMap[String, Seq[RefLikeExpression]]() ++ portNameToExprs
+ private val instRenames = mutable.ListBuffer[(Instance, Instance)]()
def lower(mem: DefMemory): Seq[DefMemory] = {
val (mems, refs) = DestructTypes.destructMemory(m, mem, namespace, renameMap, portNames)
@@ -228,7 +235,7 @@ private class LoweringTable(
mems
}
def lower(inst: DefInstance): DefInstance = {
- val (newInst, refs) = DestructTypes.destructInstance(m, inst, namespace, renameMap, portNames)
+ val (newInst, refs) = DestructTypes.destructInstance(m, inst, namespace, instRenames, portNames)
nameToExprs ++= refs.map { case (name, r) => name -> List(r) }
newInst
}
@@ -245,6 +252,7 @@ private class LoweringTable(
}
def getReferences(expr: RefLikeExpression): Seq[RefLikeExpression] = nameToExprs(serialize(expr))
+ def getInstanceRenames: List[(Instance, Instance)] = instRenames.toList
// We could just use FirrtlNode.serialize here, but we want to make sure there are not SubAccess nodes left.
private def serialize(expr: RefLikeExpression): String = expr match {
@@ -296,11 +304,11 @@ private object DestructTypes {
* instead of a flat Reference when turning them into access expressions.
*/
def destructInstance(
- m: ModuleTarget,
- instance: DefInstance,
- namespace: Namespace,
- renameMap: RenameMap,
- reserved: Set[String]
+ m: ModuleTarget,
+ instance: DefInstance,
+ namespace: Namespace,
+ instRenames: mutable.ListBuffer[(Instance, Instance)],
+ reserved: Set[String]
): (DefInstance, Seq[(String, SubField)]) = {
val (rename, _) = uniquify(Field(instance.name, Default, instance.tpe), namespace, reserved)
val newName = rename.map(_.name).getOrElse(instance.name)
@@ -314,7 +322,7 @@ private object DestructTypes {
// rename all references to the instance if necessary
if (newName != instance.name) {
- renameMap.record(m.instOf(instance.name, instance.module), m.instOf(newName, instance.module))
+ instRenames += Instance(instance.name) -> Instance(newName)
}
// The ports do not need to be explicitly renamed here. They are renamed when the module ports are lowered.