aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorKevin Laeufer2021-02-17 12:16:52 -0800
committerGitHub2021-02-17 20:16:52 +0000
commit5a89fca6090948d0a99c217a09c692e58a20d1df (patch)
tree7996829e3589205607862cbbf578a4e9a9d6e623 /src/main
parent856226416cfa2d770c7205efad5331297c2e3a32 (diff)
Allow Side Effecting Statement to have Names (#2057)
* firrtl: add optional statement labels for stop, printf, assert, assume and cover * test: parsing of statement labels * ir: ensure that name is properly retained * SymbolTable: add support for labled statements * test: parsing statement labels * test: lower types name collisions with named statements * ignore empty names * Inline: deal with named and unnamed statements * RemoveWires: treat stop, printf and verification statements as "others" * test: fix InlineInstance tests * DeadCodeEliminations: statements are now als declarations * CheckHighForm: ensure that statement names are not used as references * CheckSpec: throw error if statement name collides * add pass to automatically add missing statement names * check: make sure that two statements cannot have the same name * stmtLabel -> stmtName * scalafmt * add statement names to spec * spec: meta data -> metadata * EnsureStatementNames: explain naming algorithm * remove returns * better namespace use * ir: add CanBeReferenced trait * ir: add newline as jack requested
Diffstat (limited to 'src/main')
-rw-r--r--src/main/antlr4/FIRRTL.g414
-rw-r--r--src/main/scala/firrtl/Namespace.scala8
-rw-r--r--src/main/scala/firrtl/Visitor.scala16
-rw-r--r--src/main/scala/firrtl/WIR.scala3
-rw-r--r--src/main/scala/firrtl/analyses/SymbolTable.scala4
-rw-r--r--src/main/scala/firrtl/graph/DiGraph.scala3
-rw-r--r--src/main/scala/firrtl/ir/IR.scala56
-rw-r--r--src/main/scala/firrtl/ir/Serializer.scala18
-rw-r--r--src/main/scala/firrtl/passes/CheckHighForm.scala27
-rw-r--r--src/main/scala/firrtl/passes/Inline.scala27
-rw-r--r--src/main/scala/firrtl/transforms/DeadCodeElimination.scala10
-rw-r--r--src/main/scala/firrtl/transforms/EnsureNamedStatements.scala39
-rw-r--r--src/main/scala/firrtl/transforms/RemoveWires.scala5
13 files changed, 172 insertions, 58 deletions
diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4
index 54ad8d0e..aa53f2f0 100644
--- a/src/main/antlr4/FIRRTL.g4
+++ b/src/main/antlr4/FIRRTL.g4
@@ -103,13 +103,17 @@ stmt
| exp '<-' exp info?
| exp 'is' 'invalid' info?
| when
- | 'stop(' exp exp intLit ')' info?
- | 'printf(' exp exp StringLit ( exp)* ')' info?
+ | 'stop(' exp exp intLit ')' stmtName? info?
+ | 'printf(' exp exp StringLit ( exp)* ')' stmtName? info?
| 'skip' info?
| 'attach' '(' exp+ ')' info?
- | 'assert' '(' exp exp exp StringLit ')' info?
- | 'assume' '(' exp exp exp StringLit ')' info?
- | 'cover' '(' exp exp exp StringLit ')' info?
+ | 'assert' '(' exp exp exp StringLit ')' stmtName? info?
+ | 'assume' '(' exp exp exp StringLit ')' stmtName? info?
+ | 'cover' '(' exp exp exp StringLit ')' stmtName? info?
+ ;
+
+stmtName
+ : ':' id
;
memField
diff --git a/src/main/scala/firrtl/Namespace.scala b/src/main/scala/firrtl/Namespace.scala
index 25f4a805..a4b7bc7a 100644
--- a/src/main/scala/firrtl/Namespace.scala
+++ b/src/main/scala/firrtl/Namespace.scala
@@ -53,9 +53,11 @@ object Namespace {
val namespace = new Namespace
def buildNamespaceStmt(s: Statement): Seq[String] = s match {
- case s: IsDeclaration => Seq(s.name)
- case s: Conditionally => buildNamespaceStmt(s.conseq) ++ buildNamespaceStmt(s.alt)
- case s: Block => s.stmts.flatMap(buildNamespaceStmt)
+ // Empty names are allowed for backwards compatibility reasons and
+ // indicate that the entity has essentially no name.
+ case s: IsDeclaration if s.name.nonEmpty => Seq(s.name)
+ case s: Conditionally => buildNamespaceStmt(s.conseq) ++ buildNamespaceStmt(s.alt)
+ case s: Block => s.stmts.flatMap(buildNamespaceStmt)
case _ => Nil
}
namespace.namespace ++= m.ports.map(_.name)
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index dadcac46..f1b3a5c2 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -318,6 +318,7 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
private def visitStmt(ctx: StmtContext): Statement = {
val ctx_exp = ctx.exp.asScala
val info = visitInfo(Option(ctx.info), ctx)
+ def stmtName = Option(ctx.stmtName).map(_.id.getText).getOrElse("")
ctx.getChild(0) match {
case when: WhenContext => visitWhen(when)
case term: TerminalNode =>
@@ -346,7 +347,8 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
case "inst" => DefInstance(info, ctx.id(0).getText, ctx.id(1).getText)
case "node" => DefNode(info, ctx.id(0).getText, visitExp(ctx_exp(0)))
- case "stop(" => Stop(info, string2Int(ctx.intLit().getText), visitExp(ctx_exp(0)), visitExp(ctx_exp(1)))
+ case "stop(" =>
+ Stop(info, string2Int(ctx.intLit().getText), visitExp(ctx_exp(0)), visitExp(ctx_exp(1)), name = stmtName)
case "attach" => Attach(info, ctx_exp.map(visitExp).toSeq)
case "printf(" =>
Print(
@@ -354,7 +356,8 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
visitStringLit(ctx.StringLit),
ctx_exp.drop(2).map(visitExp).toSeq,
visitExp(ctx_exp(0)),
- visitExp(ctx_exp(1))
+ visitExp(ctx_exp(1)),
+ name = stmtName
)
// formal
case "assert" =>
@@ -364,7 +367,8 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
visitExp(ctx_exp(0)),
visitExp(ctx_exp(1)),
visitExp(ctx_exp(2)),
- visitStringLit(ctx.StringLit)
+ visitStringLit(ctx.StringLit),
+ name = stmtName
)
case "assume" =>
Verification(
@@ -373,7 +377,8 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
visitExp(ctx_exp(0)),
visitExp(ctx_exp(1)),
visitExp(ctx_exp(2)),
- visitStringLit(ctx.StringLit)
+ visitStringLit(ctx.StringLit),
+ name = stmtName
)
case "cover" =>
Verification(
@@ -382,7 +387,8 @@ class Visitor(infoMode: InfoMode) extends AbstractParseTreeVisitor[FirrtlNode] w
visitExp(ctx_exp(0)),
visitExp(ctx_exp(1)),
visitExp(ctx_exp(2)),
- visitStringLit(ctx.StringLit)
+ visitStringLit(ctx.StringLit),
+ name = stmtName
)
// end formal
case "skip" => EmptyStmt
diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala
index a0b85007..78536a36 100644
--- a/src/main/scala/firrtl/WIR.scala
+++ b/src/main/scala/firrtl/WIR.scala
@@ -119,6 +119,7 @@ case class WDefInstanceConnector(
portCons: Seq[(Expression, Expression)])
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapExpr(f: Expression => Expression): Statement =
this.copy(portCons = portCons.map { case (e1, e2) => (f(e1), f(e2)) })
@@ -346,6 +347,7 @@ case class CDefMemory(
readUnderWrite: ReadUnderWrite.Value = ReadUnderWrite.Undefined)
extends Statement
with HasInfo
+ with CanBeReferenced
with UseSerializer {
def mapExpr(f: Expression => Expression): Statement = this
def mapStmt(f: Statement => Statement): Statement = this
@@ -361,6 +363,7 @@ case class CDefMemory(
case class CDefMPort(info: Info, name: String, tpe: Type, mem: String, exps: Seq[Expression], direction: MPortDir)
extends Statement
with HasInfo
+ with CanBeReferenced
with UseSerializer {
def mapExpr(f: Expression => Expression): Statement = this.copy(exps = exps.map(f))
def mapStmt(f: Statement => Statement): Statement = this
diff --git a/src/main/scala/firrtl/analyses/SymbolTable.scala b/src/main/scala/firrtl/analyses/SymbolTable.scala
index 3b304bc1..e4a53444 100644
--- a/src/main/scala/firrtl/analyses/SymbolTable.scala
+++ b/src/main/scala/firrtl/analyses/SymbolTable.scala
@@ -87,6 +87,10 @@ object SymbolTable {
case d: DefNode => table.declare(d)
case d: DefWire => table.declare(d)
case d: DefRegister => table.declare(d)
+ // Matches named statements like printf, stop, assert, assume, cover if the name is not empty.
+ // Empty names are allowed for backwards compatibility reasons and
+ // indicate that the entity has essentially no name.
+ case s: IsDeclaration if s.name.nonEmpty => table.declare(s.name, UnknownType, firrtl.UnknownKind)
case other => other.foreachStmt(scanStatement)
}
}
diff --git a/src/main/scala/firrtl/graph/DiGraph.scala b/src/main/scala/firrtl/graph/DiGraph.scala
index 9f6ffeb2..99bf8403 100644
--- a/src/main/scala/firrtl/graph/DiGraph.scala
+++ b/src/main/scala/firrtl/graph/DiGraph.scala
@@ -423,8 +423,7 @@ class DiGraph[T](private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) {
rec(nextTab, nodex, nextMark + " ", acc)
}
}
- this.findSources
- .toList // Convert LinkedHashSet to List to avoid determinism issues
+ this.findSources.toList // Convert LinkedHashSet to List to avoid determinism issues
.sortBy(_.toString) // Make order deterministic
.foldLeft(Nil: List[String]) {
case (acc, root) => rec("", root, "", acc)
diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala
index 1b564d42..9c3d6186 100644
--- a/src/main/scala/firrtl/ir/IR.scala
+++ b/src/main/scala/firrtl/ir/IR.scala
@@ -4,7 +4,7 @@ package firrtl
package ir
import Utils.{dec2string, trim}
-import dataclass.data
+import dataclass.{data, since}
import firrtl.constraint.{Constraint, IsKnown, IsVar}
import org.apache.commons.text.translate.{AggregateTranslator, JavaUnicodeEscaper, LookupTranslator}
@@ -227,6 +227,13 @@ abstract class Expression extends FirrtlNode {
*/
sealed trait RefLikeExpression extends Expression { def flow: Flow }
+/** Represents a statement that can be referenced in a firrtl expression.
+ * This explicitly excludes named side-effecting statements like Print, Stop and Verification.
+ * Note: This trait cannot be sealed since the memory ports are declared in WIR.scala.
+ * Once we fully remove all WIR, this trait could be sealed.
+ */
+trait CanBeReferenced
+
object Reference {
/** Creates a Reference from a Wire */
@@ -387,7 +394,11 @@ abstract class Statement extends FirrtlNode {
def foreachString(f: String => Unit): Unit
def foreachInfo(f: Info => Unit): Unit
}
-case class DefWire(info: Info, name: String, tpe: Type) extends Statement with IsDeclaration with UseSerializer {
+case class DefWire(info: Info, name: String, tpe: Type)
+ extends Statement
+ with IsDeclaration
+ with CanBeReferenced
+ with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = this
def mapType(f: Type => Type): Statement = DefWire(info, name, f(tpe))
@@ -408,6 +419,7 @@ case class DefRegister(
init: Expression)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement =
@@ -429,6 +441,7 @@ object DefInstance {
case class DefInstance(info: Info, name: String, module: String, tpe: Type = UnknownType)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapExpr(f: Expression => Expression): Statement = this
def mapStmt(f: Statement => Statement): Statement = this
@@ -462,6 +475,7 @@ case class DefMemory(
readUnderWrite: ReadUnderWrite.Value = ReadUnderWrite.Undefined)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = this
@@ -477,6 +491,7 @@ case class DefMemory(
case class DefNode(info: Info, name: String, value: Expression)
extends Statement
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement = DefNode(info, name, f(value))
@@ -594,22 +609,24 @@ case class Attach(info: Info, exprs: Seq[Expression]) extends Statement with Has
def foreachString(f: String => Unit): Unit = ()
def foreachInfo(f: Info => Unit): Unit = f(info)
}
-@data class Stop(info: Info, ret: Int, clk: Expression, en: Expression)
+
+@data class Stop(info: Info, ret: Int, clk: Expression, en: Expression, @since("FIRRTL 1.5") name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
- def mapExpr(f: Expression => Expression): Statement = Stop(info, ret, f(clk), f(en))
+ def mapExpr(f: Expression => Expression): Statement = Stop(info, ret, f(clk), f(en), name)
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = this.copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { f(clk); f(en) }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(info: Info = info, ret: Int = ret, clk: Expression = clk, en: Expression = en): Stop = {
- Stop(info, ret, clk, en)
+ Stop(info, ret, clk, en, name)
}
}
object Stop {
@@ -622,19 +639,22 @@ object Stop {
string: StringLit,
args: Seq[Expression],
clk: Expression,
- en: Expression)
+ en: Expression,
+ @since("FIRRTL 1.5")
+ name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
- def mapExpr(f: Expression => Expression): Statement = Print(info, string, args.map(f), f(clk), f(en))
+ def mapExpr(f: Expression => Expression): Statement = Print(info, string, args.map(f), f(clk), f(en), name)
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = this.copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { args.foreach(f); f(clk); f(en) }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(
info: Info = info,
@@ -643,7 +663,7 @@ object Stop {
clk: Expression = clk,
en: Expression = en
): Print = {
- Print(info, string, args, clk, en)
+ Print(info, string, args, clk, en, name)
}
}
object Print {
@@ -665,20 +685,23 @@ object Formal extends Enumeration {
clk: Expression,
pred: Expression,
en: Expression,
- msg: StringLit)
+ msg: StringLit,
+ @since("FIRRTL 1.5")
+ name: String = "")
extends Statement
with HasInfo
+ with IsDeclaration
with UseSerializer {
def mapStmt(f: Statement => Statement): Statement = this
def mapExpr(f: Expression => Expression): Statement =
copy(clk = f(clk), pred = f(pred), en = f(en))
def mapType(f: Type => Type): Statement = this
- def mapString(f: String => String): Statement = this
+ def mapString(f: String => String): Statement = withName(f(name))
def mapInfo(f: Info => Info): Statement = copy(info = f(info))
def foreachStmt(f: Statement => Unit): Unit = ()
def foreachExpr(f: Expression => Unit): Unit = { f(clk); f(pred); f(en); }
def foreachType(f: Type => Unit): Unit = ()
- def foreachString(f: String => Unit): Unit = ()
+ def foreachString(f: String => Unit): Unit = f(name)
def foreachInfo(f: Info => Unit): Unit = f(info)
def copy(
op: Formal.Value = op,
@@ -688,7 +711,7 @@ object Formal extends Enumeration {
en: Expression = en,
msg: StringLit = msg
): Verification = {
- Verification(op, info, clk, pred, en, msg)
+ Verification(op, info, clk, pred, en, msg, name)
}
}
object Verification {
@@ -1016,6 +1039,7 @@ case class Port(
tpe: Type)
extends FirrtlNode
with IsDeclaration
+ with CanBeReferenced
with UseSerializer {
def mapType(f: Type => Type): Port = Port(info, name, direction, f(tpe))
def mapString(f: String => String): Port = Port(info, f(name), direction, tpe)
diff --git a/src/main/scala/firrtl/ir/Serializer.scala b/src/main/scala/firrtl/ir/Serializer.scala
index 983a7866..caea0a9c 100644
--- a/src/main/scala/firrtl/ir/Serializer.scala
+++ b/src/main/scala/firrtl/ir/Serializer.scala
@@ -102,11 +102,13 @@ object Serializer {
s(it.next())
if (it.hasNext) newLineAndIndent()
}
- case Stop(info, ret, clk, en) =>
- b ++= "stop("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= ret.toString; b += ')'; s(info)
- case Print(info, string, args, clk, en) =>
+ case stop @ Stop(info, ret, clk, en) =>
+ b ++= "stop("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= ret.toString; b += ')'
+ sStmtName(stop.name); s(info)
+ case print @ Print(info, string, args, clk, en) =>
b ++= "printf("; s(clk); b ++= ", "; s(en); b ++= ", "; b ++= string.escape
- if (args.nonEmpty) b ++= ", "; s(args, ", "); b += ')'; s(info)
+ if (args.nonEmpty) b ++= ", "; s(args, ", "); b += ')'
+ sStmtName(print.name); s(info)
case IsInvalid(info, expr) => s(expr); b ++= " is invalid"; s(info)
case DefWire(info, name, tpe) => b ++= "wire "; b ++= name; b ++= " : "; s(tpe); s(info)
case DefRegister(info, name, tpe, clock, reset, init) =>
@@ -138,9 +140,9 @@ object Serializer {
case Attach(info, exprs) =>
// exprs should never be empty since the attach statement takes *at least* two signals according to the spec
b ++= "attach ("; s(exprs, ", "); b += ')'; s(info)
- case Verification(op, info, clk, pred, en, msg) =>
+ case veri @ Verification(op, info, clk, pred, en, msg) =>
b ++= op.toString; b += '('; s(List(clk, pred, en), ", ", false); b ++= msg.escape
- b += ')'; s(info)
+ b += ')'; sStmtName(veri.name); s(info)
// WIR
case firrtl.CDefMemory(info, name, tpe, size, seq, readUnderWrite) =>
@@ -155,6 +157,10 @@ object Serializer {
case other => b ++= other.serialize // Handle user-defined nodes
}
+ private def sStmtName(lbl: String)(implicit b: StringBuilder): Unit = {
+ if (lbl.nonEmpty) { b ++= s" : $lbl" }
+ }
+
private def s(node: Width)(implicit b: StringBuilder, indent: Int): Unit = node match {
case IntWidth(width) => b += '<'; b ++= width.toString(); b += '>'
case UnknownWidth => // empty string
diff --git a/src/main/scala/firrtl/passes/CheckHighForm.scala b/src/main/scala/firrtl/passes/CheckHighForm.scala
index e3468c4e..05635d00 100644
--- a/src/main/scala/firrtl/passes/CheckHighForm.scala
+++ b/src/main/scala/firrtl/passes/CheckHighForm.scala
@@ -22,6 +22,10 @@ trait CheckHighFormLike { this: Pass =>
moduleNS += name
scopes.head += name
}
+ // ensures that the name cannot be used again, but prevent references to this name
+ def addToNamespace(name: String): Unit = {
+ moduleNS += name
+ }
def expandMPortVisibility(port: CDefMPort): Unit = {
// Legacy CHIRRTL ports are visible in any scope where their parent memory is visible
scopes.find(_.contains(port.mem)).getOrElse(scopes.head) += port.name
@@ -250,10 +254,19 @@ trait CheckHighFormLike { this: Pass =>
e.foreach(checkHighFormE(info, mname, names))
}
- def checkName(info: Info, mname: String, names: ScopeView)(name: String): Unit = {
- if (!names.legalDecl(name))
- errors.append(new NotUniqueException(info, mname, name))
- names.declare(name)
+ def checkName(info: Info, mname: String, names: ScopeView, canBeReference: Boolean)(name: String): Unit = {
+ // Empty names are allowed for backwards compatibility reasons and
+ // indicate that the entity has essentially no name.
+ if (name.isEmpty) { assert(!canBeReference, "A statement with an empty name cannot be used as a reference!") }
+ else {
+ if (!names.legalDecl(name))
+ errors.append(new NotUniqueException(info, mname, name))
+ if (canBeReference) {
+ names.declare(name)
+ } else {
+ names.addToNamespace(name)
+ }
+ }
}
def checkInstance(info: Info, child: String, parent: String): Unit = {
@@ -270,7 +283,11 @@ trait CheckHighFormLike { this: Pass =>
case NoInfo => minfo
case x => x
}
- s.foreach(checkName(info, mname, names))
+ val canBeReference = s match {
+ case _: CanBeReferenced => true
+ case _ => false
+ }
+ s.foreach(checkName(info, mname, names, canBeReference))
s match {
case DefRegister(info, name, tpe, _, reset, init) =>
if (hasFlip(tpe))
diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala
index 4eba5d59..912acf8e 100644
--- a/src/main/scala/firrtl/passes/Inline.scala
+++ b/src/main/scala/firrtl/passes/Inline.scala
@@ -187,18 +187,23 @@ class InlineInstances extends Transform with DependencyAPIMigration with Registe
renameMap: RenameMap
)(s: Statement
): Statement = {
- def onName(ofModuleOpt: Option[String])(name: String) = {
- if (prefix.nonEmpty && !ns.tryName(prefix + name)) {
- throw new Exception(s"Inlining failed. Inlined name '${prefix + name}' already exists")
- }
- ofModuleOpt match {
- case None =>
- renameMap.record(currentModule.ref(name), nextModule.ref(prefix + name))
- case Some(ofModule) =>
- renameMap.record(currentModule.instOf(name, ofModule), nextModule.instOf(prefix + name, ofModule))
+ def onName(ofModuleOpt: Option[String])(name: String): String = {
+ // Empty names are allowed for backwards compatibility reasons and
+ // indicate that the entity has essentially no name and thus cannot be prefixed.
+ if (name.isEmpty) { name }
+ else {
+ if (prefix.nonEmpty && !ns.tryName(prefix + name)) {
+ throw new Exception(s"Inlining failed. Inlined name '${prefix + name}' already exists")
+ }
+ ofModuleOpt match {
+ case None =>
+ renameMap.record(currentModule.ref(name), nextModule.ref(prefix + name))
+ case Some(ofModule) =>
+ renameMap.record(currentModule.instOf(name, ofModule), nextModule.instOf(prefix + name, ofModule))
+ }
+ renames(name) = prefix + name
+ prefix + name
}
- renames(name) = prefix + name
- prefix + name
}
s match {
diff --git a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
index 13173fdd..1d9bfd0e 100644
--- a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
+++ b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
@@ -258,6 +258,11 @@ class DeadCodeElimination extends Transform with RegisteredTransform with Depend
renames.delete(inst.name)
EmptyStmt
}
+ case print: Print => deleteIfNotEnabled(print, print.en)
+ case stop: Stop => deleteIfNotEnabled(stop, stop.en)
+ case formal: Verification => deleteIfNotEnabled(formal, formal.en)
+ // Statements are also declarations and thus this case needs to come *after* checking the
+ // print, stop and verification statements.
case decl: IsDeclaration =>
val node = LogicNode(mod.name, decl.name)
if (deadNodes.contains(node)) {
@@ -265,10 +270,7 @@ class DeadCodeElimination extends Transform with RegisteredTransform with Depend
renames.delete(decl.name)
EmptyStmt
} else decl
- case print: Print => deleteIfNotEnabled(print, print.en)
- case stop: Stop => deleteIfNotEnabled(stop, stop.en)
- case formal: Verification => deleteIfNotEnabled(formal, formal.en)
- case con: Connect =>
+ case con: Connect =>
val node = getDeps(con.loc) match { case Seq(elt) => elt }
if (deadNodes.contains(node)) EmptyStmt else con
case Attach(info, exprs) => // If any exprs are dead then all are
diff --git a/src/main/scala/firrtl/transforms/EnsureNamedStatements.scala b/src/main/scala/firrtl/transforms/EnsureNamedStatements.scala
new file mode 100644
index 00000000..a40409f9
--- /dev/null
+++ b/src/main/scala/firrtl/transforms/EnsureNamedStatements.scala
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package firrtl.transforms
+
+import firrtl._
+import firrtl.ir._
+
+/** Adds default names to print, stop and verification statements if their name is empty. */
+object EnsureNamedStatements extends Transform with DependencyAPIMigration {
+ override def invalidates(a: Transform) = false
+
+ override protected def execute(state: CircuitState): CircuitState = {
+ val c = state.circuit.mapModule(onModule)
+ state.copy(circuit = c)
+ }
+
+ private def onModule(m: DefModule): DefModule = m match {
+ case e: ExtModule => e
+ case mod: Module =>
+ val namespace = Namespace(mod)
+ // Ensure we always start with _0 suffix
+ val prefixes = Seq("cover", "assert", "assume", "print", "stop")
+ prefixes.filterNot(namespace.contains).foreach(namespace.newName)
+ mod.mapStmt(onStmt(namespace))
+ }
+
+ private def onStmt(namespace: Namespace)(stmt: Statement): Statement = stmt match {
+ case s: Print if s.name.isEmpty => s.withName(namespace.newName("print"))
+ case s: Stop if s.name.isEmpty => s.withName(namespace.newName("stop"))
+ case s: Verification if s.name.isEmpty =>
+ val baseName = s.op match {
+ case Formal.Cover => "cover"
+ case Formal.Assert => "assert"
+ case Formal.Assume => "assume"
+ }
+ s.withName(namespace.newName(baseName))
+ case other => other.mapStmt(onStmt(namespace))
+ }
+}
diff --git a/src/main/scala/firrtl/transforms/RemoveWires.scala b/src/main/scala/firrtl/transforms/RemoveWires.scala
index ee03ad30..f2907db2 100644
--- a/src/main/scala/firrtl/transforms/RemoveWires.scala
+++ b/src/main/scala/firrtl/transforms/RemoveWires.scala
@@ -115,7 +115,10 @@ class RemoveWires extends Transform with DependencyAPIMigration {
val initDep = Some(reg.init).filter(we(WRef(reg)) != we(_)) // Dependency exists IF reg doesn't init itself
regInfo(we(WRef(reg))) = reg
netlist(we(WRef(reg))) = (Seq(reg.clock) ++ resetDep ++ initDep, reg.info)
- case decl: IsDeclaration => // Keep all declarations except for nodes and non-Analog wires
+ case decl: CanBeReferenced =>
+ // Keep all declarations except for nodes and non-Analog wires and "other" statements.
+ // Thus this is expected to match DefInstance and DefMemory which both do not connect to
+ // any signals directly (instead a separate Connect is used).
decls += decl
case con @ Connect(cinfo, lhs, rhs) =>
kind(lhs) match {