Skip to content

Commit

Permalink
[circt-test] Add support for contracts
Browse files Browse the repository at this point in the history
Add the `LowerContracts` or `StripContracts` pass to the circt-test
pipeline in order to leverage contracts during formal verification. To
make this work, circ-test has to run a preparatory pass pipeline on the
input MLIR, and pass the result as input to the MLIR runners instead of
the original file.

Also add an `--ir` option to dump the IR after the preparatory passes.
  • Loading branch information
fabianschuiki committed Feb 4, 2025
1 parent e78f330 commit ac03265
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 7 deletions.
20 changes: 20 additions & 0 deletions test/circt-test/pipeline.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: circt-test --ir %s | FileCheck %s
// RUN: circt-test --ir --ignore-contracts %s | FileCheck %s --check-prefix=NOCONTRACT

// CHECK: hw.module @Foo
// CHECK-NOT: verif.contract
// CHECK: verif.formal @Foo_CheckContract

// NOCONTRACT: hw.module @Foo
// NOCONTRACT-NOT: verif.contract
// NOCONTRACT-NOT: verif.formal @Foo

hw.module @Foo(in %a: i1, in %b: i1, out z: i1) {
%0 = comb.xor %a, %b : i1
%1 = verif.contract %0 : i1 {
%2 = comb.add %a, %b : i1
%3 = comb.icmp eq %1, %2 : i1
verif.ensure %3 : i1
}
hw.output %1 : i1
}
64 changes: 57 additions & 7 deletions tools/circt-test/circt-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "circt/Dialect/Verif/VerifOps.h"
#include "circt/Dialect/Verif/VerifPasses.h"
#include "circt/Support/JSON.h"
#include "circt/Support/Passes.h"
#include "circt/Support/Version.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
Expand All @@ -35,6 +36,7 @@
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/FileUtilities.h"
#include "mlir/Support/ToolUtilities.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
Expand Down Expand Up @@ -82,15 +84,23 @@ struct Options {
"d", cl::desc("Result directory (default `.circt-test`)"),
cl::value_desc("dir"), cl::init(".circt-test"), cl::cat(cat)};

cl::opt<bool> verifyPasses{
"verify-each",
cl::desc("Run the verifier after each transformation pass"),
cl::init(true), cl::cat(cat)};

cl::list<std::string> runners{"r", cl::desc("Use a specific set of runners"),
cl::value_desc("name"),
cl::MiscFlags::CommaSeparated, cl::cat(cat)};

cl::opt<bool> ignoreContracts{
"ignore-contracts",
cl::desc("Do not use contracts to simplify and parallelize tests"),
cl::init(false), cl::cat(cat)};

cl::opt<bool> emitIR{"ir", cl::desc("Emit IR after initial lowering"),
cl::init(false), cl::cat(cat)};

cl::opt<bool> verifyPasses{
"verify-each",
cl::desc("Run the verifier after each transformation pass"),
cl::init(true), cl::Hidden, cl::cat(cat)};

cl::opt<bool> verifyDiagnostics{
"verify-diagnostics",
cl::desc("Check that emitted diagnostics match expected-* lines on the "
Expand Down Expand Up @@ -404,10 +414,38 @@ static LogicalResult listTests(TestSuite &suite) {
static LogicalResult executeWithHandler(MLIRContext *context,
RunnerSuite &runnerSuite,
SourceMgr &srcMgr) {
std::string errorMessage;
auto module = parseSourceFile<ModuleOp>(srcMgr, context);
if (!module)
return failure();

// Preprocess the input.
{
PassManager pm(context);
pm.enableVerifier(opts.verifyPasses);
if (opts.ignoreContracts)
pm.addPass(verif::createStripContractsPass());
else
pm.addPass(verif::createLowerContractsPass());
pm.addNestedPass<hw::HWModuleOp>(verif::createSimplifyAssumeEqPass());
pm.addPass(createCSEPass());
pm.addPass(createSimpleCanonicalizerPass());
if (failed(pm.run(*module)))
return failure();
}

// Emit the IR and exit if requested.
if (opts.emitIR) {
auto output = openOutputFile(opts.outputFilename, &errorMessage);
if (!output) {
WithColor::error() << errorMessage << "\n";
return failure();
}
module->print(output->os());
output->keep();
return success();
}

// Discover all tests in the input.
TestSuite suite(context, opts.listIgnored);
if (failed(suite.discoverInModule(*module)))
Expand All @@ -428,10 +466,21 @@ static LogicalResult executeWithHandler(MLIRContext *context,
return failure();
}

// Generate the MLIR output.
SmallString<128> mlirPath(opts.resultDir);
llvm::sys::path::append(mlirPath, "design.mlir");
auto mlirFile = openOutputFile(mlirPath, &errorMessage);
if (!mlirFile) {
WithColor::error() << errorMessage << "\n";
return failure();
}
module->print(mlirFile->os());
mlirFile->os().flush();
mlirFile->keep();

// Open the Verilog file for writing.
SmallString<128> verilogPath(opts.resultDir);
llvm::sys::path::append(verilogPath, "design.sv");
std::string errorMessage;
auto verilogFile = openOutputFile(verilogPath, &errorMessage);
if (!verilogFile) {
WithColor::error() << errorMessage << "\n";
Expand All @@ -448,6 +497,7 @@ static LogicalResult executeWithHandler(MLIRContext *context,
pm.addPass(createExportVerilogPass(verilogFile->os()));
if (failed(pm.run(*module)))
return failure();
verilogFile->os().flush();
verilogFile->keep();

// Run the tests.
Expand Down Expand Up @@ -502,7 +552,7 @@ static LogicalResult executeWithHandler(MLIRContext *context,
SmallVector<StringRef> args;
args.push_back(runner->binary);
if (runner->readsMLIR)
args.push_back(opts.inputFilename);
args.push_back(mlirPath);
else
args.push_back(verilogPath);
args.push_back("-t");
Expand Down

0 comments on commit ac03265

Please sign in to comment.