diff options
| author | mergify[bot] | 2022-06-16 23:15:42 +0000 |
|---|---|---|
| committer | GitHub | 2022-06-16 23:15:42 +0000 |
| commit | d001b34f816f1f65d0625aebf33e5cfc5ba93e49 (patch) | |
| tree | 7145978904fea41e4a61a14ff3b08d3b243cf951 /core/src | |
| parent | 13641d95951b189d7f5b0d4d99ace45f8b8f6282 (diff) | |
Define leading '_' as API for creating temporaries (backport #2580) (#2581)
* Define leading '_' as API for creating temporaries
Chisel and FIRRTL have long used signals with names beginning with an
underscore as an API to specify that the name does not really matter.
Tools like Verilator follow a similar convention and exclude signals
with underscore names from waveform dumps by default. With the
introduction of compiler-plugin prefixing in Chisel 3.4, the convention
remained but was hard for users to use unless the unnnamed signal
existed outside of any prefix domain. Notably, unnamed signals are most
useful when creating wires inside of utility methods which almost always
results in the signal ending up with a prefix.
With this commit, Chisel explicitly recognizes signals whos val names
start with an underscore and preserve that underscore regardless of any
prefixing. Chisel will also ignore such underscores when generating
prefixes based on the temporary signal, preventing accidental double
underscores in the names of signals that are prefixed by the temporary.
(cherry picked from commit bd94366290886f3489d58f88b9768c7c11fa2cb6)
* Remove unused defaultPrefix argument from _computeName
(cherry picked from commit ec178aa20a830df2c8c756b9e569709a59073554)
# Conflicts:
# core/src/main/scala/chisel3/Module.scala
# core/src/main/scala/chisel3/experimental/hierarchy/ModuleClone.scala
* Resolve backport conflicts
* Waive false positive binary compatibility errors
Co-authored-by: Jack Koenig <koenig@sifive.com>
Diffstat (limited to 'core/src')
6 files changed, 57 insertions, 40 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index d03122f9..ba2d2e32 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -275,7 +275,7 @@ package internal { private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = { val record = _portsRecord // Use .forceName to re-use default name resolving behavior - record.forceName(None, default = this.desiredName, namespace) + record.forceName(default = this.desiredName, namespace) // Now take the Ref that forceName set and convert it to the correct Arg val instName = record.getRef match { case Ref(name) => name @@ -497,7 +497,7 @@ package experimental { private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = { for (port <- getModulePorts) { - port._computeName(None, None).orElse(names.get(port)) match { + port._computeName(None).orElse(names.get(port)) match { case Some(name) => if (_namespace.contains(name)) { Builder.error( diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index bd04fdc4..f2ce4c70 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -94,26 +94,26 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends id match { case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling case id: InstanceClone[_] => id.setAsInstanceRef() - case id: BaseModule => id.forceName(None, default = id.desiredName, _namespace) - case id: MemBase[_] => id.forceName(None, default = "MEM", _namespace) - case id: stop.Stop => id.forceName(None, default = "stop", _namespace) - case id: assert.Assert => id.forceName(None, default = "assert", _namespace) - case id: assume.Assume => id.forceName(None, default = "assume", _namespace) - case id: cover.Cover => id.forceName(None, default = "cover", _namespace) - case id: printf.Printf => id.forceName(None, default = "printf", _namespace) + case id: BaseModule => id.forceName(default = id.desiredName, _namespace) + case id: MemBase[_] => id.forceName(default = "MEM", _namespace) + case id: stop.Stop => id.forceName(default = "stop", _namespace) + case id: assert.Assert => id.forceName(default = "assert", _namespace) + case id: assume.Assume => id.forceName(default = "assume", _namespace) + case id: cover.Cover => id.forceName(default = "cover", _namespace) + case id: printf.Printf => id.forceName(default = "printf", _namespace) case id: Data => if (id.isSynthesizable) { id.topBinding match { case OpBinding(_, _) => - id.forceName(Some(""), default = "T", _namespace) + id.forceName(default = "_T", _namespace) case MemoryPortBinding(_, _) => - id.forceName(None, default = "MPORT", _namespace) + id.forceName(default = "MPORT", _namespace) case PortBinding(_) => - id.forceName(None, default = "PORT", _namespace) + id.forceName(default = "PORT", _namespace) case RegBinding(_, _) => - id.forceName(None, default = "REG", _namespace) + id.forceName(default = "REG", _namespace) case WireBinding(_, _) => - id.forceName(Some(""), default = "WIRE", _namespace) + id.forceName(default = "_WIRE", _namespace) case _ => // don't name literals } } // else, don't name unbound types @@ -189,18 +189,39 @@ package object internal { /** Marker trait for modules that are not true modules */ private[chisel3] trait PseudoModule extends BaseModule + /* Check if a String name is a temporary name */ + def isTemp(name: String): Boolean = name.nonEmpty && name.head == '_' + /** Creates a name String from a prefix and a seed * @param prefix The prefix associated with the seed (must be in correct order, *not* reversed) * @param seed The seed for computing the name (if available) */ def buildName(seed: String, prefix: Prefix): String = { - val builder = new StringBuilder() - prefix.foreach { p => - builder ++= p - builder += '_' + // Don't bother copying the String if there's no prefix + if (prefix.isEmpty) { + seed + } else { + // Using Java's String builder to micro-optimize appending a String excluding 1st character + // for temporaries + val builder = new java.lang.StringBuilder() + // Starting with _ is the indicator of a temporary + val temp = isTemp(seed) + // Make sure the final result is also a temporary if this is a temporary + if (temp) { + builder.append('_') + } + prefix.foreach { p => + builder.append(p) + builder.append('_') + } + if (temp) { + // We've moved the leading _ to the front, drop it here + builder.append(seed, 1, seed.length) + } else { + builder.append(seed) + } + builder.toString } - builder ++= seed - builder.toString } // Private reflective version of "val io" to maintain Chisel.Module semantics without having diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala index c583c516..71ae2d8f 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/package.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala @@ -33,7 +33,7 @@ package object dataview { // The names of views do not matter except for when a view is annotated. For Views that correspond // To a single Data, we just forward the name of the Target. For Views that correspond to more // than one Data, we return this assigned name but rename it in the Convert stage - result.forceName(None, "view", Builder.viewNamespace) + result.forceName("view", Builder.viewNamespace) result } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala index 46a38e7c..c83479b0 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala @@ -218,7 +218,7 @@ object Lookupable { result.bind(newBinding) result.setAllParents(Some(ViewParent)) - result.forceName(None, "view", Builder.viewNamespace) + result.forceName("view", Builder.viewNamespace) result } diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 6f02b57c..6fd9bdd5 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -177,21 +177,13 @@ private[chisel3] trait HasId extends InstanceId { } /** Computes the name of this HasId, if one exists - * @param defaultPrefix Optionally provide a default prefix for computing the name * @param defaultSeed Optionally provide default seed for computing the name * @return the name, if it can be computed */ - private[chisel3] def _computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = { - if (hasSeed) { - Some(buildName(seedOpt.get, naming_prefix.reverse)) - } else { - defaultSeed.map { default => - defaultPrefix match { - case Some(p) => buildName(default, p :: naming_prefix.reverse) - case None => buildName(default, naming_prefix.reverse) - } - } - } + private[chisel3] def _computeName(defaultSeed: Option[String]): Option[String] = { + seedOpt + .orElse(defaultSeed) + .map(name => buildName(name, naming_prefix.reverse)) } /** This resolves the precedence of [[autoSeed]] and [[suggestName]] @@ -211,9 +203,9 @@ private[chisel3] trait HasId extends InstanceId { // Uses a namespace to convert suggestion into a true name // Will not do any naming if the reference already assigned. // (e.g. tried to suggest a name to part of a Record) - private[chisel3] def forceName(prefix: Option[String], default: => String, namespace: Namespace): Unit = + private[chisel3] def forceName(default: => String, namespace: Namespace): Unit = if (_ref.isEmpty) { - val candidate_name = _computeName(prefix, Some(default)).get + val candidate_name = _computeName(Some(default)).get val available_name = namespace.name(candidate_name) setRef(Ref(available_name)) // Clear naming prefix to free memory @@ -246,7 +238,7 @@ private[chisel3] trait HasId extends InstanceId { "This will become an error in Chisel 3.6." errors.deprecated(msg, None) errors.checkpoint(logger) - _computeName(None, None).get + _computeName(None).get } // Helper for reifying views if they map to a single Target @@ -506,7 +498,11 @@ private[chisel3] object Builder extends LazyLogging { } } buildAggName(d).map { name => - pushPrefix(name) + if (isTemp(name)) { + pushPrefix(name.tail) + } else { + pushPrefix(name) + } }.isDefined } @@ -749,7 +745,7 @@ private[chisel3] object Builder extends LazyLogging { logger.info("Elaborating design...") val mod = f if (forceModName) { // This avoids definition name index skipping with D/I - mod.forceName(None, mod.name, globalNamespace) + mod.forceName(mod.name, globalNamespace) } errors.checkpoint(logger) logger.info("Done elaborating.") diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 1ee8842f..9327c29e 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -94,7 +94,7 @@ object Arg { case Some(arg) => arg.name case None => id match { - case data: Data => data._computeName(None, Some("?")).get + case data: Data => data._computeName(Some("?")).get case _ => "?" } } |
