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);
89static Value applyEnable(ConversionPatternRewriter &rewriter,
90 const TypeConverter *typeConverter, Location loc,
91 Value enable, Value cond) {
94 Value
en = typeConverter->materializeTargetConversion(
95 rewriter, loc, smt::BoolType::get(rewriter.getContext()), enable);
96 return smt::ImpliesOp::create(rewriter, loc, en, cond);
102 using OpConversionPattern<verif::AssertOp>::OpConversionPattern;
105 matchAndRewrite(verif::AssertOp op, OpAdaptor adaptor,
106 ConversionPatternRewriter &rewriter)
const override {
107 Value cond = typeConverter->materializeTargetConversion(
108 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
109 adaptor.getProperty());
110 cond = applyEnable(rewriter, typeConverter, op.getLoc(),
111 adaptor.getEnable(), cond);
112 Value notCond = smt::NotOp::create(rewriter, op.getLoc(), cond);
113 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, notCond);
120 using OpConversionPattern<verif::AssumeOp>::OpConversionPattern;
123 matchAndRewrite(verif::AssumeOp op, OpAdaptor adaptor,
124 ConversionPatternRewriter &rewriter)
const override {
125 Value cond = typeConverter->materializeTargetConversion(
126 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
127 adaptor.getProperty());
128 cond = applyEnable(rewriter, typeConverter, op.getLoc(),
129 adaptor.getEnable(), cond);
130 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, cond);
135template <
typename OpTy>
137 using OpConversionPattern<OpTy>::OpConversionPattern;
140 using ConversionPattern::typeConverter;
142 createOutputsDifferentOps(Operation *firstOutputs, Operation *secondOutputs,
143 Location &loc, ConversionPatternRewriter &rewriter,
144 SmallVectorImpl<Value> &outputsDifferent)
const {
149 for (
auto [out1, out2] :
150 llvm::zip(firstOutputs->getOperands(), secondOutputs->getOperands())) {
151 Value o1 = typeConverter->materializeTargetConversion(
152 rewriter, loc, typeConverter->convertType(out1.getType()), out1);
153 Value o2 = typeConverter->materializeTargetConversion(
154 rewriter, loc, typeConverter->convertType(out1.getType()), out2);
155 outputsDifferent.emplace_back(
156 smt::DistinctOp::create(rewriter, loc, o1, o2));
160 void replaceOpWithSatCheck(OpTy &op, Location &loc,
161 ConversionPatternRewriter &rewriter,
162 smt::SolverOp &solver)
const {
167 if (op.getNumResults() == 0) {
168 auto checkOp = smt::CheckOp::create(rewriter, loc, TypeRange{});
169 rewriter.createBlock(&checkOp.getSatRegion());
170 smt::YieldOp::create(rewriter, loc);
171 rewriter.createBlock(&checkOp.getUnknownRegion());
172 smt::YieldOp::create(rewriter, loc);
173 rewriter.createBlock(&checkOp.getUnsatRegion());
174 smt::YieldOp::create(rewriter, loc);
175 rewriter.setInsertionPointAfter(checkOp);
176 smt::YieldOp::create(rewriter, loc);
179 rewriter.eraseOp(op);
182 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
184 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
185 auto checkOp = smt::CheckOp::create(rewriter, loc, rewriter.getI1Type());
186 rewriter.createBlock(&checkOp.getSatRegion());
187 smt::YieldOp::create(rewriter, loc, falseVal);
188 rewriter.createBlock(&checkOp.getUnknownRegion());
189 smt::YieldOp::create(rewriter, loc, falseVal);
190 rewriter.createBlock(&checkOp.getUnsatRegion());
191 smt::YieldOp::create(rewriter, loc, trueVal);
192 rewriter.setInsertionPointAfter(checkOp);
193 smt::YieldOp::create(rewriter, loc, checkOp->getResults());
195 rewriter.replaceOp(op, solver->getResults());
205struct LogicEquivalenceCheckingOpConversion
206 : CircuitRelationCheckOpConversion<verif::LogicEquivalenceCheckingOp> {
207 using CircuitRelationCheckOpConversion<
208 verif::LogicEquivalenceCheckingOp>::CircuitRelationCheckOpConversion;
211 matchAndRewrite(verif::LogicEquivalenceCheckingOp op, OpAdaptor adaptor,
212 ConversionPatternRewriter &rewriter)
const override {
213 Location loc = op.getLoc();
214 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
215 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
217 auto hasNoResult = op.getNumResults() == 0;
219 if (firstOutputs->getNumOperands() == 0) {
222 rewriter.eraseOp(op);
224 Value trueVal = arith::ConstantOp::create(rewriter, loc,
225 rewriter.getBoolAttr(
true));
226 rewriter.replaceOp(op, trueVal);
233 smt::SolverOp solver;
235 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
237 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
239 rewriter.createBlock(&solver.getBodyRegion());
242 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
245 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
250 SmallVector<Value> inputs;
251 for (
auto arg : adaptor.getFirstCircuit().getArguments())
252 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
261 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), solver.getBody(),
263 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
265 rewriter.setInsertionPointToEnd(solver.getBody());
268 SmallVector<Value> outputsDifferent;
269 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
272 rewriter.eraseOp(firstOutputs);
273 rewriter.eraseOp(secondOutputs);
276 if (outputsDifferent.size() == 1)
277 toAssert = outputsDifferent[0];
279 toAssert = smt::OrOp::create(rewriter, loc, outputsDifferent);
281 smt::AssertOp::create(rewriter, loc, toAssert);
284 replaceOpWithSatCheck(op, loc, rewriter, solver);
289struct RefinementCheckingOpConversion
290 : CircuitRelationCheckOpConversion<verif::RefinementCheckingOp> {
291 using CircuitRelationCheckOpConversion<
292 verif::RefinementCheckingOp>::CircuitRelationCheckOpConversion;
295 matchAndRewrite(verif::RefinementCheckingOp op, OpAdaptor adaptor,
296 ConversionPatternRewriter &rewriter)
const override {
300 SmallVector<Value> srcNonDetValues;
302 for (
auto ndOp : op.getFirstCircuit().getOps<smt::DeclareFunOp>()) {
303 if (!isa<smt::IntType, smt::BoolType, smt::BitVectorType>(
305 ndOp.emitError(
"Uninterpreted function of non-primitive type cannot be "
309 srcNonDetValues.push_back(ndOp.getResult());
314 if (srcNonDetValues.empty()) {
318 auto eqOp = verif::LogicEquivalenceCheckingOp::create(
319 rewriter, op.getLoc(), op.getNumResults() != 0);
320 rewriter.moveBlockBefore(&op.getFirstCircuit().front(),
321 &eqOp.getFirstCircuit(),
322 eqOp.getFirstCircuit().end());
323 rewriter.moveBlockBefore(&op.getSecondCircuit().front(),
324 &eqOp.getSecondCircuit(),
325 eqOp.getSecondCircuit().end());
326 rewriter.replaceOp(op, eqOp);
330 Location loc = op.getLoc();
331 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
332 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
334 auto hasNoResult = op.getNumResults() == 0;
336 if (firstOutputs->getNumOperands() == 0) {
339 rewriter.eraseOp(op);
341 Value trueVal = arith::ConstantOp::create(rewriter, loc,
342 rewriter.getBoolAttr(
true));
343 rewriter.replaceOp(op, trueVal);
350 smt::SolverOp solver;
352 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
354 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
356 rewriter.createBlock(&solver.getBodyRegion());
359 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
362 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
367 SmallVector<Value> inputs;
368 for (
auto arg : adaptor.getFirstCircuit().getArguments())
369 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
372 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
374 rewriter.setInsertionPointToEnd(solver.getBody());
378 auto forallOp = smt::ForallOp::create(
379 rewriter, op.getLoc(), TypeRange(srcNonDetValues),
380 [&](OpBuilder &builder,
auto, ValueRange args) -> Value {
382 Block *body = builder.getBlock();
383 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), body,
388 for (
auto [freeVar, boundVar] : llvm::zip(srcNonDetValues, args))
389 rewriter.replaceOp(freeVar.getDefiningOp(), boundVar);
392 rewriter.setInsertionPointToEnd(body);
393 SmallVector<Value> outputsDifferent;
394 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
396 if (outputsDifferent.size() == 1)
397 return outputsDifferent[0];
399 return rewriter.createOrFold<smt::OrOp>(loc, outputsDifferent);
402 rewriter.eraseOp(firstOutputs);
403 rewriter.eraseOp(secondOutputs);
406 rewriter.setInsertionPointAfter(forallOp);
407 smt::AssertOp::create(rewriter, op.getLoc(), forallOp.getResult());
410 replaceOpWithSatCheck(op, loc, rewriter, solver);
417struct VerifBoundedModelCheckingOpConversion
419 using OpConversionPattern<verif::BoundedModelCheckingOp>::OpConversionPattern;
421 VerifBoundedModelCheckingOpConversion(
422 TypeConverter &converter, MLIRContext *
context, Namespace &names,
423 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps)
424 : OpConversionPattern(converter,
context), names(names),
425 risingClocksOnly(risingClocksOnly),
426 propertylessBMCOps(propertylessBMCOps) {}
428 matchAndRewrite(verif::BoundedModelCheckingOp op, OpAdaptor adaptor,
429 ConversionPatternRewriter &rewriter)
const override {
430 Location loc = op.getLoc();
432 if (llvm::find(propertylessBMCOps, op) != propertylessBMCOps.end()) {
437 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
438 rewriter.replaceOp(op, trueVal);
442 SmallVector<Type> oldLoopInputTy(op.getLoop().getArgumentTypes());
443 SmallVector<Type> oldCircuitInputTy(op.getCircuit().getArgumentTypes());
447 SmallVector<Type> loopInputTy, circuitInputTy, initOutputTy,
449 if (failed(typeConverter->convertTypes(oldLoopInputTy, loopInputTy)))
451 if (failed(typeConverter->convertTypes(oldCircuitInputTy, circuitInputTy)))
453 if (failed(typeConverter->convertTypes(
454 op.getInit().front().back().getOperandTypes(), initOutputTy)))
456 if (failed(typeConverter->convertTypes(
457 op.getCircuit().front().back().getOperandTypes(), circuitOutputTy)))
459 auto debugNames = collectDebugNames(op.getCircuit().front());
460 if (failed(rewriter.convertRegionTypes(&op.getInit(), *typeConverter)))
462 if (failed(rewriter.convertRegionTypes(&op.getLoop(), *typeConverter)))
464 if (failed(rewriter.convertRegionTypes(&op.getCircuit(), *typeConverter)))
467 unsigned numRegs = op.getNumRegs();
468 auto initialValues = op.getInitialValues();
470 auto initFuncTy = rewriter.getFunctionType({}, initOutputTy);
473 auto loopFuncTy = rewriter.getFunctionType(loopInputTy, initOutputTy);
475 rewriter.getFunctionType(circuitInputTy, circuitOutputTy);
477 func::FuncOp initFuncOp, loopFuncOp, circuitFuncOp;
480 OpBuilder::InsertionGuard guard(rewriter);
481 rewriter.setInsertionPointToEnd(
482 op->getParentOfType<ModuleOp>().getBody());
483 initFuncOp = func::FuncOp::create(rewriter, loc,
484 names.newName(
"bmc_init"), initFuncTy);
485 rewriter.inlineRegionBefore(op.getInit(), initFuncOp.getFunctionBody(),
487 loopFuncOp = func::FuncOp::create(rewriter, loc,
488 names.newName(
"bmc_loop"), loopFuncTy);
489 rewriter.inlineRegionBefore(op.getLoop(), loopFuncOp.getFunctionBody(),
491 circuitFuncOp = func::FuncOp::create(
492 rewriter, loc, names.newName(
"bmc_circuit"), circuitFuncTy);
493 rewriter.inlineRegionBefore(op.getCircuit(),
494 circuitFuncOp.getFunctionBody(),
495 circuitFuncOp.end());
496 auto funcOps = {&initFuncOp, &loopFuncOp, &circuitFuncOp};
498 auto outputTys = {initOutputTy, initOutputTy, circuitOutputTy};
499 for (
auto [funcOp, outputTy] : llvm::zip(funcOps, outputTys)) {
500 auto operands = funcOp->getBody().front().back().getOperands();
501 rewriter.eraseOp(&funcOp->getFunctionBody().front().back());
502 rewriter.setInsertionPointToEnd(&funcOp->getBody().front());
503 SmallVector<Value> toReturn;
504 for (
unsigned i = 0; i < outputTy.size(); ++i)
505 toReturn.push_back(typeConverter->materializeTargetConversion(
506 rewriter, loc, outputTy[i], operands[i]));
507 func::ReturnOp::create(rewriter, loc, toReturn);
511 auto solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
513 rewriter.createBlock(&solver.getBodyRegion());
516 ValueRange initVals =
517 func::CallOp::create(rewriter, loc, initFuncOp)->getResults();
520 smt::PushOp::create(rewriter, loc, 1);
525 size_t initIndex = 0;
526 size_t regStartIdx = oldCircuitInputTy.size() - numRegs;
527 SmallVector<Value> inputDecls;
528 SmallVector<int> clockIndexes;
529 auto getNameAttr = [&](
unsigned argIndex,
bool isReg) {
530 if (
auto it = debugNames.find(argIndex); it != debugNames.end())
532 auto fallback = isReg ? (
"reg_" + Twine(argIndex - regStartIdx)).str()
533 : (
"input_" + Twine(argIndex)).str();
534 return rewriter.getStringAttr(fallback);
536 for (
auto [curIndex, oldTy, newTy] :
537 llvm::enumerate(oldCircuitInputTy, circuitInputTy)) {
538 if (isa<seq::ClockType>(oldTy)) {
539 inputDecls.push_back(initVals[initIndex++]);
540 clockIndexes.push_back(curIndex);
543 if (curIndex >= regStartIdx) {
544 auto initVal = initialValues[curIndex - regStartIdx];
545 if (
auto initIntAttr = dyn_cast<IntegerAttr>(initVal)) {
546 const auto &cstInt = initIntAttr.getValue();
547 assert(cstInt.getBitWidth() ==
548 cast<smt::BitVectorType>(newTy).getWidth() &&
549 "Width mismatch between initial value and target type");
550 inputDecls.push_back(
551 smt::BVConstantOp::create(rewriter, loc, cstInt));
555 inputDecls.push_back(smt::DeclareFunOp::create(
556 rewriter, loc, newTy,
557 getNameAttr(curIndex, curIndex >= regStartIdx)));
560 auto numStateArgs = initVals.size() - initIndex;
562 for (; initIndex < initVals.size(); ++initIndex)
563 inputDecls.push_back(initVals[initIndex]);
565 attachDebugVariables(
566 rewriter, loc, oldCircuitInputTy,
567 ValueRange(inputDecls).take_front(circuitFuncOp.getNumArguments()),
571 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
573 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(1));
575 arith::ConstantOp::create(rewriter, loc, adaptor.getBoundAttr());
577 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
579 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
580 inputDecls.push_back(constFalse);
585 auto forOp = scf::ForOp::create(
586 rewriter, loc, lowerBound, upperBound, step, inputDecls,
587 [&](OpBuilder &builder, Location loc, Value i, ValueRange iterArgs) {
588 attachDebugVariables(
589 builder, loc, oldCircuitInputTy,
590 iterArgs.take_front(circuitFuncOp.getNumArguments()), debugNames);
592 builder, loc, i, oldCircuitInputTy,
593 iterArgs.take_front(circuitFuncOp.getNumArguments()), debugNames);
596 smt::PopOp::create(builder, loc, 1);
597 smt::PushOp::create(builder, loc, 1);
600 ValueRange circuitCallOuts =
601 func::CallOp::create(
602 builder, loc, circuitFuncOp,
603 iterArgs.take_front(circuitFuncOp.getNumArguments()))
610 auto insideForPoint = builder.saveInsertionPoint();
614 auto ignoreAssertionsUntil =
615 op->getAttrOfType<IntegerAttr>(
"ignore_asserts_until");
616 if (ignoreAssertionsUntil) {
617 auto ignoreUntilConstant = arith::ConstantOp::create(
619 rewriter.getI32IntegerAttr(
620 ignoreAssertionsUntil.getValue().getZExtValue()));
622 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::ult,
623 i, ignoreUntilConstant);
624 auto ifShouldIgnore = scf::IfOp::create(
625 builder, loc, builder.getI1Type(), shouldIgnore,
true);
627 builder.setInsertionPointToEnd(
628 &ifShouldIgnore.getThenRegion().front());
629 scf::YieldOp::create(builder, loc, ValueRange(iterArgs.back()));
630 builder.setInsertionPointToEnd(
631 &ifShouldIgnore.getElseRegion().front());
632 yieldedValue = ifShouldIgnore.getResult(0);
636 smt::CheckOp::create(rewriter, loc, builder.getI1Type());
638 OpBuilder::InsertionGuard guard(builder);
639 builder.createBlock(&checkOp.getSatRegion());
640 smt::YieldOp::create(builder, loc, constTrue);
641 builder.createBlock(&checkOp.getUnknownRegion());
642 smt::YieldOp::create(builder, loc, constTrue);
643 builder.createBlock(&checkOp.getUnsatRegion());
644 smt::YieldOp::create(builder, loc, constFalse);
647 Value violated = arith::OrIOp::create(
648 builder, loc, checkOp.getResult(0), iterArgs.back());
652 if (ignoreAssertionsUntil) {
653 scf::YieldOp::create(builder, loc, violated);
655 violated = yieldedValue;
659 builder.restoreInsertionPoint(insideForPoint);
662 SmallVector<Value> loopCallInputs;
664 for (
auto index : clockIndexes)
665 loopCallInputs.push_back(iterArgs[index]);
667 for (
auto stateArg : iterArgs.drop_back().take_back(numStateArgs))
668 loopCallInputs.push_back(stateArg);
669 ValueRange loopVals =
670 func::CallOp::create(builder, loc, loopFuncOp, loopCallInputs)
673 size_t loopIndex = 0;
675 SmallVector<Value> newDecls;
676 for (
auto [inputIdx, oldTy, newTy] :
677 llvm::enumerate(TypeRange(oldCircuitInputTy).drop_back(numRegs),
678 TypeRange(circuitInputTy).drop_back(numRegs))) {
679 if (isa<seq::ClockType>(oldTy)) {
680 newDecls.push_back(loopVals[loopIndex++]);
682 newDecls.push_back(smt::DeclareFunOp::create(
683 builder, loc, newTy, getNameAttr(inputIdx,
false)));
691 if (clockIndexes.size() == 1) {
692 SmallVector<Value> regInputs = circuitCallOuts.take_back(numRegs);
693 if (risingClocksOnly) {
696 newDecls.append(regInputs);
698 auto clockIndex = clockIndexes[0];
699 auto oldClock = iterArgs[clockIndex];
702 auto newClock = loopVals[0];
703 auto oldClockLow = smt::BVNotOp::create(builder, loc, oldClock);
705 smt::BVAndOp::create(builder, loc, oldClockLow, newClock);
707 auto trueBV = smt::BVConstantOp::create(builder, loc, 1, 1);
709 smt::EqOp::create(builder, loc, isPosedgeBV, trueBV);
711 iterArgs.take_front(circuitFuncOp.getNumArguments())
713 SmallVector<Value> nextRegStates;
714 for (
auto [regState, regInput] :
715 llvm::zip(regStates, regInputs)) {
719 nextRegStates.push_back(smt::IteOp::create(
720 builder, loc, isPosedge, regInput, regState));
722 newDecls.append(nextRegStates);
727 for (; loopIndex < loopVals.size(); ++loopIndex)
728 newDecls.push_back(loopVals[loopIndex]);
730 attachDebugVariables(
731 builder, loc, oldCircuitInputTy,
732 ValueRange(newDecls).take_front(circuitFuncOp.getNumArguments()),
735 newDecls.push_back(violated);
737 scf::YieldOp::create(builder, loc, newDecls);
740 Value res = arith::XOrIOp::create(rewriter, loc, forOp->getResults().back(),
742 smt::YieldOp::create(rewriter, loc, res);
743 rewriter.replaceOp(op, solver.getResults());
748 bool risingClocksOnly;
749 SmallVectorImpl<Operation *> &propertylessBMCOps;
759struct ConvertVerifToSMTPass
760 :
public circt::impl::ConvertVerifToSMTBase<ConvertVerifToSMTPass> {
762 void runOnOperation()
override;
768 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps) {
769 patterns.add<VerifAssertOpConversion, VerifAssumeOpConversion,
770 LogicEquivalenceCheckingOpConversion,
771 RefinementCheckingOpConversion>(converter,
773 patterns.add<VerifBoundedModelCheckingOpConversion>(
774 converter,
patterns.getContext(), names, risingClocksOnly,
778void ConvertVerifToSMTPass::runOnOperation() {
779 ConversionTarget target(getContext());
780 target.addIllegalDialect<verif::VerifDialect>();
781 target.addLegalDialect<debug::DebugDialect, smt::SMTDialect,
782 arith::ArithDialect, scf::SCFDialect,
783 func::FuncDialect>();
784 target.addLegalOp<verif::BMCTraceOp>();
785 target.addLegalOp<UnrealizedConversionCastOp>();
789 SymbolTable symbolTable(getOperation());
790 SmallVector<Operation *> propertylessBMCOps;
791 WalkResult assertionCheck = getOperation().walk(
793 if (
auto bmcOp = dyn_cast<verif::BoundedModelCheckingOp>(op)) {
796 auto regTypes = TypeRange(bmcOp.getCircuit().getArgumentTypes())
797 .take_back(bmcOp.getNumRegs());
798 for (
auto [regType, initVal] :
799 llvm::zip(regTypes, bmcOp.getInitialValues())) {
800 if (!isa<UnitAttr>(initVal)) {
801 if (!isa<IntegerType>(regType)) {
802 op->emitError(
"initial values are currently only supported for "
803 "registers with integer types");
804 return WalkResult::interrupt();
806 auto tyAttr = dyn_cast<TypedAttr>(initVal);
807 if (!tyAttr || tyAttr.getType() != regType) {
808 op->emitError(
"type of initial value does not match type of "
809 "initialized register");
810 return WalkResult::interrupt();
815 auto numClockArgs = 0;
816 for (
auto argType : bmcOp.getCircuit().getArgumentTypes())
817 if (isa<seq::ClockType>(argType))
821 if (numClockArgs > 1) {
823 "only modules with one or zero clocks are currently supported");
824 return WalkResult::interrupt();
826 SmallVector<mlir::Operation *> worklist;
827 int numAssertions = 0;
828 op->walk([&](Operation *curOp) {
829 if (isa<verif::AssertOp>(curOp))
831 if (
auto inst = dyn_cast<InstanceOp>(curOp))
832 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
833 if (
auto func = dyn_cast<func::CallOp>(curOp))
834 worklist.push_back(symbolTable.lookup(func.getCallee()));
838 while (!worklist.empty()) {
839 auto *
module = worklist.pop_back_val();
840 module->walk([&](Operation *curOp) {
841 if (isa<verif::AssertOp>(curOp))
843 if (
auto inst = dyn_cast<InstanceOp>(curOp))
844 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
845 if (
auto func = dyn_cast<func::CallOp>(curOp))
846 worklist.push_back(symbolTable.lookup(func.getCallee()));
848 if (numAssertions > 1)
851 if (numAssertions == 0) {
852 op->emitWarning(
"no property provided to check in module - will "
853 "trivially find no violations.");
854 propertylessBMCOps.push_back(bmcOp);
856 if (numAssertions > 1) {
858 "bounded model checking problems with multiple assertions are "
860 "correctly handled - instead, you can assert the "
861 "conjunction of your assertions");
862 return WalkResult::interrupt();
865 return WalkResult::advance();
867 if (assertionCheck.wasInterrupted())
868 return signalPassFailure();
869 RewritePatternSet patterns(&getContext());
870 TypeConverter converter;
873 SymbolCache symCache;
879 risingClocksOnly, propertylessBMCOps);
881 if (failed(mlir::applyPartialConversion(getOperation(), target,
882 std::move(patterns))))
883 return signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.
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.