blob: a4b7bc7a5263dc65f4145b20949442841c1c06d6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// SPDX-License-Identifier: Apache-2.0
package firrtl
import scala.collection.mutable
import scala.annotation.tailrec
import firrtl.ir._
class Namespace private {
private val tempNamePrefix: String = "_GEN"
// Begin with a tempNamePrefix in namespace so we always have a number suffix
private val namespace = mutable.HashSet[String](tempNamePrefix)
// Memoize where we were on a given prefix
private val indices = mutable.HashMap[String, Int]()
def tryName(value: String): Boolean = {
val unused = !contains(value)
if (unused) namespace += value
unused
}
def contains(value: String): Boolean = namespace.contains(value)
def newName(value: String): String = {
// First try, just check
if (tryName(value)) value
else {
var idx = indices.getOrElse(value, 0)
var str = value
do {
str = s"${value}_$idx"
idx += 1
} while (!(tryName(str)))
indices(value) = idx
str
}
}
def newTemp: String = newName(tempNamePrefix)
/** Create a copy of the HashSet backing this [[Namespace]]
* @return a copy of the underlying HashSet
*/
def cloneUnderlying: mutable.HashSet[String] = namespace.clone
}
/* TODO(azidar): Make Namespace return unique names that will not conflict with expanded
* names after LowerTypes expands names (like the Uniquify pass).
*/
object Namespace {
// Initializes a namespace from a Module
def apply(m: DefModule): Namespace = {
val namespace = new Namespace
def buildNamespaceStmt(s: Statement): Seq[String] = s match {
// 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)
m match {
case in: Module =>
namespace.namespace ++= buildNamespaceStmt(in.body)
case _ => // Do nothing
}
namespace
}
/** Initializes a [[Namespace]] for [[ir.Module]] names in a [[ir.Circuit]] */
def apply(c: Circuit): Namespace = {
val namespace = new Namespace
namespace.namespace ++= c.modules.map(_.name)
namespace
}
/** Initializes a [[Namespace]] from arbitrary strings * */
def apply(names: Seq[String] = Nil): Namespace = {
val namespace = new Namespace
namespace.namespace ++= names
namespace
}
/** Appends delim to prefix until no collisions of prefix + elts in names We don't add an _ in the collision check
* because elts could be Seq("") In this case, we're just really checking if prefix itself collides
*/
def findValidPrefix(
prefix: String,
elts: Iterable[String],
namespace: String => Boolean
): String = {
@tailrec
def rec(p: String): String = {
val found = elts.exists(elt => namespace(p + elt))
if (found) rec(p + "_") else p
}
rec(prefix)
}
}
|