15#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
16#include "mlir/Dialect/Arith/IR/Arith.h"
17#include "mlir/Dialect/Func/IR/FuncOps.h"
18#include "mlir/Dialect/SCF/IR/SCF.h"
19#include "mlir/Dialect/SMT/IR/SMTOps.h"
20#include "mlir/Dialect/SMT/IR/SMTTypes.h"
21#include "mlir/IR/ValueRange.h"
22#include "mlir/Pass/Pass.h"
23#include "mlir/Transforms/DialectConversion.h"
24#include "llvm/ADT/DenseMap.h"
25#include "llvm/ADT/SmallVector.h"
28#define GEN_PASS_DEF_CONVERTVERIFTOSMT
29#include "circt/Conversion/Passes.h.inc"
43 for (
auto arg : block.getArguments()) {
44 for (
auto *user : arg.getUsers()) {
45 auto varOp = dyn_cast<debug::VariableOp>(user);
48 auto name = varOp.getNameAttr();
49 if (name.getValue().empty())
51 debugNames.try_emplace(arg.getArgNumber(), name);
58static void attachDebugVariables(
59 OpBuilder &builder, Location loc, ArrayRef<Type> originalTypes,
62 for (
auto [argIndex, value] :
llvm::enumerate(values)) {
63 if (isa<seq::ClockType>(originalTypes[argIndex]))
65 auto it = debugNames.find(argIndex);
66 if (it == debugNames.end())
68 debug::VariableOp::create(builder, loc, it->second, value,
73static void attachTraceRecords(
74 OpBuilder &builder, Location loc, Value step, ArrayRef<Type> originalTypes,
77 for (
auto [argIndex, value] :
llvm::enumerate(values)) {
78 if (isa<seq::ClockType>(originalTypes[argIndex]))
80 auto it = debugNames.find(argIndex);
81 if (it == debugNames.end())
83 verif::BMCTraceOp::create(builder, loc, step, it->second, value);
93 matchAndRewrite(verif::AssertOp op, OpAdaptor adaptor,
94 ConversionPatternRewriter &rewriter)
const override {
95 Value cond = typeConverter->materializeTargetConversion(
96 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
97 adaptor.getProperty());
98 Value notCond = smt::NotOp::create(rewriter, op.getLoc(), cond);
99 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, notCond);
109 matchAndRewrite(verif::AssumeOp op, OpAdaptor adaptor,
110 ConversionPatternRewriter &rewriter)
const override {
111 Value cond = typeConverter->materializeTargetConversion(
112 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
113 adaptor.getProperty());
114 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, cond);
119template <
typename OpTy>
124 using ConversionPattern::typeConverter;
126 createOutputsDifferentOps(Operation *firstOutputs, Operation *secondOutputs,
127 Location &loc, ConversionPatternRewriter &rewriter,
128 SmallVectorImpl<Value> &outputsDifferent)
const {
133 for (
auto [out1, out2] :
134 llvm::zip(firstOutputs->getOperands(), secondOutputs->getOperands())) {
135 Value o1 = typeConverter->materializeTargetConversion(
136 rewriter, loc, typeConverter->convertType(out1.getType()), out1);
137 Value o2 = typeConverter->materializeTargetConversion(
138 rewriter, loc, typeConverter->convertType(out1.getType()), out2);
139 outputsDifferent.emplace_back(
140 smt::DistinctOp::create(rewriter, loc, o1, o2));
144 void replaceOpWithSatCheck(OpTy &op, Location &loc,
145 ConversionPatternRewriter &rewriter,
146 smt::SolverOp &solver)
const {
151 if (op.getNumResults() == 0) {
152 auto checkOp = smt::CheckOp::create(rewriter, loc, TypeRange{});
153 rewriter.createBlock(&checkOp.getSatRegion());
154 smt::YieldOp::create(rewriter, loc);
155 rewriter.createBlock(&checkOp.getUnknownRegion());
156 smt::YieldOp::create(rewriter, loc);
157 rewriter.createBlock(&checkOp.getUnsatRegion());
158 smt::YieldOp::create(rewriter, loc);
159 rewriter.setInsertionPointAfter(checkOp);
160 smt::YieldOp::create(rewriter, loc);
163 rewriter.eraseOp(op);
166 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
168 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
169 auto checkOp = smt::CheckOp::create(rewriter, loc, rewriter.getI1Type());
170 rewriter.createBlock(&checkOp.getSatRegion());
171 smt::YieldOp::create(rewriter, loc, falseVal);
172 rewriter.createBlock(&checkOp.getUnknownRegion());
173 smt::YieldOp::create(rewriter, loc, falseVal);
174 rewriter.createBlock(&checkOp.getUnsatRegion());
175 smt::YieldOp::create(rewriter, loc, trueVal);
176 rewriter.setInsertionPointAfter(checkOp);
177 smt::YieldOp::create(rewriter, loc, checkOp->getResults());
179 rewriter.replaceOp(op, solver->getResults());
189struct LogicEquivalenceCheckingOpConversion
190 : CircuitRelationCheckOpConversion<verif::LogicEquivalenceCheckingOp> {
191 using CircuitRelationCheckOpConversion<
192 verif::LogicEquivalenceCheckingOp>::CircuitRelationCheckOpConversion;
195 matchAndRewrite(verif::LogicEquivalenceCheckingOp op, OpAdaptor adaptor,
196 ConversionPatternRewriter &rewriter)
const override {
197 Location loc = op.getLoc();
198 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
199 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
201 auto hasNoResult = op.getNumResults() == 0;
203 if (firstOutputs->getNumOperands() == 0) {
206 rewriter.eraseOp(op);
208 Value trueVal = arith::ConstantOp::create(rewriter, loc,
209 rewriter.getBoolAttr(
true));
210 rewriter.replaceOp(op, trueVal);
217 smt::SolverOp solver;
219 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
221 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
223 rewriter.createBlock(&solver.getBodyRegion());
226 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
229 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
234 SmallVector<Value> inputs;
235 for (
auto arg : adaptor.getFirstCircuit().getArguments())
236 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
245 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), solver.getBody(),
247 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
249 rewriter.setInsertionPointToEnd(solver.getBody());
252 SmallVector<Value> outputsDifferent;
253 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
256 rewriter.eraseOp(firstOutputs);
257 rewriter.eraseOp(secondOutputs);
260 if (outputsDifferent.size() == 1)
261 toAssert = outputsDifferent[0];
263 toAssert = smt::OrOp::create(rewriter, loc, outputsDifferent);
265 smt::AssertOp::create(rewriter, loc, toAssert);
268 replaceOpWithSatCheck(op, loc, rewriter, solver);
273struct RefinementCheckingOpConversion
274 : CircuitRelationCheckOpConversion<verif::RefinementCheckingOp> {
275 using CircuitRelationCheckOpConversion<
276 verif::RefinementCheckingOp>::CircuitRelationCheckOpConversion;
279 matchAndRewrite(verif::RefinementCheckingOp op, OpAdaptor adaptor,
280 ConversionPatternRewriter &rewriter)
const override {
284 SmallVector<Value> srcNonDetValues;
286 for (
auto ndOp : op.getFirstCircuit().getOps<smt::DeclareFunOp>()) {
287 if (!isa<smt::IntType, smt::BoolType, smt::BitVectorType>(
289 ndOp.emitError(
"Uninterpreted function of non-primitive type cannot be "
293 srcNonDetValues.push_back(ndOp.getResult());
298 if (srcNonDetValues.empty()) {
302 auto eqOp = verif::LogicEquivalenceCheckingOp::create(
303 rewriter, op.getLoc(), op.getNumResults() != 0);
304 rewriter.moveBlockBefore(&op.getFirstCircuit().front(),
305 &eqOp.getFirstCircuit(),
306 eqOp.getFirstCircuit().end());
307 rewriter.moveBlockBefore(&op.getSecondCircuit().front(),
308 &eqOp.getSecondCircuit(),
309 eqOp.getSecondCircuit().end());
310 rewriter.replaceOp(op, eqOp);
314 Location loc = op.getLoc();
315 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
316 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
318 auto hasNoResult = op.getNumResults() == 0;
320 if (firstOutputs->getNumOperands() == 0) {
323 rewriter.eraseOp(op);
325 Value trueVal = arith::ConstantOp::create(rewriter, loc,
326 rewriter.getBoolAttr(
true));
327 rewriter.replaceOp(op, trueVal);
334 smt::SolverOp solver;
336 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
338 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
340 rewriter.createBlock(&solver.getBodyRegion());
343 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
346 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
351 SmallVector<Value> inputs;
352 for (
auto arg : adaptor.getFirstCircuit().getArguments())
353 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
356 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
358 rewriter.setInsertionPointToEnd(solver.getBody());
362 auto forallOp = smt::ForallOp::create(
363 rewriter, op.getLoc(), TypeRange(srcNonDetValues),
364 [&](OpBuilder &builder,
auto, ValueRange args) -> Value {
366 Block *body = builder.getBlock();
367 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), body,
372 for (
auto [freeVar, boundVar] :
llvm::zip(srcNonDetValues, args))
373 rewriter.replaceOp(freeVar.getDefiningOp(), boundVar);
376 rewriter.setInsertionPointToEnd(body);
377 SmallVector<Value> outputsDifferent;
378 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
380 if (outputsDifferent.size() == 1)
381 return outputsDifferent[0];
383 return rewriter.createOrFold<smt::OrOp>(loc, outputsDifferent);
386 rewriter.eraseOp(firstOutputs);
387 rewriter.eraseOp(secondOutputs);
390 rewriter.setInsertionPointAfter(forallOp);
391 smt::AssertOp::create(rewriter, op.getLoc(), forallOp.getResult());
394 replaceOpWithSatCheck(op, loc, rewriter, solver);
401struct VerifBoundedModelCheckingOpConversion
405 VerifBoundedModelCheckingOpConversion(
407 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps)
409 risingClocksOnly(risingClocksOnly),
410 propertylessBMCOps(propertylessBMCOps) {}
412 matchAndRewrite(verif::BoundedModelCheckingOp op, OpAdaptor adaptor,
413 ConversionPatternRewriter &rewriter)
const override {
414 Location loc = op.getLoc();
416 if (std::find(propertylessBMCOps.begin(), propertylessBMCOps.end(), op) !=
417 propertylessBMCOps.end()) {
422 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
423 rewriter.replaceOp(op, trueVal);
427 SmallVector<Type> oldLoopInputTy(op.getLoop().getArgumentTypes());
428 SmallVector<Type> oldCircuitInputTy(op.getCircuit().getArgumentTypes());
432 SmallVector<Type> loopInputTy, circuitInputTy, initOutputTy,
434 if (failed(typeConverter->convertTypes(oldLoopInputTy, loopInputTy)))
436 if (failed(typeConverter->convertTypes(oldCircuitInputTy, circuitInputTy)))
438 if (failed(typeConverter->convertTypes(
439 op.getInit().front().back().getOperandTypes(), initOutputTy)))
441 if (failed(typeConverter->convertTypes(
442 op.getCircuit().front().back().getOperandTypes(), circuitOutputTy)))
444 auto debugNames = collectDebugNames(op.getCircuit().front());
445 if (failed(rewriter.convertRegionTypes(&op.getInit(), *typeConverter)))
447 if (failed(rewriter.convertRegionTypes(&op.getLoop(), *typeConverter)))
449 if (failed(rewriter.convertRegionTypes(&op.getCircuit(), *typeConverter)))
452 unsigned numRegs = op.getNumRegs();
453 auto initialValues = op.getInitialValues();
455 auto initFuncTy = rewriter.getFunctionType({}, initOutputTy);
458 auto loopFuncTy = rewriter.getFunctionType(loopInputTy, initOutputTy);
460 rewriter.getFunctionType(circuitInputTy, circuitOutputTy);
462 func::FuncOp initFuncOp, loopFuncOp, circuitFuncOp;
465 OpBuilder::InsertionGuard guard(rewriter);
466 rewriter.setInsertionPointToEnd(
467 op->getParentOfType<ModuleOp>().getBody());
468 initFuncOp = func::FuncOp::create(rewriter, loc,
469 names.newName(
"bmc_init"), initFuncTy);
470 rewriter.inlineRegionBefore(op.getInit(), initFuncOp.getFunctionBody(),
472 loopFuncOp = func::FuncOp::create(rewriter, loc,
473 names.newName(
"bmc_loop"), loopFuncTy);
474 rewriter.inlineRegionBefore(op.getLoop(), loopFuncOp.getFunctionBody(),
476 circuitFuncOp = func::FuncOp::create(
477 rewriter, loc, names.newName(
"bmc_circuit"), circuitFuncTy);
478 rewriter.inlineRegionBefore(op.getCircuit(),
479 circuitFuncOp.getFunctionBody(),
480 circuitFuncOp.end());
481 auto funcOps = {&initFuncOp, &loopFuncOp, &circuitFuncOp};
483 auto outputTys = {initOutputTy, initOutputTy, circuitOutputTy};
484 for (
auto [funcOp, outputTy] :
llvm::zip(funcOps, outputTys)) {
485 auto operands = funcOp->getBody().front().back().getOperands();
486 rewriter.eraseOp(&funcOp->getFunctionBody().front().back());
487 rewriter.setInsertionPointToEnd(&funcOp->getBody().front());
488 SmallVector<Value> toReturn;
489 for (
unsigned i = 0; i < outputTy.size(); ++i)
490 toReturn.push_back(typeConverter->materializeTargetConversion(
491 rewriter, loc, outputTy[i], operands[i]));
492 func::ReturnOp::create(rewriter, loc, toReturn);
496 auto solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
498 rewriter.createBlock(&solver.getBodyRegion());
501 ValueRange initVals =
502 func::CallOp::create(rewriter, loc, initFuncOp)->getResults();
505 smt::PushOp::create(rewriter, loc, 1);
510 size_t initIndex = 0;
511 size_t regStartIdx = oldCircuitInputTy.size() - numRegs;
512 SmallVector<Value> inputDecls;
513 SmallVector<int> clockIndexes;
514 auto getNameAttr = [&](
unsigned argIndex,
bool isReg) {
515 if (
auto it = debugNames.find(argIndex); it != debugNames.end())
517 auto fallback = isReg ? (
"reg_" + Twine(argIndex - regStartIdx)).str()
518 : (
"input_" + Twine(argIndex)).str();
519 return rewriter.getStringAttr(fallback);
521 for (
auto [curIndex, oldTy, newTy] :
522 llvm::enumerate(oldCircuitInputTy, circuitInputTy)) {
523 if (isa<seq::ClockType>(oldTy)) {
524 inputDecls.push_back(initVals[initIndex++]);
525 clockIndexes.push_back(curIndex);
528 if (curIndex >= regStartIdx) {
529 auto initVal = initialValues[curIndex - regStartIdx];
530 if (
auto initIntAttr = dyn_cast<IntegerAttr>(initVal)) {
531 const auto &cstInt = initIntAttr.getValue();
532 assert(cstInt.getBitWidth() ==
533 cast<smt::BitVectorType>(newTy).getWidth() &&
534 "Width mismatch between initial value and target type");
535 inputDecls.push_back(
536 smt::BVConstantOp::create(rewriter, loc, cstInt));
540 inputDecls.push_back(smt::DeclareFunOp::create(
541 rewriter, loc, newTy,
542 getNameAttr(curIndex, curIndex >= regStartIdx)));
545 auto numStateArgs = initVals.size() - initIndex;
547 for (; initIndex < initVals.size(); ++initIndex)
548 inputDecls.push_back(initVals[initIndex]);
550 attachDebugVariables(
551 rewriter, loc, oldCircuitInputTy,
552 ValueRange(inputDecls).take_front(circuitFuncOp.getNumArguments()),
556 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
558 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(1));
560 arith::ConstantOp::create(rewriter, loc, adaptor.getBoundAttr());
562 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
564 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
565 inputDecls.push_back(constFalse);
570 auto forOp = scf::ForOp::create(
571 rewriter, loc, lowerBound, upperBound, step, inputDecls,
572 [&](OpBuilder &builder, Location loc, Value i, ValueRange iterArgs) {
573 attachDebugVariables(
574 builder, loc, oldCircuitInputTy,
575 iterArgs.take_front(circuitFuncOp.getNumArguments()), debugNames);
577 builder, loc, i, oldCircuitInputTy,
578 iterArgs.take_front(circuitFuncOp.getNumArguments()), debugNames);
581 smt::PopOp::create(builder, loc, 1);
582 smt::PushOp::create(builder, loc, 1);
585 ValueRange circuitCallOuts =
586 func::CallOp::create(
587 builder, loc, circuitFuncOp,
588 iterArgs.take_front(circuitFuncOp.getNumArguments()))
595 auto insideForPoint = builder.saveInsertionPoint();
599 auto ignoreAssertionsUntil =
600 op->getAttrOfType<IntegerAttr>(
"ignore_asserts_until");
601 if (ignoreAssertionsUntil) {
602 auto ignoreUntilConstant = arith::ConstantOp::create(
604 rewriter.getI32IntegerAttr(
605 ignoreAssertionsUntil.getValue().getZExtValue()));
607 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::ult,
608 i, ignoreUntilConstant);
609 auto ifShouldIgnore = scf::IfOp::create(
610 builder, loc, builder.getI1Type(), shouldIgnore,
true);
612 builder.setInsertionPointToEnd(
613 &ifShouldIgnore.getThenRegion().front());
614 scf::YieldOp::create(builder, loc, ValueRange(iterArgs.back()));
615 builder.setInsertionPointToEnd(
616 &ifShouldIgnore.getElseRegion().front());
617 yieldedValue = ifShouldIgnore.getResult(0);
621 smt::CheckOp::create(rewriter, loc, builder.getI1Type());
623 OpBuilder::InsertionGuard guard(builder);
624 builder.createBlock(&checkOp.getSatRegion());
625 smt::YieldOp::create(builder, loc, constTrue);
626 builder.createBlock(&checkOp.getUnknownRegion());
627 smt::YieldOp::create(builder, loc, constTrue);
628 builder.createBlock(&checkOp.getUnsatRegion());
629 smt::YieldOp::create(builder, loc, constFalse);
632 Value violated = arith::OrIOp::create(
633 builder, loc, checkOp.getResult(0), iterArgs.back());
637 if (ignoreAssertionsUntil) {
638 scf::YieldOp::create(builder, loc, violated);
640 violated = yieldedValue;
644 builder.restoreInsertionPoint(insideForPoint);
647 SmallVector<Value> loopCallInputs;
649 for (
auto index : clockIndexes)
650 loopCallInputs.push_back(iterArgs[index]);
652 for (
auto stateArg : iterArgs.drop_back().take_back(numStateArgs))
653 loopCallInputs.push_back(stateArg);
654 ValueRange loopVals =
655 func::CallOp::create(builder, loc, loopFuncOp, loopCallInputs)
658 size_t loopIndex = 0;
660 SmallVector<Value> newDecls;
661 for (
auto [inputIdx, oldTy, newTy] :
662 llvm::enumerate(TypeRange(oldCircuitInputTy).drop_back(numRegs),
663 TypeRange(circuitInputTy).drop_back(numRegs))) {
664 if (isa<seq::ClockType>(oldTy)) {
665 newDecls.push_back(loopVals[loopIndex++]);
667 newDecls.push_back(smt::DeclareFunOp::create(
668 builder, loc, newTy, getNameAttr(inputIdx,
false)));
676 if (clockIndexes.size() == 1) {
677 SmallVector<Value> regInputs = circuitCallOuts.take_back(numRegs);
678 if (risingClocksOnly) {
681 newDecls.append(regInputs);
683 auto clockIndex = clockIndexes[0];
684 auto oldClock = iterArgs[clockIndex];
687 auto newClock = loopVals[0];
688 auto oldClockLow = smt::BVNotOp::create(builder, loc, oldClock);
690 smt::BVAndOp::create(builder, loc, oldClockLow, newClock);
692 auto trueBV = smt::BVConstantOp::create(builder, loc, 1, 1);
694 smt::EqOp::create(builder, loc, isPosedgeBV, trueBV);
696 iterArgs.take_front(circuitFuncOp.getNumArguments())
698 SmallVector<Value> nextRegStates;
699 for (
auto [regState, regInput] :
700 llvm::zip(regStates, regInputs)) {
704 nextRegStates.push_back(smt::IteOp::create(
705 builder, loc, isPosedge, regInput, regState));
707 newDecls.append(nextRegStates);
712 for (; loopIndex < loopVals.size(); ++loopIndex)
713 newDecls.push_back(loopVals[loopIndex]);
715 attachDebugVariables(
716 builder, loc, oldCircuitInputTy,
717 ValueRange(newDecls).take_front(circuitFuncOp.getNumArguments()),
720 newDecls.push_back(violated);
722 scf::YieldOp::create(builder, loc, newDecls);
725 Value res = arith::XOrIOp::create(rewriter, loc, forOp->getResults().back(),
727 smt::YieldOp::create(rewriter, loc, res);
728 rewriter.replaceOp(op, solver.getResults());
733 bool risingClocksOnly;
734 SmallVectorImpl<Operation *> &propertylessBMCOps;
744struct ConvertVerifToSMTPass
745 :
public circt::impl::ConvertVerifToSMTBase<ConvertVerifToSMTPass> {
747 void runOnOperation()
override;
753 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps) {
754 patterns.add<VerifAssertOpConversion, VerifAssumeOpConversion,
755 LogicEquivalenceCheckingOpConversion,
756 RefinementCheckingOpConversion>(converter,
758 patterns.add<VerifBoundedModelCheckingOpConversion>(
759 converter,
patterns.getContext(), names, risingClocksOnly,
763void ConvertVerifToSMTPass::runOnOperation() {
764 ConversionTarget target(getContext());
765 target.addIllegalDialect<verif::VerifDialect>();
766 target.addLegalDialect<debug::DebugDialect, smt::SMTDialect,
767 arith::ArithDialect, scf::SCFDialect,
768 func::FuncDialect>();
769 target.addLegalOp<verif::BMCTraceOp>();
770 target.addLegalOp<UnrealizedConversionCastOp>();
774 SymbolTable symbolTable(getOperation());
775 SmallVector<Operation *> propertylessBMCOps;
776 WalkResult assertionCheck = getOperation().walk(
778 if (
auto bmcOp = dyn_cast<verif::BoundedModelCheckingOp>(op)) {
781 auto regTypes = TypeRange(bmcOp.getCircuit().getArgumentTypes())
782 .take_back(bmcOp.getNumRegs());
783 for (
auto [regType, initVal] :
784 llvm::zip(regTypes, bmcOp.getInitialValues())) {
785 if (!isa<UnitAttr>(initVal)) {
786 if (!isa<IntegerType>(regType)) {
787 op->emitError(
"initial values are currently only supported for "
788 "registers with integer types");
789 return WalkResult::interrupt();
791 auto tyAttr = dyn_cast<TypedAttr>(initVal);
792 if (!tyAttr || tyAttr.getType() != regType) {
793 op->emitError(
"type of initial value does not match type of "
794 "initialized register");
795 return WalkResult::interrupt();
800 auto numClockArgs = 0;
801 for (
auto argType : bmcOp.getCircuit().getArgumentTypes())
802 if (isa<
seq::ClockType>(argType))
806 if (numClockArgs > 1) {
808 "only modules with one or zero clocks are currently supported");
809 return WalkResult::interrupt();
811 SmallVector<mlir::Operation *> worklist;
812 int numAssertions = 0;
813 op->walk([&](Operation *curOp) {
814 if (isa<verif::AssertOp>(curOp))
816 if (
auto inst = dyn_cast<InstanceOp>(curOp))
817 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
818 if (
auto func = dyn_cast<func::CallOp>(curOp))
819 worklist.push_back(symbolTable.lookup(func.getCallee()));
823 while (!worklist.empty()) {
824 auto *
module = worklist.pop_back_val();
825 module->walk([&](Operation *curOp) {
826 if (isa<verif::AssertOp>(curOp))
828 if (
auto inst = dyn_cast<InstanceOp>(curOp))
829 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
830 if (
auto func = dyn_cast<func::CallOp>(curOp))
831 worklist.push_back(symbolTable.lookup(func.getCallee()));
833 if (numAssertions > 1)
836 if (numAssertions == 0) {
837 op->emitWarning(
"no property provided to check in module - will "
838 "trivially find no violations.");
839 propertylessBMCOps.push_back(bmcOp);
841 if (numAssertions > 1) {
843 "bounded model checking problems with multiple assertions are "
845 "correctly handled - instead, you can assert the "
846 "conjunction of your assertions");
847 return WalkResult::interrupt();
850 return WalkResult::advance();
852 if (assertionCheck.wasInterrupted())
853 return signalPassFailure();
854 RewritePatternSet
patterns(&getContext());
855 TypeConverter converter;
864 risingClocksOnly, propertylessBMCOps);
866 if (failed(mlir::applyPartialConversion(getOperation(), target,
868 return signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
A namespace that is used to store existing names and generate new names in some scope within the IR.
void add(mlir::ModuleOp module)
void addDefinitions(mlir::Operation *top)
Populate the symbol cache with all symbol-defining operations within the 'top' operation.
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateVerifToSMTConversionPatterns(TypeConverter &converter, RewritePatternSet &patterns, Namespace &names, bool risingClocksOnly, SmallVectorImpl< Operation * > &propertylessBMCOps)
Get the Verif to SMT conversion patterns.
void populateHWToSMTTypeConverter(TypeConverter &converter)
Get the HW to SMT type conversions.