18#include "mlir/Analysis/TopologicalSortUtils.h" 
   19#include "mlir/Dialect/Func/IR/FuncOps.h" 
   20#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h" 
   21#include "mlir/Dialect/LLVMIR/LLVMDialect.h" 
   22#include "mlir/IR/Builders.h" 
   23#include "mlir/IR/Location.h" 
   24#include "mlir/IR/SymbolTable.h" 
   25#include "llvm/Support/LogicalResult.h" 
   32#define GEN_PASS_DEF_LOWERTOBMC 
   33#include "circt/Tools/circt-bmc/Passes.h.inc" 
   41struct LowerToBMCPass : 
public circt::impl::LowerToBMCBase<LowerToBMCPass> {
 
   42  using LowerToBMCBase::LowerToBMCBase;
 
   43  void runOnOperation() 
override;
 
   47void LowerToBMCPass::runOnOperation() {
 
   50  auto moduleOp = getOperation();
 
   53    moduleOp.emitError(
"hw.module named '") << topModule << 
"' not found";
 
   54    return signalPassFailure();
 
   58  if (hwModule.getOps<verif::AssertOp>().empty() &&
 
   59      hwModule.getOps<hw::InstanceOp>().empty()) {
 
   60    hwModule.emitError(
"no property provided to check in module");
 
   61    return signalPassFailure();
 
   64  if (!sortTopologically(&hwModule.getBodyRegion().front())) {
 
   65    hwModule->emitError(
"could not resolve cycles in module");
 
   66    return signalPassFailure();
 
   69  if (bound < ignoreAssertionsUntil) {
 
   71        "number of ignored cycles must be less than or equal to bound");
 
   72    return signalPassFailure();
 
   76  auto *ctx = &getContext();
 
   77  OpBuilder builder(ctx);
 
   78  Location loc = moduleOp->getLoc();
 
   79  builder.setInsertionPointToEnd(moduleOp.getBody());
 
   80  auto ptrTy = LLVM::LLVMPointerType::get(ctx);
 
   81  auto voidTy = LLVM::LLVMVoidType::get(ctx);
 
   85      LLVM::lookupOrCreateFn(builder, moduleOp, 
"printf", ptrTy, voidTy, 
true);
 
   86  if (failed(printfFunc)) {
 
   87    moduleOp->emitError(
"failed to lookup or create printf");
 
   88    return signalPassFailure();
 
   92  auto entryFunc = func::FuncOp::create(builder, loc, topModule,
 
   93                                        builder.getFunctionType({}, {}));
 
   94  builder.createBlock(&entryFunc.getBody());
 
   97    OpBuilder::InsertionGuard guard(builder);
 
   98    auto *terminator = hwModule.getBody().front().getTerminator();
 
   99    builder.setInsertionPoint(terminator);
 
  100    verif::YieldOp::create(builder, loc, terminator->getOperands());
 
  106  verif::BoundedModelCheckingOp bmcOp;
 
  107  auto numRegs = hwModule->getAttrOfType<IntegerAttr>(
"num_regs");
 
  108  auto initialValues = hwModule->getAttrOfType<ArrayAttr>(
"initial_values");
 
  109  if (numRegs && initialValues) {
 
  110    for (
auto value : initialValues) {
 
  111      if (!isa<IntegerAttr, UnitAttr>(value)) {
 
  112        hwModule->emitError(
"initial_values attribute must contain only " 
  113                            "integer or unit attributes");
 
  114        return signalPassFailure();
 
  117    bmcOp = verif::BoundedModelCheckingOp::create(
 
  118        builder, loc, risingClocksOnly ? bound : 2 * bound,
 
  119        cast<IntegerAttr>(numRegs).getValue().getZExtValue(), initialValues);
 
  122    if (ignoreAssertionsUntil)
 
  123      bmcOp->setAttr(
"ignore_asserts_until",
 
  124                     builder.getI32IntegerAttr(
 
  125                         risingClocksOnly ? ignoreAssertionsUntil
 
  126                                          : 2 * ignoreAssertionsUntil));
 
  128    hwModule->emitOpError(
"no num_regs or initial_values attribute found - " 
  129                          "please run externalize " 
  130                          "registers pass first");
 
  131    return signalPassFailure();
 
  138  for (
auto input : hwModule.getInputTypes()) {
 
  139    if (isa<seq::ClockType>(input)) {
 
  141        hwModule.emitError(
"designs with multiple clocks not yet supported");
 
  142        return signalPassFailure();
 
  146    if (
auto hwStruct = dyn_cast<hw::StructType>(input)) {
 
  147      for (
auto field : hwStruct.getElements()) {
 
  148        if (isa<seq::ClockType>(field.type)) {
 
  151                "designs with multiple clocks not yet supported");
 
  152            return signalPassFailure();
 
  160    OpBuilder::InsertionGuard guard(builder);
 
  163    auto *initBlock = builder.createBlock(&bmcOp.getInit());
 
  164    builder.setInsertionPointToStart(initBlock);
 
  167                                            risingClocksOnly ? 1 : 0);
 
  168      auto toClk = seq::ToClockOp::create(builder, loc, initVal);
 
  169      verif::YieldOp::create(builder, loc, ValueRange{toClk});
 
  171      verif::YieldOp::create(builder, loc, ValueRange{});
 
  175    auto *loopBlock = builder.createBlock(&bmcOp.getLoop());
 
  176    builder.setInsertionPointToStart(loopBlock);
 
  178      loopBlock->addArgument(seq::ClockType::get(ctx), loc);
 
  179      if (risingClocksOnly) {
 
  181        verif::YieldOp::create(builder, loc,
 
  182                               ValueRange{loopBlock->getArgument(0)});
 
  185            seq::FromClockOp::create(builder, loc, loopBlock->getArgument(0));
 
  188        auto nClk = comb::XorOp::create(builder, loc, fromClk, cNeg1);
 
  189        auto toClk = seq::ToClockOp::create(builder, loc, nClk);
 
  191        verif::YieldOp::create(builder, loc, ValueRange{toClk});
 
  194      verif::YieldOp::create(builder, loc, ValueRange{});
 
  197  bmcOp.getCircuit().takeBody(hwModule.getBody());
 
  201  auto createUniqueStringGlobal = [&](StringRef str) -> FailureOr<Value> {
 
  202    Location loc = moduleOp.getLoc();
 
  204    OpBuilder b = OpBuilder::atBlockEnd(moduleOp.getBody());
 
  205    auto arrayTy = LLVM::LLVMArrayType::get(b.getI8Type(), str.size() + 1);
 
  206    auto global = LLVM::GlobalOp::create(
 
  207        b, loc, arrayTy, 
true, LLVM::linkage::Linkage::Private,
 
  209        StringAttr::get(b.getContext(), Twine(str).
concat(Twine(
'\00'))));
 
  210    SymbolTable symTable(moduleOp);
 
  211    if (failed(symTable.renameToUnique(global, {&symTable}))) {
 
  212      return mlir::failure();
 
  216        LLVM::AddressOfOp::create(builder, loc, global)->getResult(0));
 
  219  auto successStrAddr =
 
  220      createUniqueStringGlobal(
"Bound reached with no violations!\n");
 
  221  auto failureStrAddr =
 
  222      createUniqueStringGlobal(
"Assertion can be violated!\n");
 
  224  if (failed(successStrAddr) || failed(failureStrAddr)) {
 
  225    moduleOp->emitOpError(
"could not create result message strings");
 
  226    return signalPassFailure();
 
  230      LLVM::SelectOp::create(builder, loc, bmcOp.getResult(),
 
  231                             successStrAddr.value(), failureStrAddr.value());
 
  232  LLVM::CallOp::create(builder, loc, printfFunc.value(),
 
  233                       ValueRange{formatString});
 
  234  func::ReturnOp::create(builder, loc);
 
  236  if (insertMainFunc) {
 
  237    builder.setInsertionPointToEnd(getOperation().getBody());
 
  238    Type i32Ty = builder.getI32Type();
 
  239    auto mainFunc = func::FuncOp::create(
 
  240        builder, loc, 
"main", builder.getFunctionType({i32Ty, ptrTy}, {i32Ty}));
 
  241    builder.createBlock(&mainFunc.getBody(), {}, {i32Ty, ptrTy}, {loc, loc});
 
  242    func::CallOp::create(builder, loc, entryFunc, ValueRange{});
 
  244    Value constZero = LLVM::ConstantOp::create(builder, loc, i32Ty, 0);
 
  245    func::ReturnOp::create(builder, loc, constZero);
 
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
 
A namespace that is used to store existing names and generate new names in some scope within the IR.
 
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.