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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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: ExtModule => 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[Module].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,DefModule]()
// Contains modules whose direct/indirect children modules have been inlined, and whose tagged instances have been inlined.
val inlinedModules = mutable.HashMap[String,DefModule]()
// Recursive.
def onModule(m: DefModule): DefModule = {
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: ExtModule => throw new PassException("Cannot inline external module")
case m: Module => 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 Module(info, name, ports, body) => {
val mx = Module(info, name, ports, onStmt(body))
inlinedModules(name) = mx
mx
}
case m: ExtModule => {
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)
}
}
|