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
|
// SPDX-License-Identifier: Apache-2.0
package firrtl.passes
import firrtl._
import firrtl.ir._
import firrtl.Mappers._
import firrtl.PrimOps._
import firrtl.options.Dependency
/** Handles dynamic accesses to zero-length vectors.
*
* @note Removes assignments that use a zero-length vector as a sink
* @note Removes signals resulting from accesses to a zero-length vector from attach groups
* @note Removes attaches that become degenerate after zero-length-accessor removal
* @note Replaces "source" references to elements of zero-length vectors with always-invalid validif
*/
object ZeroLengthVecs extends Pass {
override def prerequisites =
Seq(Dependency(PullMuxes), Dependency(ResolveKinds), Dependency(InferTypes), Dependency(ExpandConnects))
override def invalidates(a: Transform) = false
// Pass in an expression, not just a type, since it's not possible to generate an expression of
// interval type with the type alone unless you declare a component
private def replaceWithDontCare(toReplace: Expression): Expression = {
val default = toReplace.tpe match {
case UIntType(w) => UIntLiteral(0, w)
case SIntType(w) => SIntLiteral(0, w)
case FixedType(w, p) => FixedLiteral(0, w, p)
case it: IntervalType =>
val zeroType = IntervalType(Closed(0), Closed(0), IntWidth(0))
val zeroLit = DoPrim(AsInterval, Seq(SIntLiteral(0)), Seq(0, 0, 0), zeroType)
DoPrim(Clip, Seq(zeroLit, toReplace), Nil, it)
}
ValidIf(UIntLiteral(0), default, toReplace.tpe)
}
private def zeroLenDerivedRefLike(expr: Expression): Boolean = (expr, expr.tpe) match {
case (_, VectorType(_, 0)) => true
case (WSubIndex(e, _, _, _), _) => zeroLenDerivedRefLike(e)
case (WSubAccess(e, _, _, _), _) => zeroLenDerivedRefLike(e)
case (WSubField(e, _, _, _), _) => zeroLenDerivedRefLike(e)
case _ => false
}
// The connects have all been lowered, so all aggregate-typed expressions are "grounded" by WSubField/WSubAccess/WSubIndex
// Map before matching because we want don't-cares to propagate UP expression trees
private def dropZeroLenSubAccesses(expr: Expression): Expression = expr match {
case _: WSubIndex | _: WSubAccess | _: WSubField =>
if (zeroLenDerivedRefLike(expr)) replaceWithDontCare(expr) else expr
case e => e.map(dropZeroLenSubAccesses)
}
// Attach semantics: drop all zero-length-derived members of attach group, drop stmt if trivial
private def onStmt(stmt: Statement): Statement = stmt match {
case Connect(_, sink, _) if zeroLenDerivedRefLike(sink) => EmptyStmt
case IsInvalid(_, sink) if zeroLenDerivedRefLike(sink) => EmptyStmt
case Attach(info, sinks) =>
val filtered = Attach(info, sinks.filterNot(zeroLenDerivedRefLike))
if (filtered.exprs.length < 2) EmptyStmt else filtered
case s => s.map(onStmt).map(dropZeroLenSubAccesses)
}
override def run(c: Circuit): Circuit = {
c.copy(modules = c.modules.map(m => m.map(onStmt)))
}
}
|