aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Magyar2020-02-06 16:29:58 -0800
committerAlbert Magyar2020-02-06 16:35:13 -0800
commit98a23c0c1fe018c0899d26da5bfd18fb1e0bcab5 (patch)
tree916d9a493843eae50909a0ca682b5714dfb42614 /src
parentb36e36d956ced8f8ccfe8c540e11855b85e038c0 (diff)
Better register const prop through speculative de-optimization
* Fixes #1240 * Add failing reg const prop test case from #1240
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/transforms/ConstantPropagation.scala8
-rw-r--r--src/test/scala/firrtlTests/ConstantPropagationTests.scala23
2 files changed, 31 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/transforms/ConstantPropagation.scala b/src/main/scala/firrtl/transforms/ConstantPropagation.scala
index 66cf24b8..ad784559 100644
--- a/src/main/scala/firrtl/transforms/ConstantPropagation.scala
+++ b/src/main/scala/firrtl/transforms/ConstantPropagation.scala
@@ -490,6 +490,12 @@ class ConstantPropagation extends Transform with ResolvedAnnotationPaths {
* NonConstant values. When encountering a node reference, it expands the node by to its
* RHS assignment and recurses.
*
+ * @note Some optimization of Mux trees turn 1-bit mux operators into boolean operators. This
+ * can stifle register constant propagations, which looks at drivers through value-preserving
+ * Muxes and Connects only. By speculatively expanding some 1-bit Or and And operations into
+ * muxes, we can obtain the best possible insight on the value of the mux with a simple peephole
+ * de-optimization that does not actually appear in the output code.
+ *
* @return a RegCPEntry describing the constant prop-compatible sources driving this expression
*/
def regConstant(e: Expression): RegCPEntry = e match {
@@ -498,6 +504,8 @@ class ConstantPropagation extends Transform with ResolvedAnnotationPaths {
case WRef(nodeName, _, NodeKind, _) if nodeMap.contains(nodeName) =>
nodeRegCPEntries.getOrElseUpdate(nodeName, { regConstant(nodeMap(nodeName)) })
case Mux(_, tval, fval, _) => regConstant(tval).resolve(regConstant(fval))
+ case DoPrim(Or, Seq(a, b), Nil, BoolType) => regConstant(Mux(a, one, b, BoolType))
+ case DoPrim(And, Seq(a, b), Nil, BoolType) => regConstant(Mux(a, b, zero, BoolType))
case _ => RegCPEntry(NonConstant, NonConstant)
}
diff --git a/src/test/scala/firrtlTests/ConstantPropagationTests.scala b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
index af186cda..99b8c2f0 100644
--- a/src/test/scala/firrtlTests/ConstantPropagationTests.scala
+++ b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
@@ -1148,6 +1148,29 @@ class ConstantPropagationIntegrationSpec extends LowTransformSpec {
execute(input, check, Seq.empty)
}
+ "Const prop of registers" should "do limited speculative expansion of optimized muxes to absorb bigger cones" in {
+ val input =
+ """circuit Top :
+ | module Top :
+ | input clock : Clock
+ | input reset : UInt<1>
+ | input en : UInt<1>
+ | output out : UInt<1>
+ | reg r : UInt<1>, clock
+ | when en :
+ | r <= UInt<1>(1)
+ | out <= r""".stripMargin
+ val check =
+ """circuit Top :
+ | module Top :
+ | input clock : Clock
+ | input reset : UInt<1>
+ | input en : UInt<1>
+ | output out : UInt<1>
+ | out <= UInt<1>("h1")""".stripMargin
+ execute(input, check, Seq.empty)
+ }
+
"A register with constant reset and all connection to either itself or the same constant" should "be replaced with that constant" in {
val input =
"""circuit Top :