From 8358725dbb863d19d8123c72b8d89895d9c1324b Mon Sep 17 00:00:00 2001 From: Mike Urbach Date: Thu, 13 Oct 2022 12:07:20 -0600 Subject: [PATCH] [SV] Add feature flags to new SVExtractTestCode features. (#4094) These new additions are both fairly significant departures from past behavior, so add an ability to disable them. They remain enabled by default. The new flags are plumbed out to firtool flags so they can be disabled from firtool, and a test is added that this behavior can be controlled from firtool. --- include/circt/Dialect/SV/SVPasses.h | 4 +- include/circt/Dialect/SV/SVPasses.td | 6 ++ .../SV/Transforms/SVExtractTestCode.cpp | 18 ++++-- test/firtool/extract-test-code.fir | 57 +++++++++++++++++++ tools/firtool/firtool.cpp | 13 ++++- 5 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 test/firtool/extract-test-code.fir diff --git a/include/circt/Dialect/SV/SVPasses.h b/include/circt/Dialect/SV/SVPasses.h index 6084319784f7..bac54e229d62 100644 --- a/include/circt/Dialect/SV/SVPasses.h +++ b/include/circt/Dialect/SV/SVPasses.h @@ -29,7 +29,9 @@ std::unique_ptr createHWMemSimImplPass(bool replSeqMem = false, bool ignoreReadEnableMem = false, bool stripMuxPragmas = false); -std::unique_ptr createSVExtractTestCodePass(); +std::unique_ptr +createSVExtractTestCodePass(bool disableInstanceExtraction = false, + bool disableModuleInlining = false); std::unique_ptr createHWExportModuleHierarchyPass(llvm::Optional directory = {}); /// Generate the code for registering passes. diff --git a/include/circt/Dialect/SV/SVPasses.td b/include/circt/Dialect/SV/SVPasses.td index 4b84e691f2d1..5e71b1c66ac6 100644 --- a/include/circt/Dialect/SV/SVPasses.td +++ b/include/circt/Dialect/SV/SVPasses.td @@ -114,6 +114,12 @@ def SVExtractTestCode : Pass<"sv-extract-test-code", "ModuleOp"> { let constructor = "circt::sv::createSVExtractTestCodePass()"; let dependentDialects = ["circt::sv::SVDialect"]; + let options = [ + Option<"disableInstanceExtraction", "disable-instance-extraction", "bool", + "false", "Disable extracting instances only that feed test code">, + Option<"disableModuleInlining", "disable-module-inlining", "bool", + "false", "Disable inlining modules that only feed test code"> + ]; let statistics = [ Statistic<"numOpsExtracted", "num-ops-extracted", "Number of ops extracted">, Statistic<"numOpsErased", "num-ops-erased", "Number of ops erased"> diff --git a/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp b/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp index 81c5ac9b1d64..35713cb37ba1 100644 --- a/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp +++ b/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp @@ -448,6 +448,11 @@ namespace { struct SVExtractTestCodeImplPass : public SVExtractTestCodeBase { + SVExtractTestCodeImplPass(bool disableInstanceExtraction, + bool disableModuleInlining) { + this->disableInstanceExtraction = disableInstanceExtraction; + this->disableModuleInlining = disableModuleInlining; + } void runOnOperation() override; private: @@ -490,7 +495,9 @@ struct SVExtractTestCodeImplPass // Find instances that directly feed the clone set, and add them if // possible. - addInstancesToCloneSet(inputs, opsToClone, opsToErase, extractedInstances); + if (!disableInstanceExtraction) + addInstancesToCloneSet(inputs, opsToClone, opsToErase, + extractedInstances); numOpsExtracted += opsToClone.size(); numOpsErased += opsToErase.size(); @@ -629,7 +636,7 @@ void SVExtractTestCodeImplPass::runOnOperation() { coverBindFile, bindTable, opsToErase); // Inline any modules that only have inputs for test code. - if (anyThingExtracted) + if (!disableModuleInlining && anyThingExtracted) inlineInputOnly(rtlmod, instanceGraph, bindTable, opsToErase); // Erase any instances that were extracted, and their forward dataflow. @@ -661,6 +668,9 @@ void SVExtractTestCodeImplPass::runOnOperation() { top->removeAttr("firrtl.extract.testbench"); } -std::unique_ptr circt::sv::createSVExtractTestCodePass() { - return std::make_unique(); +std::unique_ptr +circt::sv::createSVExtractTestCodePass(bool disableInstanceExtraction, + bool disableModuleInlining) { + return std::make_unique(disableInstanceExtraction, + disableModuleInlining); } diff --git a/test/firtool/extract-test-code.fir b/test/firtool/extract-test-code.fir new file mode 100644 index 000000000000..ea47318b8be5 --- /dev/null +++ b/test/firtool/extract-test-code.fir @@ -0,0 +1,57 @@ +; RUN: firtool %s -extract-test-code | FileCheck %s +; RUN: firtool %s -extract-test-code -etc-disable-instance-extraction | FileCheck %s --check-prefix=DISABLEINSTANCE +; RUN: firtool %s -extract-test-code -etc-disable-module-inlining | FileCheck %s --check-prefix=DISABLEMODULE + +circuit Top: + module Foo: + input a : UInt<1> + output b : UInt<1> + b <= a + + ; Ensure foo is extracted by default. + ; CHECK-LABEL: module InstanceExtracted_assert( + ; CHECK: Foo foo + + ; Ensure foo is not extracted when disabled. + ; DISABLEINSTANCE-LABEL: module InstanceExtracted( + ; DISABLEINSTANCE: Foo foo + + module InstanceExtracted: + input clock : Clock + input cond : UInt<1> + output out : UInt<1> + + wire b : UInt<1> + inst foo of Foo + foo.a <= cond + b <= foo.b + + assert(clock, cond, b, "Some assertion") + + out <= cond + + ; Ensure InputOnly is inlined by default. + ; CHECK-NOT: module InputOnly( + + ; Ensure InputOnly is not inlined when disabled. + ; DISABLEMODULE-LABEL: module InputOnly( + + module InputOnly: + input clock : Clock + input cond : UInt<1> + assert(clock, cond, cond, "Some assertion") + + module Top: + input clock : Clock + input cond : UInt<1> + output out : UInt<1> + + inst instance_extracted of InstanceExtracted + instance_extracted.clock <= clock + instance_extracted.cond <= cond + out <= instance_extracted.out + + inst input_only of InputOnly + input_only.clock <= clock + input_only.cond <= cond + diff --git a/tools/firtool/firtool.cpp b/tools/firtool/firtool.cpp index c3d6fc1f37ae..0990cb0b9ee6 100644 --- a/tools/firtool/firtool.cpp +++ b/tools/firtool/firtool.cpp @@ -312,6 +312,16 @@ static cl::opt disableInferRW("disable-infer-rw", cl::init(false), cl::Hidden, cl::cat(mainCategory)); +static cl::opt etcDisableInstanceExtraction( + "etc-disable-instance-extraction", + cl::desc("Disable extracting instances only that feed test code"), + cl::init(false), cl::cat(mainCategory)); + +static cl::opt etcDisableModuleInlining( + "etc-disable-module-inlining", + cl::desc("Disable inlining modules that only feed test code"), + cl::init(false), cl::cat(mainCategory)); + enum OutputFormatKind { OutputParseOnly, OutputIRFir, @@ -751,7 +761,8 @@ processBuffer(MLIRContext &context, TimingScope &ts, llvm::SourceMgr &sourceMgr, stripMuxPragmas)); if (extractTestCode) - pm.addPass(sv::createSVExtractTestCodePass()); + pm.addPass(sv::createSVExtractTestCodePass(etcDisableInstanceExtraction, + etcDisableModuleInlining)); // If enabled, run the optimizer. if (!disableOptimization) {