aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/passes/Inline.scala110
-rw-r--r--src/main/scala/firrtl/passes/clocklist/ClockList.scala2
-rw-r--r--src/test/scala/firrtlTests/FlattenTests.scala60
-rw-r--r--src/test/scala/firrtlTests/InlineInstancesTests.scala165
4 files changed, 241 insertions, 96 deletions
diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala
index 0ba0c5d9..f963e762 100644
--- a/src/main/scala/firrtl/passes/Inline.scala
+++ b/src/main/scala/firrtl/passes/Inline.scala
@@ -6,6 +6,7 @@ package passes
import firrtl.ir._
import firrtl.Mappers._
import firrtl.annotations._
+import firrtl.analyses.InstanceGraph
// Datastructures
import scala.collection.mutable
@@ -15,13 +16,14 @@ case class InlineAnnotation(target: Named) extends SingleTargetAnnotation[Named]
def duplicate(n: Named) = InlineAnnotation(n)
}
-// Only use on legal Firrtl. Specifically, the restriction of
-// instance loops must have been checked, or else this pass can
-// infinitely recurse
+/** Inline instances as indicated by existing [[InlineAnnotation]]s
+ * @note Only use on legal Firrtl. Specifically, the restriction of instance loops must have been checked, or else this
+ * pass can infinitely recurse.
+ */
class InlineInstances extends Transform {
def inputForm = LowForm
def outputForm = LowForm
- val inlineDelim = "$"
+ private [firrtl] val inlineDelim: String = "_"
private def collectAnns(circuit: Circuit, anns: Iterable[Annotation]): (Set[ModuleName], Set[ComponentName]) =
anns.foldLeft(Set.empty[ModuleName], Set.empty[ComponentName]) {
@@ -52,7 +54,7 @@ class InlineInstances extends Transform {
// 3) All annotated instances exist, and their modules can be inline
def check(c: Circuit, moduleNames: Set[ModuleName], instanceNames: Set[ComponentName]): Unit = {
val errors = mutable.ArrayBuffer[PassException]()
- val moduleMap = (for(m <- c.modules) yield m.name -> m).toMap
+ val moduleMap = new InstanceGraph(c).moduleMap
def checkExists(name: String): Unit =
if (!moduleMap.contains(name))
errors += new PassException(s"Annotated module does not exist: $name")
@@ -108,36 +110,86 @@ class InlineInstances extends Transform {
check(c, modsToInline, instsToInline)
val flatModules = modsToInline.map(m => m.name)
val flatInstances = instsToInline.map(i => i.module.name + "." + i.name) ++ getInstancesOf(c, flatModules)
- val moduleMap = c.modules.foldLeft(Map[String, DefModule]()) { (map, m) => map + (m.name -> m) }
-
- def appendNamePrefix(prefix: String)(name:String): String = prefix + name
- def appendRefPrefix(prefix: String, currentModule: String)(e: Expression): Expression = e match {
- case WSubField(WRef(ref, _, InstanceKind, _), field, tpe, gen) if flatInstances.contains(currentModule + "." + ref) =>
- WRef(prefix + ref + inlineDelim + field, tpe, WireKind, gen)
- case WRef(name, tpe, kind, gen) => WRef(prefix + name, tpe, kind, gen)
- case ex => ex map appendRefPrefix(prefix, currentModule)
+ val iGraph = new InstanceGraph(c)
+ val namespaceMap = collection.mutable.Map[String, Namespace]()
+
+ /** Add a prefix to all declarations updating a [[Namespace]] and appending to a [[RenameMap]] */
+ def appendNamePrefix(prefix: String, ns: Namespace, renames: RenameMap)(name:String): String = {
+ if (prefix.nonEmpty && !ns.tryName(prefix + name))
+ throw new Exception(s"Inlining failed. Inlined name '${prefix + name}' already exists")
+ renames.rename(name, prefix + name)
+ prefix + name
}
- def onStmt(prefix: String, currentModule: String)(s: Statement): Statement = s match {
- case WDefInstance(info, instName, moduleName, instTpe) =>
- // Rewrites references in inlined statements from ref to inst$ref
- val shouldInline = flatInstances.contains(currentModule + "." + instName)
- // Used memoized instance if available
- if (shouldInline) {
- val toInline = moduleMap(moduleName) match {
- case m: ExtModule => throw new PassException("Cannot inline external module")
- case m: Module => m
+ /** Modify all references */
+ def appendRefPrefix(currentModule: ModuleName, renames: RenameMap)
+ (e: Expression): Expression = e match {
+ case wsf@ WSubField(wr@ WRef(ref, _, InstanceKind, _), field, tpe, gen) =>
+ val port = ComponentName(s"$ref.$field", currentModule)
+ val inst = ComponentName(s"$ref", currentModule)
+ (renames.get(port), renames.get(inst)) match {
+ case (Some(p :: Nil), None) => WRef(p.name, tpe, WireKind, gen)
+ case (None, Some(i :: Nil)) => wsf.map(appendRefPrefix(currentModule, renames))
+ case (None, None) => wsf
+ case (Some(p), Some(i)) => throw new PassException(
+ s"Inlining found multiple renames for ports ($p) and/or instances ($i). This should be impossible...")
+ }
+ case wr@ WRef(name, _, _, _) =>
+ val comp = ComponentName(name, currentModule)
+ renames.get(comp).orElse(Some(Seq(comp))) match {
+ case Some(car :: Nil) => wr.copy(name=car.name)
+ case c@ Some(_) => throw new PassException(
+ s"Inlining found mlutiple renames for ref $comp -> $c. This should be impossible...")
+ }
+ case ex => ex.map(appendRefPrefix(currentModule, renames))
+ }
+
+ def onStmt(currentModule: ModuleName, renames: RenameMap)(s: Statement): Statement = {
+ val ns = namespaceMap.getOrElseUpdate(currentModule.name, Namespace(iGraph.moduleMap(currentModule.name)))
+ renames.setModule(currentModule.name)
+ s match {
+ case wDef@ WDefInstance(_, instName, modName, _) if flatInstances.contains(s"${currentModule.name}.$instName") =>
+ val toInline = iGraph.moduleMap(modName) match {
+ case m: ExtModule => throw new PassException(s"Cannot inline external module ${m.name}")
+ case m: Module => m
}
- val stmts = toInline.ports.map(p => DefWire(p.info, p.name, p.tpe)) :+ toInline.body
- onStmt(prefix + instName + inlineDelim, moduleName)(Block(stmts))
- } else WDefInstance(info, prefix + instName, moduleName, instTpe)
- case sx => sx map appendRefPrefix(prefix, currentModule) map onStmt(prefix, currentModule) map appendNamePrefix(prefix)
+
+ val ports = toInline.ports.map(p => DefWire(p.info, p.name, p.tpe))
+
+ val subRenames = RenameMap()
+ subRenames.setCircuit(currentModule.circuit.name)
+ val bodyx = Block(ports :+ toInline.body) map onStmt(currentModule.copy(name=modName), subRenames)
+
+ val names = "" +: Uniquify
+ .enumerateNames(Uniquify.stmtToType(bodyx)(NoInfo, ""))
+ .map(_.mkString("_"))
+
+ /** The returned prefix will not be "prefix unique". It may be the same as other existing prefixes in the namespace.
+ * However, prepending this prefix to all inlined components is guaranteed to not conflict with this module's
+ * namespace. To make it prefix unique, this requires expanding all names in the namespace to include their
+ * prefixes before calling findValidPrefix.
+ */
+ val safePrefix = Uniquify.findValidPrefix(instName + inlineDelim, names, ns.cloneUnderlying - instName)
+
+ ports.foreach( p => renames.rename(s"$instName.${p.name}", safePrefix + p.name) )
+
+ def recName(s: Statement): Statement = s.map(recName).map(appendNamePrefix(safePrefix, ns, subRenames))
+ def recRef(s: Statement): Statement = s.map(recRef).map(appendRefPrefix(currentModule.copy(name=modName), subRenames))
+
+ bodyx
+ .map(recName)
+ .map(recRef)
+ case sx => sx
+ .map(appendRefPrefix(currentModule, renames))
+ .map(onStmt(currentModule, renames))
+ }
}
- val flatCircuit = c.copy(modules = c.modules.flatMap {
+ val renames = RenameMap()
+ renames.setCircuit(c.main)
+ val flatCircuit = c.copy(modules = c.modules.flatMap {
case m if flatModules.contains(m.name) => None
- case m =>
- Some(m map onStmt("", m.name))
+ case m => Some(m.map(onStmt(ModuleName(m.name, CircuitName(c.main)), renames)))
})
CircuitState(flatCircuit, LowForm, annos, None)
}
diff --git a/src/main/scala/firrtl/passes/clocklist/ClockList.scala b/src/main/scala/firrtl/passes/clocklist/ClockList.scala
index 43583726..7be43471 100644
--- a/src/main/scala/firrtl/passes/clocklist/ClockList.scala
+++ b/src/main/scala/firrtl/passes/clocklist/ClockList.scala
@@ -42,7 +42,7 @@ class ClockList(top: String, writer: Writer) extends Pass {
// Inline the clock-only circuit up to the specified top module
val modulesToInline = (c.modules.collect { case Module(_, n, _, _) if n != top => ModuleName(n, CircuitName(c.main)) }).toSet
- val inlineTransform = new InlineInstances
+ val inlineTransform = new InlineInstances{ override val inlineDelim = "$" }
val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), Seq()).circuit
val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError("no top module"))
diff --git a/src/test/scala/firrtlTests/FlattenTests.scala b/src/test/scala/firrtlTests/FlattenTests.scala
index 570d03bf..77a221be 100644
--- a/src/test/scala/firrtlTests/FlattenTests.scala
+++ b/src/test/scala/firrtlTests/FlattenTests.scala
@@ -44,11 +44,11 @@ class FlattenTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | i$b <= i$a
- | b <= i$b
- | i$a <= a
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | i_b <= i_a
+ | b <= i_b
+ | i_a <= a
| module Inline1 :
| input a : UInt<32>
| output b : UInt<32>
@@ -77,16 +77,16 @@ class FlattenTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i1$a : UInt<32>
- | wire i1$b : UInt<32>
- | i1$b <= i1$a
- | wire i2$a : UInt<32>
- | wire i2$b : UInt<32>
- | i2$b <= i2$a
- | node tmp = i1$b
- | b <= i2$b
- | i1$a <= a
- | i2$a <= tmp
+ | wire i1_a : UInt<32>
+ | wire i1_b : UInt<32>
+ | i1_b <= i1_a
+ | wire i2_a : UInt<32>
+ | wire i2_b : UInt<32>
+ | i2_b <= i2_a
+ | node tmp = i1_b
+ | b <= i2_b
+ | i1_a <= a
+ | i2_a <= tmp
| module Inline1 :
| input a : UInt<32>
| output b : UInt<32>
@@ -131,17 +131,17 @@ class FlattenTests extends LowTransformSpec {
| input na : UInt<32>
| output b : UInt<32>
| output nb : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | wire i$i$a : UInt<32>
- | wire i$i$b : UInt<32>
- | i$i$b <= i$i$a
- | i$b <= i$i$a
- | i$i$a <= i$a
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | wire i_i_a : UInt<32>
+ | wire i_i_b : UInt<32>
+ | i_i_b <= i_i_a
+ | i_b <= i_i_a
+ | i_i_a <= i_a
| inst ni of NotInline1
- | b <= i$b
- | nb <= ni.b
- | i$a <= a
+ | b <= i_b
+ | nb <= ni.b
+ | i_a <= a
| ni.a <= na
| module NotInline1 :
| input a : UInt<32>
@@ -213,11 +213,11 @@ class FlattenTests extends LowTransformSpec {
| module Inline1 :
| input a : UInt<32>
| output b : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | i$b <= i$a
- | b <= i$a
- | i$a <= a
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | i_b <= i_a
+ | b <= i_a
+ | i_a <= a
| module Inline2 :
| input a : UInt<32>
| output b : UInt<32>
diff --git a/src/test/scala/firrtlTests/InlineInstancesTests.scala b/src/test/scala/firrtlTests/InlineInstancesTests.scala
index 4398df48..6d386d48 100644
--- a/src/test/scala/firrtlTests/InlineInstancesTests.scala
+++ b/src/test/scala/firrtlTests/InlineInstancesTests.scala
@@ -46,11 +46,11 @@ class InlineInstancesTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | i$b <= i$a
- | b <= i$b
- | i$a <= a""".stripMargin
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | i_b <= i_a
+ | b <= i_b
+ | i_a <= a""".stripMargin
execute(input, check, Seq(inline("Inline")))
}
@@ -74,15 +74,15 @@ class InlineInstancesTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i0$a : UInt<32>
- | wire i0$b : UInt<32>
- | i0$b <= i0$a
- | wire i1$a : UInt<32>
- | wire i1$b : UInt<32>
- | i1$b <= i1$a
- | b <= i1$b
- | i0$a <= a
- | i1$a <= i0$b""".stripMargin
+ | wire i0_a : UInt<32>
+ | wire i0_b : UInt<32>
+ | i0_b <= i0_a
+ | wire i1_a : UInt<32>
+ | wire i1_b : UInt<32>
+ | i1_b <= i1_a
+ | b <= i1_b
+ | i0_a <= a
+ | i1_a <= i0_b""".stripMargin
execute(input, check, Seq(inline("Simple")))
}
@@ -106,13 +106,13 @@ class InlineInstancesTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i0$a : UInt<32>
- | wire i0$b : UInt<32>
- | i0$b <= i0$a
+ | wire i0_a : UInt<32>
+ | wire i0_b : UInt<32>
+ | i0_b <= i0_a
| inst i1 of Simple
| b <= i1.b
- | i0$a <= a
- | i1.a <= i0$b
+ | i0_a <= a
+ | i1.a <= i0_b
| module Simple :
| input a : UInt<32>
| output b : UInt<32>
@@ -146,21 +146,21 @@ class InlineInstancesTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i0$a : UInt<32>
- | wire i0$b : UInt<32>
- | i0$b <= i0$a
+ | wire i0_a : UInt<32>
+ | wire i0_b : UInt<32>
+ | i0_b <= i0_a
| inst i1 of B
| b <= i1.b
- | i0$a <= a
- | i1.a <= i0$b
+ | i0_a <= a
+ | i1.a <= i0_b
| module B :
| input a : UInt<32>
| output b : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | i$b <= i$a
- | b <= i$b
- | i$a <= a""".stripMargin
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | i_b <= i_a
+ | b <= i_b
+ | i_a <= a""".stripMargin
execute(input, check, Seq(inline("A")))
}
@@ -188,13 +188,13 @@ class InlineInstancesTests extends LowTransformSpec {
| module Top :
| input a : UInt<32>
| output b : UInt<32>
- | wire i$a : UInt<32>
- | wire i$b : UInt<32>
- | inst i$i of B
- | i$b <= i$i.b
- | i$i.a <= i$a
- | b <= i$b
- | i$a <= a
+ | wire i_a : UInt<32>
+ | wire i_b : UInt<32>
+ | inst i_i of B
+ | i_b <= i_i.b
+ | i_i.a <= i_a
+ | b <= i_b
+ | i_a <= a
| module B :
| input a : UInt<32>
| output b : UInt<32>
@@ -202,6 +202,99 @@ class InlineInstancesTests extends LowTransformSpec {
execute(input, check, Seq(inline("A")))
}
+ "A module with nested inlines" should "still prepend prefixes" in {
+ val input =
+ """|circuit Top:
+ | module Top:
+ | inst foo of Foo
+ | module Foo:
+ | inst bar of Bar
+ | inst baz of Bar
+ | node foo = UInt<1>("h0")
+ | module Bar:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ val check =
+ """|circuit Top:
+ | module Top:
+ | node foo_bar_bar = UInt<1>("h0")
+ | inst foo_baz of Bar
+ | node foo_foo = UInt<1>("h0")
+ | module Bar:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ execute(input, check, Seq(inline("Foo"), inline("Foo.bar")))
+ }
+
+ "An inlined module" should "NOT be prefix unique" in {
+ val input =
+ """|circuit Top:
+ | module Top:
+ | inst a of A
+ | node a_foo = UInt<1>("h0")
+ | node a__bar = UInt<1>("h0")
+ | module A:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ val check =
+ """|circuit Top:
+ | module Top:
+ | node a_bar = UInt<1>("h0")
+ | node a_foo = UInt<1>("h0")
+ | node a__bar = UInt<1>("h0")
+ |""".stripMargin
+ execute(input, check, Seq(inline("A")))
+ }
+
+ /* This test is mutually exclusive with the above */
+ ignore should "be prefix unique" in {
+ val input =
+ """|circuit Top:
+ | module Top:
+ | inst a of A
+ | node a_foo = UInt<1>("h0")
+ | node a__bar = UInt<1>("h0")
+ | module A:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ val check =
+ """|circuit Top:
+ | module Top:
+ | node a___bar = UInt<1>("h0")
+ | node a_foo = UInt<1>("h0")
+ | node a__bar = UInt<1>("h0")
+ |""".stripMargin
+ execute(input, check, Seq(inline("A")))
+ }
+
+ it should "uniquify sanely" in {
+ val input =
+ """|circuit Top:
+ | module Top:
+ | inst foo of Foo
+ | node foo_ = UInt<1>("h0")
+ | node foo__bar = UInt<1>("h0")
+ | module Foo:
+ | inst bar of Bar
+ | inst baz of Bar
+ | node foo = UInt<1>("h0")
+ | module Bar:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ val check =
+ """|circuit Top:
+ | module Top:
+ | node foo__bar_bar = UInt<1>("h0")
+ | inst foo__baz of Bar
+ | node foo__foo = UInt<1>("h0")
+ | node foo_ = UInt<1>("h0")
+ | node foo__bar = UInt<1>("h0")
+ | module Bar:
+ | node bar = UInt<1>("h0")
+ |""".stripMargin
+ execute(input, check, Seq(inline("Foo"), inline("Foo.bar")))
+ }
+
// ---- Errors ----
// 1) ext module
"External module" should "not be inlined" in {