diff options
| author | Andrew Waterman | 2016-06-10 13:39:18 -0700 |
|---|---|---|
| committer | Andrew Waterman | 2016-06-10 14:14:15 -0700 |
| commit | 83f53a3a0cdcfc7537e923b827ab820205025d45 (patch) | |
| tree | 30bb8fb31240275d8573bd684c130a33faeb9ebe /src | |
| parent | a81c5ac84fe676b09fa5f6b0789d07fffc455448 (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.scala | 15 |
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") |
