aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Waterman2016-06-10 13:39:18 -0700
committerAndrew Waterman2016-06-10 14:14:15 -0700
commit83f53a3a0cdcfc7537e923b827ab820205025d45 (patch)
tree30bb8fb31240275d8573bd684c130a33faeb9ebe /src
parenta81c5ac84fe676b09fa5f6b0789d07fffc455448 (diff)
Avoid exponential growth in reg code emission
In 7afe9f6180a53fd9f024c67d78289689a601c8b7, I reintroduced a performance pathology when recursing through Mux trees. This patch prevents redundantly expanding the same Mux more than a constant number of times, preserving linear runtime but still resulting in acceptable QoR.
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Emitter.scala15
1 files changed, 14 insertions, 1 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index eb8eba32..f871c82a 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -319,9 +319,22 @@ class VerilogEmitter extends Emitter {
assigns += Seq("`endif")
}
def update_and_reset(r: Expression, clk: Expression, reset: Expression, init: Expression) = {
+ // We want to flatten Mux trees for reg updates into if-trees for
+ // improved QoR for conditional updates. However, unbounded recursion
+ // would take exponential time, so don't redundantly flatten the same
+ // Mux more than a bounded number of times, preserving linear runtime.
+ // The threshold is empirical but ample.
+ val flattenThreshold = 4
+ val numTimesFlattened = collection.mutable.HashMap[Mux, Int]()
+ def canFlatten(m: Mux) = {
+ val n = numTimesFlattened.getOrElse(m, 0)
+ numTimesFlattened(m) = n + 1
+ n < flattenThreshold
+ }
+
def addUpdate(e: Expression, tabs: String): Seq[Seq[Any]] = {
netlist.getOrElse(e, e) match {
- case m: Mux => {
+ case m: Mux if canFlatten(m) => {
val ifStatement = Seq(tabs, "if(", m.cond, ") begin")
val trueCase = addUpdate(m.tval, tabs + tab)
val elseStatement = Seq(tabs, "end else begin")