aboutsummaryrefslogtreecommitdiff
path: root/src/test/scala/firrtlTests/PadWidthsTests.scala
diff options
context:
space:
mode:
authorKevin Laeufer2021-08-02 13:46:29 -0700
committerGitHub2021-08-02 20:46:29 +0000
commite04f1e7f303920ac1d1f865450d0e280aafb58b3 (patch)
tree73f26cd236ac8069d9c4877a3c42457d65d477fe /src/test/scala/firrtlTests/PadWidthsTests.scala
parentff1cd28202fb423956a6803a889c3632487d8872 (diff)
add emitter for optimized low firrtl (#2304)
* rearrange passes to enable optimized firrtl emission * Support ConstProp on padded arguments to comparisons with literals * Move shr legalization logic into ConstProp Continue calling ConstProp of shr in Legalize. Co-authored-by: Jack Koenig <koenig@sifive.com> Co-authored-by: Jack Koenig <koenig@sifive.com>
Diffstat (limited to 'src/test/scala/firrtlTests/PadWidthsTests.scala')
-rw-r--r--src/test/scala/firrtlTests/PadWidthsTests.scala170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/test/scala/firrtlTests/PadWidthsTests.scala b/src/test/scala/firrtlTests/PadWidthsTests.scala
new file mode 100644
index 00000000..c92a8b79
--- /dev/null
+++ b/src/test/scala/firrtlTests/PadWidthsTests.scala
@@ -0,0 +1,170 @@
+// See LICENSE for license details.
+
+package firrtlTests
+
+import firrtl.CircuitState
+import firrtl.options.Dependency
+import firrtl.stage.{Forms, TransformManager}
+import firrtl.testutils.LeanTransformSpec
+
+class PadWidthsTests extends LeanTransformSpec(Seq(Dependency(firrtl.passes.PadWidths))) {
+ behavior.of("PadWidths pass")
+
+ it should "pad widths inside a mux" in {
+ val input =
+ """circuit Top :
+ | module Top :
+ | input a : UInt<32>
+ | input b : UInt<20>
+ | input pred : UInt<1>
+ | output c : UInt<32>
+ | c <= mux(pred,a,b)""".stripMargin
+ val check = Seq("c <= mux(pred, a, pad(b, 32))")
+ executeTest(input, check)
+ }
+
+ it should "pad widths of connects" in {
+ val input =
+ """circuit Top :
+ | module Top :
+ | output a : UInt<32>
+ | input b : UInt<20>
+ | a <= b
+ | """.stripMargin
+ val check = Seq("a <= pad(b, 32)")
+ executeTest(input, check)
+ }
+
+ it should "pad widths of register init expressions" in {
+ val input =
+ """circuit Top :
+ | module Top :
+ | input clock: Clock
+ | input reset: AsyncReset
+ |
+ | reg r: UInt<8>, clock with:
+ | reset => (reset, UInt<1>("h1"))
+ | """.stripMargin
+ // PadWidths will call into constant prop directly, thus the literal is widened instead of adding a pad
+ val check = Seq("reset => (reset, UInt<8>(\"h1\"))")
+ executeTest(input, check)
+ }
+
+ private def testOp(op: String, width: Int, resultWidth: Int): Unit = {
+ assert(width > 0)
+ val input =
+ s"""circuit Top :
+ | module Top :
+ | input a : UInt<32>
+ | input b : UInt<$width>
+ | output c : UInt<$resultWidth>
+ | c <= $op(a,b)""".stripMargin
+ val check = if (width < 32) {
+ Seq(s"c <= $op(a, pad(b, 32))")
+ } else if (width == 32) {
+ Seq(s"c <= $op(a, b)")
+ } else {
+ Seq(s"c <= $op(pad(a, $width), b)")
+ }
+ executeTest(input, check)
+ }
+
+ it should "pad widths of the arguments to add and sub" in {
+ // add and sub have the same width inference rule: max(w_1, w_2) + 1
+ testOp("add", 2, 33)
+ testOp("add", 32, 33)
+ testOp("add", 35, 36)
+
+ testOp("sub", 2, 33)
+ testOp("sub", 32, 33)
+ testOp("sub", 35, 36)
+ }
+
+ it should "pad widths of the arguments to and, or and xor" in {
+ // and, or and xor have the same width inference rule: max(w_1, w_2)
+ testOp("and", 2, 32)
+ testOp("and", 32, 32)
+ testOp("and", 35, 35)
+
+ testOp("or", 2, 32)
+ testOp("or", 32, 32)
+ testOp("or", 35, 35)
+
+ testOp("xor", 2, 32)
+ testOp("xor", 32, 32)
+ testOp("xor", 35, 35)
+ }
+
+ it should "pad widths of the arguments to lt, leq, gt, geq, eq and neq" in {
+ // lt, leq, gt, geq, eq and ne have the same width inference rule: 1
+ testOp("lt", 2, 1)
+ testOp("lt", 32, 1)
+ testOp("lt", 35, 1)
+
+ testOp("leq", 2, 1)
+ testOp("leq", 32, 1)
+ testOp("leq", 35, 1)
+
+ testOp("gt", 2, 1)
+ testOp("gt", 32, 1)
+ testOp("gt", 35, 1)
+
+ testOp("geq", 2, 1)
+ testOp("geq", 32, 1)
+ testOp("geq", 35, 1)
+
+ testOp("eq", 2, 1)
+ testOp("eq", 32, 1)
+ testOp("eq", 35, 1)
+
+ testOp("neq", 2, 1)
+ testOp("neq", 32, 1)
+ testOp("neq", 35, 1)
+ }
+
+ private val resolvedCompiler = new TransformManager(Forms.Resolved)
+ private def checkWidthsAfterPadWidths(input: String, op: String): Unit = {
+ val result = compile(input)
+
+ // we serialize the result in order to rerun width inference
+ val resultFir = firrtl.Parser.parse(result.circuit.serialize)
+ val newWidths = resolvedCompiler.runTransform(CircuitState(resultFir, Seq()))
+
+ // the newly loaded circuit should look the same in serialized form (if this fails, the test has a bug)
+ assert(newWidths.circuit.serialize == result.circuit.serialize)
+
+ // we compare the widths produced by PadWidths with the widths that would normally be inferred
+ assert(newWidths.circuit.modules.head == result.circuit.modules.head, s"failed with op `$op`")
+ }
+
+ it should "always generate valid firrtl" in {
+ // an older version of PadWidths would generate ill types firrtl for mul, div, rem and dshl
+
+ def input(op: String): String =
+ s"""circuit Top:
+ | module Top:
+ | input a: UInt<3>
+ | input b: UInt<1>
+ | output c: UInt
+ | c <= $op(a, b)
+ |""".stripMargin
+
+ def test(op: String): Unit = checkWidthsAfterPadWidths(input(op), op)
+
+ // This was never broken, but we want to make sure that the test works.
+ test("add")
+
+ test("mul")
+ test("div")
+ test("rem")
+ test("dshl")
+ }
+
+ private def executeTest(input: String, expected: Seq[String]): Unit = {
+ val result = compile(input)
+ val lines = result.circuit.serialize.split("\n").map(normalized)
+ expected.map(normalized).foreach { e =>
+ assert(lines.contains(e), f"Failed to find $e in ${lines.mkString("\n")}")
+ }
+ }
+}