aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/passes
diff options
context:
space:
mode:
authorAdam Izraelevitz2016-05-02 14:59:51 -0700
committerjackkoenig2016-05-12 22:42:06 -0700
commitf07baed2bc46e107250c317f290af48747a98322 (patch)
treea63c5d2477eabccab85dc6780f289fc24cbcad5c /src/main/scala/firrtl/passes
parent0ee659e85c7fe46c2678a49866ef1eca8f4a2c65 (diff)
Restructured Compiler to use Transforms. Added an InlineInstance pass.
Transforms are new unit of modularity within the compiler.
Diffstat (limited to 'src/main/scala/firrtl/passes')
-rw-r--r--src/main/scala/firrtl/passes/Inline.scala171
-rw-r--r--src/main/scala/firrtl/passes/Passes.scala14
2 files changed, 171 insertions, 14 deletions
diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala
new file mode 100644
index 00000000..5e523a37
--- /dev/null
+++ b/src/main/scala/firrtl/passes/Inline.scala
@@ -0,0 +1,171 @@
+package firrtl
+package passes
+
+// Datastructures
+import scala.collection.mutable
+
+import firrtl.Mappers.{ExpMap,StmtMap}
+import firrtl.Utils.WithAs
+
+
+// Tags an annotation to be consumed by this pass
+case object InlineCAKind extends CircuitAnnotationKind
+
+// Only use on legal Firrtl. Specifically, the restriction of
+// instance loops must have been checked, or else this pass can
+// infinitely recurse
+object InlineInstances extends Transform {
+ val inlineDelim = "$"
+ def name = "Inline Instances"
+ def execute(circuit: Circuit, annotations: Seq[CircuitAnnotation]): TransformResult = {
+ annotations.count(_.kind == InlineCAKind) match {
+ case 0 => TransformResult(circuit, None, None)
+ case 1 => {
+ // This could potentially be cleaned up, but the best solution is unclear at the moment.
+ val myAnnotation = annotations.find(_.kind == InlineCAKind).get match {
+ case x: StickyCircuitAnnotation => x
+ case _ => throw new PassException("Circuit annotation must be StickyCircuitAnnotation")
+ }
+ check(circuit, myAnnotation)
+ run(circuit, myAnnotation.getModuleNames, myAnnotation.getComponentNames)
+ }
+ // Default behavior is to error if more than one annotation for inlining
+ // This could potentially change
+ case _ => throw new PassException("Found more than one circuit annotation of InlineCAKind!")
+ }
+ }
+
+ // Checks the following properties:
+ // 1) All annotated modules exist
+ // 2) All annotated modules are InModules (can be inlined)
+ // 3) All annotated instances exist, and their modules can be inline
+ def check(c: Circuit, ca: StickyCircuitAnnotation): Unit = {
+ val errors = mutable.ArrayBuffer[PassException]()
+ val moduleMap = (for(m <- c.modules) yield m.name -> m).toMap
+ val annModuleNames = ca.getModuleNames.map(_.name) ++ ca.getComponentNames.map(_.module.name)
+ def checkExists(name: String): Unit =
+ if (!moduleMap.contains(name))
+ errors += new PassException(s"Annotated module does not exist: ${name}")
+ def checkExternal(name: String): Unit = moduleMap(name) match {
+ case m: ExModule => errors += new PassException(s"Annotated module cannot be an external module: ${name}")
+ case _ => {}
+ }
+ def checkInstance(cn: ComponentName): Unit = {
+ var containsCN = false
+ def onStmt(name: String)(s: Stmt): Stmt = {
+ s match {
+ case WDefInstance(_, inst_name, module_name, tpe) =>
+ if (name == inst_name) {
+ containsCN = true
+ checkExternal(module_name)
+ }
+ case _ => {}
+ }
+ s map onStmt(name)
+ }
+ onStmt(cn.name)(moduleMap(cn.module.name).asInstanceOf[InModule].body)
+ if (!containsCN) errors += new PassException(s"Annotated instance does not exist: ${cn.module.name}.${cn.name}")
+ }
+ annModuleNames.foreach{n => checkExists(n)}
+ if (!errors.isEmpty) throw new PassExceptions(errors)
+ annModuleNames.foreach{n => checkExternal(n)}
+ if (!errors.isEmpty) throw new PassExceptions(errors)
+ ca.getComponentNames.foreach{cn => checkInstance(cn)}
+ if (!errors.isEmpty) throw new PassExceptions(errors)
+ }
+
+ def run(c: Circuit, modsToInline: Seq[ModuleName], instsToInline: Seq[ComponentName]): TransformResult = {
+ // ---- Rename functions/data ----
+ val renameMap = mutable.HashMap[Named,Seq[Named]]()
+ // Updates renameMap with new names
+ def update(name: Named, rename: Named) = {
+ val existing = renameMap.getOrElse(name, Seq[Named]())
+ if (!existing.contains(rename)) renameMap(name) = existing.:+(rename)
+ }
+
+ // ---- Pass functions/data ----
+ // Contains all unaltered modules
+ val originalModules = mutable.HashMap[String,Module]()
+ // Contains modules whose direct/indirect children modules have been inlined, and whose tagged instances have been inlined.
+ val inlinedModules = mutable.HashMap[String,Module]()
+
+ // Recursive.
+ def onModule(m: Module): Module = {
+ val inlinedInstances = mutable.ArrayBuffer[String]()
+ // Recursive. Replaces inst.port with inst$port
+ def onExp(e: Expression): Expression = e match {
+ case WSubField(WRef(ref, _, _, _), field, tpe, gen) => {
+ // Relies on instance declaration before any instance references
+ if (inlinedInstances.contains(ref)) {
+ val newName = ref + inlineDelim + field
+ update(ComponentName(ref, ModuleName(m.name)), ComponentName(newName, ModuleName(m.name)))
+ WRef(newName, tpe, WireKind(), gen)
+ }
+ else e
+ }
+ case e => e map onExp
+ }
+ // Recursive. Inlines tagged instances
+ def onStmt(s: Stmt): Stmt = s match {
+ case WDefInstance(info, instName, moduleName, instTpe) => {
+ def rename(name:String): String = {
+ val newName = instName + inlineDelim + name
+ update(ComponentName(name, ModuleName(moduleName)), ComponentName(newName, ModuleName(m.name)))
+ newName
+ }
+ // Rewrites references in inlined statements from ref to inst$ref
+ def renameStmt(s: Stmt): Stmt = {
+ def renameExp(e: Expression): Expression = {
+ e map renameExp match {
+ case WRef(name, tpe, kind, gen) => WRef(rename(name), tpe, kind, gen)
+ case e => e
+ }
+ }
+ s map rename map renameStmt map renameExp
+ }
+ val shouldInline =
+ modsToInline.contains(ModuleName(moduleName)) ||
+ instsToInline.contains(ComponentName(instName, ModuleName(m.name)))
+ // Used memoized instance if available
+ val instModule =
+ if (inlinedModules.contains(name)) inlinedModules(name)
+ else {
+ // Warning - can infinitely recurse if there is an instance loop
+ onModule(originalModules(moduleName))
+ }
+ if (shouldInline) {
+ inlinedInstances += instName
+ val instInModule = instModule match {
+ case m: ExModule => throw new PassException("Cannot inline external module")
+ case m: InModule => m
+ }
+ val stmts = mutable.ArrayBuffer[Stmt]()
+ for (p <- instInModule.ports) {
+ stmts += DefWire(p.info, rename(p.name), p.tpe)
+ }
+ stmts += renameStmt(instInModule.body)
+ Begin(stmts.toSeq)
+ } else s
+ }
+ case s => s map onExp map onStmt
+ }
+ m match {
+ case InModule(info, name, ports, body) => {
+ val mx = InModule(info, name, ports, onStmt(body))
+ inlinedModules(name) = mx
+ mx
+ }
+ case m: ExModule => {
+ inlinedModules(m.name) = m
+ m
+ }
+ }
+ }
+
+ c.modules.foreach{ m => originalModules(m.name) = m}
+ val top = c.modules.find(m => m.name == c.main).get
+ onModule(top)
+ val modulesx = c.modules.map(m => inlinedModules(m.name))
+ TransformResult(Circuit(c.info, modulesx, c.main), Some(BasicRenameMap(renameMap.toMap)), None)
+ }
+}
diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala
index 8ccfb0b0..bc11bc9d 100644
--- a/src/main/scala/firrtl/passes/Passes.scala
+++ b/src/main/scala/firrtl/passes/Passes.scala
@@ -51,20 +51,6 @@ trait Pass extends LazyLogging {
class PassException(message: String) extends Exception(message)
class PassExceptions(exceptions: Seq[PassException]) extends Exception("\n" + exceptions.mkString("\n"))
-object PassUtils extends LazyLogging {
- val listOfPasses: Seq[Pass] = Seq(ToWorkingIR,ResolveKinds,InferTypes,ResolveGenders,InferWidths,PullMuxes,ExpandConnects,RemoveAccesses,ExpandWhens,LowerTypes)
- lazy val mapNameToPass: Map[String, Pass] = listOfPasses.map(p => p.name -> p).toMap
-
- def executePasses(c: Circuit, passes: Seq[Pass]): Circuit = {
- if (passes.isEmpty) {logger.info(s"Done!"); c}
- else {
- val p = passes.head
- val x = time(p.name) { p.run(c) }
- executePasses(x, passes.tail)
- }
- }
-}
-
// These should be distributed into separate files
object ToWorkingIR extends Pass {
private var mname = ""