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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
|
// See LICENSE for license details.
package firrtl
import annotations._
import firrtl.RenameMap.{CircularRenameException, IllegalRenameException}
import firrtl.annotations.TargetToken.{Field, Index}
import scala.collection.mutable
object RenameMap {
@deprecated("Use create with CompleteTarget instead, this will be removed in 1.3", "1.2")
def apply(map: collection.Map[Named, Seq[Named]]): RenameMap = {
val rm = new RenameMap
rm.addMap(map)
rm
}
def create(map: collection.Map[CompleteTarget, Seq[CompleteTarget]]): RenameMap = {
val rm = new RenameMap
rm.recordAll(map)
rm
}
def apply(): RenameMap = new RenameMap
abstract class RenameTargetException(reason: String) extends Exception(reason)
case class IllegalRenameException(reason: String) extends RenameTargetException(reason)
case class CircularRenameException(reason: String) extends RenameTargetException(reason)
}
/** Map old names to new names
*
* Transforms that modify names should return a [[RenameMap]] with the [[CircuitState]]
* These are mutable datastructures for convenience
*/
// TODO This should probably be refactored into immutable and mutable versions
final class RenameMap private () {
/** Record that the from [[firrtl.annotations.CircuitTarget CircuitTarget]] is renamed to another
* [[firrtl.annotations.CircuitTarget CircuitTarget]]
* @param from
* @param to
*/
def record(from: CircuitTarget, to: CircuitTarget): Unit = completeRename(from, Seq(to))
/** Record that the from [[firrtl.annotations.CircuitTarget CircuitTarget]] is renamed to another sequence of
* [[firrtl.annotations.CircuitTarget CircuitTarget]]s
* @param from
* @param tos
*/
def record(from: CircuitTarget, tos: Seq[CircuitTarget]): Unit = completeRename(from, tos)
/** Record that the from [[firrtl.annotations.IsMember Member]] is renamed to another [[firrtl.annotations.IsMember
* IsMember]]
* @param from
* @param to
*/
def record(from: IsMember, to: IsMember): Unit = completeRename(from, Seq(to))
/** Record that the from [[firrtl.annotations.IsMember IsMember]] is renamed to another sequence of
* [[firrtl.annotations.IsMember IsMember]]s
* @param from
* @param tos
*/
def record(from: IsMember, tos: Seq[IsMember]): Unit = completeRename(from, tos)
/** Records that the keys in map are also renamed to their corresponding value seqs. Only
* ([[firrtl.annotations.CircuitTarget CircuitTarget]] -> Seq[ [[firrtl.annotations.CircuitTarget CircuitTarget]] ])
* and ([[firrtl.annotations.IsMember IsMember]] -> Seq[ [[firrtl.annotations.IsMember IsMember]] ]) key/value
* allowed
* @param map
*/
def recordAll(map: collection.Map[CompleteTarget, Seq[CompleteTarget]]): Unit =
map.foreach{
case (from: IsComponent, tos: Seq[IsMember]) => completeRename(from, tos)
case (from: IsModule, tos: Seq[IsMember]) => completeRename(from, tos)
case (from: CircuitTarget, tos: Seq[CircuitTarget]) => completeRename(from, tos)
case other => Utils.throwInternalError(s"Illegal rename: ${other._1} -> ${other._2}")
}
/** Records that a [[firrtl.annotations.CompleteTarget CompleteTarget]] is deleted
* @param name
*/
def delete(name: CompleteTarget): Unit = underlying(name) = Seq.empty
/** Renames a [[firrtl.annotations.CompleteTarget CompleteTarget]]
* @param t target to rename
* @return renamed targets
*/
def apply(t: CompleteTarget): Seq[CompleteTarget] = completeGet(t).getOrElse(Seq(t))
/** Get renames of a [[firrtl.annotations.CircuitTarget CircuitTarget]]
* @param key Target referencing the original circuit
* @return Optionally return sequence of targets that key remaps to
*/
def get(key: CompleteTarget): Option[Seq[CompleteTarget]] = completeGet(key)
/** Get renames of a [[firrtl.annotations.CircuitTarget CircuitTarget]]
* @param key Target referencing the original circuit
* @return Optionally return sequence of targets that key remaps to
*/
def get(key: CircuitTarget): Option[Seq[CircuitTarget]] = completeGet(key).map( _.map { case x: CircuitTarget => x } )
/** Get renames of a [[firrtl.annotations.IsMember IsMember]]
* @param key Target referencing the original member of the circuit
* @return Optionally return sequence of targets that key remaps to
*/
def get(key: IsMember): Option[Seq[IsMember]] = completeGet(key).map { _.map { case x: IsMember => x } }
/** Create new [[RenameMap]] that merges this and renameMap
* @param renameMap
* @return
*/
def ++ (renameMap: RenameMap): RenameMap = RenameMap(underlying ++ renameMap.getUnderlying)
/** Returns the underlying map of rename information
* @return
*/
def getUnderlying: collection.Map[CompleteTarget, Seq[CompleteTarget]] = underlying
/** @return Whether this [[RenameMap]] has collected any changes */
def hasChanges: Boolean = underlying.nonEmpty
def getReverseRenameMap: RenameMap = {
val reverseMap = mutable.HashMap[CompleteTarget, Seq[CompleteTarget]]()
underlying.keysIterator.foreach{ key =>
apply(key).foreach { v =>
reverseMap(v) = key +: reverseMap.getOrElse(v, Nil)
}
}
RenameMap.create(reverseMap)
}
def keys: Iterator[CompleteTarget] = underlying.keysIterator
/** Serialize the underlying remapping of keys to new targets
* @return
*/
def serialize: String = underlying.map { case (k, v) =>
k.serialize + "=>" + v.map(_.serialize).mkString(", ")
}.mkString("\n")
/** Maps old names to new names. New names could still require renaming parts of their name
* Old names must refer to existing names in the old circuit
*/
private val underlying = mutable.HashMap[CompleteTarget, Seq[CompleteTarget]]()
/** Records which local InstanceTargets will require modification.
* Used to reduce time to rename nonlocal targets who's path does not require renaming
*/
private val sensitivity = mutable.HashSet[IsComponent]()
/** Caches results of recursiveGet. Is cleared any time a new rename target is added
*/
private val getCache = mutable.HashMap[CompleteTarget, Seq[CompleteTarget]]()
/** Updates [[sensitivity]]
* @param from original target
* @param to new target
*/
private def recordSensitivity(from: CompleteTarget, to: CompleteTarget): Unit = {
(from, to) match {
case (f: IsMember, t: IsMember) =>
val fromSet = f.pathAsTargets.toSet
val toSet = t.pathAsTargets
sensitivity ++= (fromSet -- toSet)
sensitivity ++= (fromSet.map(_.asReference) -- toSet.map(_.asReference))
case other =>
}
}
/** Get renames of a [[firrtl.annotations.CompleteTarget CompleteTarget]]
* @param key Target referencing the original circuit
* @return Optionally return sequence of targets that key remaps to
*/
private def completeGet(key: CompleteTarget): Option[Seq[CompleteTarget]] = {
val errors = mutable.ArrayBuffer[String]()
val ret = if(hasChanges) {
val ret = recursiveGet(mutable.LinkedHashSet.empty[CompleteTarget], errors)(key)
if(errors.nonEmpty) { throw IllegalRenameException(errors.mkString("\n")) }
if(ret.size == 1 && ret.head == key) { None } else { Some(ret) }
} else { None }
ret
}
// scalastyle:off
// This function requires a large cyclomatic complexity, and is best naturally expressed as a large function
/** Recursively renames a target so the returned targets are complete renamed
* @param set Used to detect circular renames
* @param errors Used to record illegal renames
* @param key Target to rename
* @return Renamed targets
*/
private def recursiveGet(set: mutable.LinkedHashSet[CompleteTarget],
errors: mutable.ArrayBuffer[String]
)(key: CompleteTarget): Seq[CompleteTarget] = {
if(getCache.contains(key)) {
getCache(key)
} else {
// First, check if whole key is remapped
// Note that remapped could hold stale parent targets that require renaming
val remapped = underlying.getOrElse(key, Seq(key))
// If we've seen this key before in recursive calls to parentTargets, then we know a circular renaming
// mapping has occurred, and no legal name exists
if(set.contains(key) && !key.isInstanceOf[CircuitTarget]) {
throw CircularRenameException(s"Illegal rename: circular renaming is illegal - ${set.mkString(" -> ")}")
}
// Add key to set to detect circular renaming
set += key
// Curry recursiveGet for cleaner syntax below
val getter = recursiveGet(set, errors)(_)
// For each remapped key, call recursiveGet on their parentTargets
val ret = remapped.flatMap {
// If t is a CircuitTarget, return it because it has no parent target
case t: CircuitTarget => Seq(t)
// If t is a ModuleTarget, try to rename parent target, then update t's parent
case t: ModuleTarget => getter(t.targetParent).map {
case CircuitTarget(c) => ModuleTarget(c, t.module)
}
/** If t is an InstanceTarget (has a path) but has no references:
* 1) Check whether the instance has been renamed (asReference)
* 2) Check whether the ofModule of the instance has been renamed (only 1:1 renaming is ok)
*/
case t: InstanceTarget =>
getter(t.asReference).map {
case t2:InstanceTarget => t2
case t2@ReferenceTarget(c, m, p, r, Nil) =>
val t3 = InstanceTarget(c, m, p, r, t.ofModule)
val ofModuleTarget = t3.ofModuleTarget
getter(ofModuleTarget) match {
case Seq(ModuleTarget(newCircuit, newOf)) if newCircuit == t3.circuit => t3.copy(ofModule = newOf)
case other =>
errors += s"Illegal rename: ofModule of $t is renamed to $other - must rename $t directly."
t
}
case other =>
errors += s"Illegal rename: $t has new instance reference $other"
t
}
/** If t is a ReferenceTarget:
* 1) Check parentTarget to tokens
* 2) Check ReferenceTarget with one layer stripped from its path hierarchy (i.e. a new root module)
*/
case t: ReferenceTarget =>
val ret: Seq[CompleteTarget] = if(t.component.nonEmpty) {
val last = t.component.last
getter(t.targetParent).map{ x =>
(x, last) match {
case (t2: ReferenceTarget, Field(f)) => t2.field(f)
case (t2: ReferenceTarget, Index(i)) => t2.index(i)
case other =>
errors += s"Illegal rename: ${t.targetParent} cannot be renamed to ${other._1} - must rename $t directly"
t
}
}
} else {
val pathTargets = sensitivity.empty ++ (t.pathAsTargets ++ t.pathAsTargets.map(_.asReference))
if(t.pathAsTargets.nonEmpty && sensitivity.intersect(pathTargets).isEmpty) Seq(t) else {
getter(t.pathTarget).map {
case newPath: IsModule => t.setPathTarget(newPath)
case other =>
errors += s"Illegal rename: path ${t.pathTarget} of $t cannot be renamed to $other - must rename $t directly"
t
}
}
}
ret.flatMap {
case y: IsComponent if !y.isLocal =>
val encapsulatingInstance = y.path.head._1.value
getter(y.stripHierarchy(1)).map {
_.addHierarchy(y.moduleOpt.get, encapsulatingInstance)
}
case other => Seq(other)
}
}
// Remove key from set as visiting the same key twice is ok, as long as its not during the same recursive call
set -= key
// Cache result
getCache(key) = ret
// Return result
ret
}
}
// scalastyle:on
/** Fully renames from to tos
* @param from
* @param tos
*/
private def completeRename(from: CompleteTarget, tos: Seq[CompleteTarget]): Unit = {
def check(from: CompleteTarget, to: CompleteTarget)(t: CompleteTarget): Unit = {
require(from != t, s"Cannot record $from to $to, as it is a circular constraint")
t match {
case _: CircuitTarget =>
case other: IsMember => check(from, to)(other.targetParent)
}
}
tos.foreach { to => if(from != to) check(from, to)(to) }
(from, tos) match {
case (x, Seq(y)) if x == y =>
case _ =>
tos.foreach{recordSensitivity(from, _)}
val existing = underlying.getOrElse(from, Vector.empty)
val updated = existing ++ tos
underlying(from) = updated
getCache.clear()
}
}
/* DEPRECATED ACCESSOR/SETTOR METHODS WITH [[firrtl.ir.Named Named]] */
@deprecated("Use record with CircuitTarget instead, this will be removed in 1.3", "1.2")
def rename(from: Named, to: Named): Unit = rename(from, Seq(to))
@deprecated("Use record with IsMember instead, this will be removed in 1.3", "1.2")
def rename(from: Named, tos: Seq[Named]): Unit = recordAll(Map(from.toTarget -> tos.map(_.toTarget)))
@deprecated("Use record with IsMember instead, this will be removed in 1.3", "1.2")
def rename(from: ComponentName, to: ComponentName): Unit = record(from, to)
@deprecated("Use record with IsMember instead, this will be removed in 1.3", "1.2")
def rename(from: ComponentName, tos: Seq[ComponentName]): Unit = record(from, tos.map(_.toTarget))
@deprecated("Use delete with CircuitTarget instead, this will be removed in 1.3", "1.2")
def delete(name: CircuitName): Unit = underlying(name) = Seq.empty
@deprecated("Use delete with IsMember instead, this will be removed in 1.3", "1.2")
def delete(name: ModuleName): Unit = underlying(name) = Seq.empty
@deprecated("Use delete with IsMember instead, this will be removed in 1.3", "1.2")
def delete(name: ComponentName): Unit = underlying(name) = Seq.empty
@deprecated("Use recordAll with CompleteTarget instead, this will be removed in 1.3", "1.2")
def addMap(map: collection.Map[Named, Seq[Named]]): Unit =
recordAll(map.map { case (key, values) => (Target.convertNamed2Target(key), values.map(Target.convertNamed2Target)) })
@deprecated("Use get with CircuitTarget instead, this will be removed in 1.3", "1.2")
def get(key: CircuitName): Option[Seq[CircuitName]] = {
get(Target.convertCircuitName2CircuitTarget(key)).map(_.collect{ case c: CircuitTarget => c.toNamed })
}
@deprecated("Use get with IsMember instead, this will be removed in 1.3", "1.2")
def get(key: ModuleName): Option[Seq[ModuleName]] = {
get(Target.convertModuleName2ModuleTarget(key)).map(_.collect{ case m: ModuleTarget => m.toNamed })
}
@deprecated("Use get with IsMember instead, this will be removed in 1.3", "1.2")
def get(key: ComponentName): Option[Seq[ComponentName]] = {
get(Target.convertComponentName2ReferenceTarget(key)).map(_.collect{ case c: IsComponent => c.toNamed })
}
@deprecated("Use get with IsMember instead, this will be removed in 1.3", "1.2")
def get(key: Named): Option[Seq[Named]] = key match {
case t: CompleteTarget => get(t)
case other => get(key.toTarget).map(_.collect{ case c: IsComponent => c.toNamed })
}
// Mutable helpers - APIs that set these are deprecated!
private var circuitName: String = ""
private var moduleName: String = ""
/** Sets mutable state to record current module we are visiting
* @param module
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def setModule(module: String): Unit = moduleName = module
/** Sets mutable state to record current circuit we are visiting
* @param circuit
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def setCircuit(circuit: String): Unit = circuitName = circuit
/** Records how a reference maps to a new reference
* @param from
* @param to
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def rename(from: String, to: String): Unit = rename(from, Seq(to))
/** Records how a reference maps to a new reference
* The reference's root module and circuit are determined by whomever called setModule or setCircuit last
* @param from
* @param tos
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def rename(from: String, tos: Seq[String]): Unit = {
val mn = ModuleName(moduleName, CircuitName(circuitName))
val fromName = ComponentName(from, mn).toTarget
val tosName = tos map { to => ComponentName(to, mn).toTarget }
record(fromName, tosName)
}
/** Records named reference is deleted
* The reference's root module and circuit are determined by whomever called setModule or setCircuit last
* @param name
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def delete(name: String): Unit = {
Target(Some(circuitName), Some(moduleName), AnnotationUtils.toSubComponents(name)).getComplete match {
case Some(t: CircuitTarget) => delete(t)
case Some(m: IsMember) => delete(m)
case other =>
}
}
/** Records that references in names are all deleted
* The reference's root module and circuit are determined by whomever called setModule or setCircuit last
* @param names
*/
@deprecated("Use typesafe rename defs instead, this will be removed in 1.3", "1.2")
def delete(names: Seq[String]): Unit = names.foreach(delete(_))
}
|