From 40cb49f9237e23608da454a194f5c55e33f19375 Mon Sep 17 00:00:00 2001 From: Albert Chen Date: Tue, 25 Aug 2020 16:54:25 -0700 Subject: Inline Boolean Expressions (#1817) The following conditions must be satisfied to inline: 1. has type Utils.BoolType 2. is bound to a DefNode with name starting with '_' 3. is bound to a DefNode with a source locator that points at the same file and line number. If it is a MultiInfo source locator, the set of file and line number pairs must be the same. Source locators may point to different column numbers. 4. InlineBooleanExpressionsMax has not been exceeded 5. is not a Mux Also updates the Verilog emitter to break up lines greater than 120 characters--- fuzzer/src/main/scala/firrtl/ExprGenParams.scala | 65 +++++++++++++++++++--- .../src/main/scala/firrtl/FirrtlCompileTests.scala | 54 +++--------------- .../main/scala/firrtl/FirrtlEquivalenceTest.scala | 59 +++++++++++++++++--- 3 files changed, 117 insertions(+), 61 deletions(-) (limited to 'fuzzer/src/main') diff --git a/fuzzer/src/main/scala/firrtl/ExprGenParams.scala b/fuzzer/src/main/scala/firrtl/ExprGenParams.scala index ddaec00d..4c11b860 100644 --- a/fuzzer/src/main/scala/firrtl/ExprGenParams.scala +++ b/fuzzer/src/main/scala/firrtl/ExprGenParams.scala @@ -1,5 +1,8 @@ package firrtl.fuzzer +import com.pholser.junit.quickcheck.generator.{Generator, GenerationStatus} +import com.pholser.junit.quickcheck.random.SourceOfRandomness + import firrtl.{Namespace, Utils} import firrtl.ir._ @@ -17,15 +20,15 @@ sealed trait ExprGenParams { */ def maxWidth: Int - /** A list of frequency/expression generator pairs + /** A mapping of expression generator to frequency * * The frequency number determines the probability that the corresponding - * generator will be chosen. i.e. for sequece Seq(1 -> A, 2 -> B, 3 -> C), - * the probabilities for A, B, and C are 1/6, 2/6, and 3/6 respectively. - * This sequency must be non-empty and all frequency numbers must be greater - * than zero. + * generator will be chosen. i.g. for Map(A -> 1, B -> 2, C -> B), the + * probabilities for A, B, and C are 1/6, 2/6, and 3/6 respectively. This + * map must be non-empty and all frequency numbers must be greater than + * zero. */ - def generators: Seq[(Int, ExprGen[_ <: Expression])] + def generators: Map[ExprGen[_ <: Expression], Int] /** The set of generated references that don't have a corresponding declaration */ @@ -102,10 +105,46 @@ sealed trait ExprGenParams { object ExprGenParams { + val defaultGenerators: Map[ExprGen[_ <: Expression], Int] = { + import ExprGen._ + Map( + AddDoPrimGen -> 1, + SubDoPrimGen -> 1, + MulDoPrimGen -> 1, + DivDoPrimGen -> 1, + LtDoPrimGen -> 1, + LeqDoPrimGen -> 1, + GtDoPrimGen -> 1, + GeqDoPrimGen -> 1, + EqDoPrimGen -> 1, + NeqDoPrimGen -> 1, + PadDoPrimGen -> 1, + ShlDoPrimGen -> 1, + ShrDoPrimGen -> 1, + DshlDoPrimGen -> 1, + CvtDoPrimGen -> 1, + NegDoPrimGen -> 1, + NotDoPrimGen -> 1, + AndDoPrimGen -> 1, + OrDoPrimGen -> 1, + XorDoPrimGen -> 1, + AndrDoPrimGen -> 1, + OrrDoPrimGen -> 1, + XorrDoPrimGen -> 1, + CatDoPrimGen -> 1, + BitsDoPrimGen -> 1, + HeadDoPrimGen -> 1, + TailDoPrimGen -> 1, + AsUIntDoPrimGen -> 1, + AsSIntDoPrimGen -> 1, + MuxGen -> 1 + ) + } + private case class ExprGenParamsImp( maxDepth: Int, maxWidth: Int, - generators: Seq[(Int, ExprGen[_ <: Expression])], + generators: Map[ExprGen[_ <: Expression], Int], protected val unboundRefs: Set[Reference], protected val namespace: Namespace) extends ExprGenParams { @@ -119,7 +158,7 @@ object ExprGenParams { def apply( maxDepth: Int, maxWidth: Int, - generators: Seq[(Int, ExprGen[_ <: Expression])] + generators: Map[ExprGen[_ <: Expression], Int] ): ExprGenParams = { require(maxWidth > 0, "maxWidth must be greater than zero") ExprGenParamsImp( @@ -190,7 +229,8 @@ object ExprGenParams { ))(tpe).map(e => e.get) // should be safe because leaf generators are defined for all types val branchGen: Type => StateGen[ExprGenParams, G, Expression] = (tpe: Type) => { - combineExprGens(s.generators)(tpe).flatMap { + val gens = s.generators.toSeq.map { case (gen, freq) => (freq, gen) } + combineExprGens(gens)(tpe).flatMap { case None => leafGen(tpe) case Some(e) => StateGen.pure(e) } @@ -211,3 +251,10 @@ object ExprGenParams { } } } + +abstract class SingleExpressionCircuitGenerator(val params: ExprGenParams) extends Generator[Circuit](classOf[Circuit]) { + override def generate(random: SourceOfRandomness, status: GenerationStatus): Circuit = { + implicit val r = random + params.generateSingleExprCircuit[SourceOfRandomnessGen]() + } +} diff --git a/fuzzer/src/main/scala/firrtl/FirrtlCompileTests.scala b/fuzzer/src/main/scala/firrtl/FirrtlCompileTests.scala index 9ee8e52b..3091e4d6 100644 --- a/fuzzer/src/main/scala/firrtl/FirrtlCompileTests.scala +++ b/fuzzer/src/main/scala/firrtl/FirrtlCompileTests.scala @@ -53,50 +53,14 @@ object SourceOfRandomnessGen { } } - -class FirrtlSingleModuleGenerator extends Generator[Circuit](classOf[Circuit]) { - override def generate(random: SourceOfRandomness, status: GenerationStatus): Circuit = { - implicit val r = random - import ExprGen._ - - val params = ExprGenParams( - maxDepth = 50, - maxWidth = 31, - generators = Seq( - 1 -> AddDoPrimGen, - 1 -> SubDoPrimGen, - 1 -> MulDoPrimGen, - 1 -> DivDoPrimGen, - 1 -> LtDoPrimGen, - 1 -> LeqDoPrimGen, - 1 -> GtDoPrimGen, - 1 -> GeqDoPrimGen, - 1 -> EqDoPrimGen, - 1 -> NeqDoPrimGen, - 1 -> PadDoPrimGen, - 1 -> ShlDoPrimGen, - 1 -> ShrDoPrimGen, - 1 -> DshlDoPrimGen, - 1 -> CvtDoPrimGen, - 1 -> NegDoPrimGen, - 1 -> NotDoPrimGen, - 1 -> AndDoPrimGen, - 1 -> OrDoPrimGen, - 1 -> XorDoPrimGen, - 1 -> AndrDoPrimGen, - 1 -> OrrDoPrimGen, - 1 -> XorrDoPrimGen, - 1 -> CatDoPrimGen, - 1 -> BitsDoPrimGen, - 1 -> HeadDoPrimGen, - 1 -> TailDoPrimGen, - 1 -> AsUIntDoPrimGen, - 1 -> AsSIntDoPrimGen - ) - ) - params.generateSingleExprCircuit[SourceOfRandomnessGen]() - } -} +import ExprGen._ +class FirrtlCompileCircuitGenerator extends SingleExpressionCircuitGenerator ( + ExprGenParams( + maxDepth = 50, + maxWidth = 31, + generators = ExprGenParams.defaultGenerators + ) +) @RunWith(classOf[JQF]) class FirrtlCompileTests { @@ -112,7 +76,7 @@ class FirrtlCompileTests { } @Fuzz - def compileSingleModule(@From(value = classOf[FirrtlSingleModuleGenerator]) c: Circuit) = { + def compileSingleModule(@From(value = classOf[FirrtlCompileCircuitGenerator]) c: Circuit) = { compile(CircuitState(c, ChirrtlForm, Seq())) } diff --git a/fuzzer/src/main/scala/firrtl/FirrtlEquivalenceTest.scala b/fuzzer/src/main/scala/firrtl/FirrtlEquivalenceTest.scala index e0aa1707..822744c2 100644 --- a/fuzzer/src/main/scala/firrtl/FirrtlEquivalenceTest.scala +++ b/fuzzer/src/main/scala/firrtl/FirrtlEquivalenceTest.scala @@ -1,17 +1,19 @@ package firrtl.fuzzer import com.pholser.junit.quickcheck.From +import com.pholser.junit.quickcheck.generator.{Generator, GenerationStatus} +import com.pholser.junit.quickcheck.random.SourceOfRandomness -import edu.berkeley.cs.jqf.fuzz.Fuzz; -import edu.berkeley.cs.jqf.fuzz.JQF; +import edu.berkeley.cs.jqf.fuzz.{Fuzz, JQF}; import firrtl._ import firrtl.annotations.{Annotation, CircuitTarget, ModuleTarget, Target} import firrtl.ir.Circuit +import firrtl.options.Dependency import firrtl.stage.{FirrtlCircuitAnnotation, InfoModeAnnotation, OutputFileAnnotation, TransformManager} import firrtl.stage.Forms.{VerilogMinimumOptimized, VerilogOptimized} import firrtl.stage.phases.WriteEmitted -import firrtl.transforms.ManipulateNames +import firrtl.transforms.{InlineBooleanExpressions, ManipulateNames} import firrtl.util.BackendCompilationUtilities import java.io.{File, FileWriter, PrintWriter, StringWriter} @@ -89,6 +91,32 @@ object FirrtlEquivalenceTestUtils { } } +import ExprGen._ +class InlineBooleanExprsCircuitGenerator extends SingleExpressionCircuitGenerator ( + ExprGenParams( + maxDepth = 50, + maxWidth = 31, + generators = ExprGenParams.defaultGenerators ++ Map( + LtDoPrimGen -> 10, + LeqDoPrimGen -> 10, + GtDoPrimGen -> 10, + GeqDoPrimGen -> 10, + EqDoPrimGen -> 10, + NeqDoPrimGen -> 10, + AndDoPrimGen -> 10, + OrDoPrimGen -> 10, + XorDoPrimGen -> 10, + AndrDoPrimGen -> 10, + OrrDoPrimGen -> 10, + XorrDoPrimGen -> 10, + BitsDoPrimGen -> 10, + HeadDoPrimGen -> 10, + TailDoPrimGen -> 10, + MuxGen -> 10 + ) + ) +) + @RunWith(classOf[JQF]) class FirrtlEquivalenceTests { private val lowFirrtlCompiler = new LowFirrtlCompiler() @@ -103,8 +131,7 @@ class FirrtlEquivalenceTests { } private val baseTestDir = new File("fuzzer/test_run_dir") - @Fuzz - def compileSingleModule(@From(value = classOf[FirrtlSingleModuleGenerator]) c: Circuit) = { + private def runTest(c: Circuit, referenceCompiler: TransformManager, customCompiler: TransformManager) = { val testDir = new File(baseTestDir, f"${c.hashCode}%08x") testDir.mkdirs() val fileWriter = new FileWriter(new File(testDir, s"${c.main}.fir")) @@ -113,9 +140,9 @@ class FirrtlEquivalenceTests { val passed = try { FirrtlEquivalenceTestUtils.firrtlEquivalenceTestPass( circuit = c, - referenceCompiler = new TransformManager(VerilogMinimumOptimized), + referenceCompiler = referenceCompiler, referenceAnnos = Seq(), - customCompiler = new TransformManager(VerilogOptimized), + customCompiler = customCompiler, customAnnos = Seq(), testDir = testDir ) @@ -131,4 +158,22 @@ class FirrtlEquivalenceTests { s"not equivalent to reference compiler on input ${testDir}:\n${c.serialize}\n", false) } } + + @Fuzz + def testOptimized(@From(value = classOf[FirrtlCompileCircuitGenerator]) c: Circuit) = { + runTest( + c = c, + referenceCompiler = new TransformManager(VerilogMinimumOptimized), + customCompiler = new TransformManager(VerilogOptimized) + ) + } + + @Fuzz + def testInlineBooleanExpressions(@From(value = classOf[InlineBooleanExprsCircuitGenerator]) c: Circuit) = { + runTest( + c = c, + referenceCompiler = new TransformManager(VerilogMinimumOptimized), + customCompiler = new TransformManager(VerilogMinimumOptimized :+ Dependency[InlineBooleanExpressions]) + ) + } } -- cgit v1.2.3