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,
79 matchAndRewrite(verif::AssertOp op, OpAdaptor adaptor,
80 ConversionPatternRewriter &rewriter)
const override {
81 Value cond = typeConverter->materializeTargetConversion(
82 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
83 adaptor.getProperty());
84 Value notCond = smt::NotOp::create(rewriter, op.getLoc(), cond);
85 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, notCond);
95 matchAndRewrite(verif::AssumeOp op, OpAdaptor adaptor,
96 ConversionPatternRewriter &rewriter)
const override {
97 Value cond = typeConverter->materializeTargetConversion(
98 rewriter, op.getLoc(), smt::BoolType::get(getContext()),
99 adaptor.getProperty());
100 rewriter.replaceOpWithNewOp<smt::AssertOp>(op, cond);
105template <
typename OpTy>
110 using ConversionPattern::typeConverter;
112 createOutputsDifferentOps(Operation *firstOutputs, Operation *secondOutputs,
113 Location &loc, ConversionPatternRewriter &rewriter,
114 SmallVectorImpl<Value> &outputsDifferent)
const {
119 for (
auto [out1, out2] :
120 llvm::zip(firstOutputs->getOperands(), secondOutputs->getOperands())) {
121 Value o1 = typeConverter->materializeTargetConversion(
122 rewriter, loc, typeConverter->convertType(out1.getType()), out1);
123 Value o2 = typeConverter->materializeTargetConversion(
124 rewriter, loc, typeConverter->convertType(out1.getType()), out2);
125 outputsDifferent.emplace_back(
126 smt::DistinctOp::create(rewriter, loc, o1, o2));
130 void replaceOpWithSatCheck(OpTy &op, Location &loc,
131 ConversionPatternRewriter &rewriter,
132 smt::SolverOp &solver)
const {
137 if (op.getNumResults() == 0) {
138 auto checkOp = smt::CheckOp::create(rewriter, loc, TypeRange{});
139 rewriter.createBlock(&checkOp.getSatRegion());
140 smt::YieldOp::create(rewriter, loc);
141 rewriter.createBlock(&checkOp.getUnknownRegion());
142 smt::YieldOp::create(rewriter, loc);
143 rewriter.createBlock(&checkOp.getUnsatRegion());
144 smt::YieldOp::create(rewriter, loc);
145 rewriter.setInsertionPointAfter(checkOp);
146 smt::YieldOp::create(rewriter, loc);
149 rewriter.eraseOp(op);
152 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
154 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
155 auto checkOp = smt::CheckOp::create(rewriter, loc, rewriter.getI1Type());
156 rewriter.createBlock(&checkOp.getSatRegion());
157 smt::YieldOp::create(rewriter, loc, falseVal);
158 rewriter.createBlock(&checkOp.getUnknownRegion());
159 smt::YieldOp::create(rewriter, loc, falseVal);
160 rewriter.createBlock(&checkOp.getUnsatRegion());
161 smt::YieldOp::create(rewriter, loc, trueVal);
162 rewriter.setInsertionPointAfter(checkOp);
163 smt::YieldOp::create(rewriter, loc, checkOp->getResults());
165 rewriter.replaceOp(op, solver->getResults());
175struct LogicEquivalenceCheckingOpConversion
176 : CircuitRelationCheckOpConversion<verif::LogicEquivalenceCheckingOp> {
177 using CircuitRelationCheckOpConversion<
178 verif::LogicEquivalenceCheckingOp>::CircuitRelationCheckOpConversion;
181 matchAndRewrite(verif::LogicEquivalenceCheckingOp op, OpAdaptor adaptor,
182 ConversionPatternRewriter &rewriter)
const override {
183 Location loc = op.getLoc();
184 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
185 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
187 auto hasNoResult = op.getNumResults() == 0;
189 if (firstOutputs->getNumOperands() == 0) {
192 rewriter.eraseOp(op);
194 Value trueVal = arith::ConstantOp::create(rewriter, loc,
195 rewriter.getBoolAttr(
true));
196 rewriter.replaceOp(op, trueVal);
203 smt::SolverOp solver;
205 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
207 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
209 rewriter.createBlock(&solver.getBodyRegion());
212 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
215 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
220 SmallVector<Value> inputs;
221 for (
auto arg : adaptor.getFirstCircuit().getArguments())
222 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
231 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), solver.getBody(),
233 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
235 rewriter.setInsertionPointToEnd(solver.getBody());
238 SmallVector<Value> outputsDifferent;
239 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
242 rewriter.eraseOp(firstOutputs);
243 rewriter.eraseOp(secondOutputs);
246 if (outputsDifferent.size() == 1)
247 toAssert = outputsDifferent[0];
249 toAssert = smt::OrOp::create(rewriter, loc, outputsDifferent);
251 smt::AssertOp::create(rewriter, loc, toAssert);
254 replaceOpWithSatCheck(op, loc, rewriter, solver);
259struct RefinementCheckingOpConversion
260 : CircuitRelationCheckOpConversion<verif::RefinementCheckingOp> {
261 using CircuitRelationCheckOpConversion<
262 verif::RefinementCheckingOp>::CircuitRelationCheckOpConversion;
265 matchAndRewrite(verif::RefinementCheckingOp op, OpAdaptor adaptor,
266 ConversionPatternRewriter &rewriter)
const override {
270 SmallVector<Value> srcNonDetValues;
272 for (
auto ndOp : op.getFirstCircuit().getOps<smt::DeclareFunOp>()) {
273 if (!isa<smt::IntType, smt::BoolType, smt::BitVectorType>(
275 ndOp.emitError(
"Uninterpreted function of non-primitive type cannot be "
279 srcNonDetValues.push_back(ndOp.getResult());
284 if (srcNonDetValues.empty()) {
288 auto eqOp = verif::LogicEquivalenceCheckingOp::create(
289 rewriter, op.getLoc(), op.getNumResults() != 0);
290 rewriter.moveBlockBefore(&op.getFirstCircuit().front(),
291 &eqOp.getFirstCircuit(),
292 eqOp.getFirstCircuit().end());
293 rewriter.moveBlockBefore(&op.getSecondCircuit().front(),
294 &eqOp.getSecondCircuit(),
295 eqOp.getSecondCircuit().end());
296 rewriter.replaceOp(op, eqOp);
300 Location loc = op.getLoc();
301 auto *firstOutputs = adaptor.getFirstCircuit().front().getTerminator();
302 auto *secondOutputs = adaptor.getSecondCircuit().front().getTerminator();
304 auto hasNoResult = op.getNumResults() == 0;
306 if (firstOutputs->getNumOperands() == 0) {
309 rewriter.eraseOp(op);
311 Value trueVal = arith::ConstantOp::create(rewriter, loc,
312 rewriter.getBoolAttr(
true));
313 rewriter.replaceOp(op, trueVal);
320 smt::SolverOp solver;
322 solver = smt::SolverOp::create(rewriter, loc, TypeRange{}, ValueRange{});
324 solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
326 rewriter.createBlock(&solver.getBodyRegion());
329 if (failed(rewriter.convertRegionTypes(&adaptor.getFirstCircuit(),
332 if (failed(rewriter.convertRegionTypes(&adaptor.getSecondCircuit(),
337 SmallVector<Value> inputs;
338 for (
auto arg : adaptor.getFirstCircuit().getArguments())
339 inputs.push_back(smt::DeclareFunOp::create(rewriter, loc, arg.getType()));
342 rewriter.mergeBlocks(&adaptor.getSecondCircuit().front(), solver.getBody(),
344 rewriter.setInsertionPointToEnd(solver.getBody());
348 auto forallOp = smt::ForallOp::create(
349 rewriter, op.getLoc(), TypeRange(srcNonDetValues),
350 [&](OpBuilder &builder,
auto, ValueRange args) -> Value {
352 Block *body = builder.getBlock();
353 rewriter.mergeBlocks(&adaptor.getFirstCircuit().front(), body,
358 for (
auto [freeVar, boundVar] :
llvm::zip(srcNonDetValues, args))
359 rewriter.replaceOp(freeVar.getDefiningOp(), boundVar);
362 rewriter.setInsertionPointToEnd(body);
363 SmallVector<Value> outputsDifferent;
364 createOutputsDifferentOps(firstOutputs, secondOutputs, loc, rewriter,
366 if (outputsDifferent.size() == 1)
367 return outputsDifferent[0];
369 return rewriter.createOrFold<smt::OrOp>(loc, outputsDifferent);
372 rewriter.eraseOp(firstOutputs);
373 rewriter.eraseOp(secondOutputs);
376 rewriter.setInsertionPointAfter(forallOp);
377 smt::AssertOp::create(rewriter, op.getLoc(), forallOp.getResult());
380 replaceOpWithSatCheck(op, loc, rewriter, solver);
387struct VerifBoundedModelCheckingOpConversion
391 VerifBoundedModelCheckingOpConversion(
393 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps)
395 risingClocksOnly(risingClocksOnly),
396 propertylessBMCOps(propertylessBMCOps) {}
398 matchAndRewrite(verif::BoundedModelCheckingOp op, OpAdaptor adaptor,
399 ConversionPatternRewriter &rewriter)
const override {
400 Location loc = op.getLoc();
402 if (std::find(propertylessBMCOps.begin(), propertylessBMCOps.end(), op) !=
403 propertylessBMCOps.end()) {
408 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
409 rewriter.replaceOp(op, trueVal);
413 SmallVector<Type> oldLoopInputTy(op.getLoop().getArgumentTypes());
414 SmallVector<Type> oldCircuitInputTy(op.getCircuit().getArgumentTypes());
418 SmallVector<Type> loopInputTy, circuitInputTy, initOutputTy,
420 if (failed(typeConverter->convertTypes(oldLoopInputTy, loopInputTy)))
422 if (failed(typeConverter->convertTypes(oldCircuitInputTy, circuitInputTy)))
424 if (failed(typeConverter->convertTypes(
425 op.getInit().front().back().getOperandTypes(), initOutputTy)))
427 if (failed(typeConverter->convertTypes(
428 op.getCircuit().front().back().getOperandTypes(), circuitOutputTy)))
430 auto debugNames = collectDebugNames(op.getCircuit().front());
431 if (failed(rewriter.convertRegionTypes(&op.getInit(), *typeConverter)))
433 if (failed(rewriter.convertRegionTypes(&op.getLoop(), *typeConverter)))
435 if (failed(rewriter.convertRegionTypes(&op.getCircuit(), *typeConverter)))
438 unsigned numRegs = op.getNumRegs();
439 auto initialValues = op.getInitialValues();
441 auto initFuncTy = rewriter.getFunctionType({}, initOutputTy);
444 auto loopFuncTy = rewriter.getFunctionType(loopInputTy, initOutputTy);
446 rewriter.getFunctionType(circuitInputTy, circuitOutputTy);
448 func::FuncOp initFuncOp, loopFuncOp, circuitFuncOp;
451 OpBuilder::InsertionGuard guard(rewriter);
452 rewriter.setInsertionPointToEnd(
453 op->getParentOfType<ModuleOp>().getBody());
454 initFuncOp = func::FuncOp::create(rewriter, loc,
455 names.newName(
"bmc_init"), initFuncTy);
456 rewriter.inlineRegionBefore(op.getInit(), initFuncOp.getFunctionBody(),
458 loopFuncOp = func::FuncOp::create(rewriter, loc,
459 names.newName(
"bmc_loop"), loopFuncTy);
460 rewriter.inlineRegionBefore(op.getLoop(), loopFuncOp.getFunctionBody(),
462 circuitFuncOp = func::FuncOp::create(
463 rewriter, loc, names.newName(
"bmc_circuit"), circuitFuncTy);
464 rewriter.inlineRegionBefore(op.getCircuit(),
465 circuitFuncOp.getFunctionBody(),
466 circuitFuncOp.end());
467 auto funcOps = {&initFuncOp, &loopFuncOp, &circuitFuncOp};
469 auto outputTys = {initOutputTy, initOutputTy, circuitOutputTy};
470 for (
auto [funcOp, outputTy] :
llvm::zip(funcOps, outputTys)) {
471 auto operands = funcOp->getBody().front().back().getOperands();
472 rewriter.eraseOp(&funcOp->getFunctionBody().front().back());
473 rewriter.setInsertionPointToEnd(&funcOp->getBody().front());
474 SmallVector<Value> toReturn;
475 for (
unsigned i = 0; i < outputTy.size(); ++i)
476 toReturn.push_back(typeConverter->materializeTargetConversion(
477 rewriter, loc, outputTy[i], operands[i]));
478 func::ReturnOp::create(rewriter, loc, toReturn);
482 auto solver = smt::SolverOp::create(rewriter, loc, rewriter.getI1Type(),
484 rewriter.createBlock(&solver.getBodyRegion());
487 ValueRange initVals =
488 func::CallOp::create(rewriter, loc, initFuncOp)->getResults();
491 smt::PushOp::create(rewriter, loc, 1);
496 size_t initIndex = 0;
497 size_t regStartIdx = oldCircuitInputTy.size() - numRegs;
498 SmallVector<Value> inputDecls;
499 SmallVector<int> clockIndexes;
500 auto getNameAttr = [&](
unsigned argIndex,
bool isReg) {
501 if (
auto it = debugNames.find(argIndex); it != debugNames.end())
503 auto fallback = isReg ? (
"reg_" + Twine(argIndex - regStartIdx)).str()
504 : (
"input_" + Twine(argIndex)).str();
505 return rewriter.getStringAttr(fallback);
507 for (
auto [curIndex, oldTy, newTy] :
508 llvm::enumerate(oldCircuitInputTy, circuitInputTy)) {
509 if (isa<seq::ClockType>(oldTy)) {
510 inputDecls.push_back(initVals[initIndex++]);
511 clockIndexes.push_back(curIndex);
514 if (curIndex >= regStartIdx) {
515 auto initVal = initialValues[curIndex - regStartIdx];
516 if (
auto initIntAttr = dyn_cast<IntegerAttr>(initVal)) {
517 const auto &cstInt = initIntAttr.getValue();
518 assert(cstInt.getBitWidth() ==
519 cast<smt::BitVectorType>(newTy).getWidth() &&
520 "Width mismatch between initial value and target type");
521 inputDecls.push_back(
522 smt::BVConstantOp::create(rewriter, loc, cstInt));
526 inputDecls.push_back(smt::DeclareFunOp::create(
527 rewriter, loc, newTy,
528 getNameAttr(curIndex, curIndex >= regStartIdx)));
531 auto numStateArgs = initVals.size() - initIndex;
533 for (; initIndex < initVals.size(); ++initIndex)
534 inputDecls.push_back(initVals[initIndex]);
536 attachDebugVariables(
537 rewriter, loc, oldCircuitInputTy,
538 ValueRange(inputDecls).take_front(circuitFuncOp.getNumArguments()),
542 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
544 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(1));
546 arith::ConstantOp::create(rewriter, loc, adaptor.getBoundAttr());
548 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
550 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
true));
551 inputDecls.push_back(constFalse);
556 auto forOp = scf::ForOp::create(
557 rewriter, loc, lowerBound, upperBound, step, inputDecls,
558 [&](OpBuilder &builder, Location loc, Value i, ValueRange iterArgs) {
559 attachDebugVariables(
560 builder, loc, oldCircuitInputTy,
561 iterArgs.take_front(circuitFuncOp.getNumArguments()), debugNames);
564 smt::PopOp::create(builder, loc, 1);
565 smt::PushOp::create(builder, loc, 1);
568 ValueRange circuitCallOuts =
569 func::CallOp::create(
570 builder, loc, circuitFuncOp,
571 iterArgs.take_front(circuitFuncOp.getNumArguments()))
578 auto insideForPoint = builder.saveInsertionPoint();
582 auto ignoreAssertionsUntil =
583 op->getAttrOfType<IntegerAttr>(
"ignore_asserts_until");
584 if (ignoreAssertionsUntil) {
585 auto ignoreUntilConstant = arith::ConstantOp::create(
587 rewriter.getI32IntegerAttr(
588 ignoreAssertionsUntil.getValue().getZExtValue()));
590 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::ult,
591 i, ignoreUntilConstant);
592 auto ifShouldIgnore = scf::IfOp::create(
593 builder, loc, builder.getI1Type(), shouldIgnore,
true);
595 builder.setInsertionPointToEnd(
596 &ifShouldIgnore.getThenRegion().front());
597 scf::YieldOp::create(builder, loc, ValueRange(iterArgs.back()));
598 builder.setInsertionPointToEnd(
599 &ifShouldIgnore.getElseRegion().front());
600 yieldedValue = ifShouldIgnore.getResult(0);
604 smt::CheckOp::create(rewriter, loc, builder.getI1Type());
606 OpBuilder::InsertionGuard guard(builder);
607 builder.createBlock(&checkOp.getSatRegion());
608 smt::YieldOp::create(builder, loc, constTrue);
609 builder.createBlock(&checkOp.getUnknownRegion());
610 smt::YieldOp::create(builder, loc, constTrue);
611 builder.createBlock(&checkOp.getUnsatRegion());
612 smt::YieldOp::create(builder, loc, constFalse);
615 Value violated = arith::OrIOp::create(
616 builder, loc, checkOp.getResult(0), iterArgs.back());
620 if (ignoreAssertionsUntil) {
621 scf::YieldOp::create(builder, loc, violated);
623 violated = yieldedValue;
627 builder.restoreInsertionPoint(insideForPoint);
630 SmallVector<Value> loopCallInputs;
632 for (
auto index : clockIndexes)
633 loopCallInputs.push_back(iterArgs[index]);
635 for (
auto stateArg : iterArgs.drop_back().take_back(numStateArgs))
636 loopCallInputs.push_back(stateArg);
637 ValueRange loopVals =
638 func::CallOp::create(builder, loc, loopFuncOp, loopCallInputs)
641 size_t loopIndex = 0;
643 SmallVector<Value> newDecls;
644 for (
auto [inputIdx, oldTy, newTy] :
645 llvm::enumerate(TypeRange(oldCircuitInputTy).drop_back(numRegs),
646 TypeRange(circuitInputTy).drop_back(numRegs))) {
647 if (isa<seq::ClockType>(oldTy)) {
648 newDecls.push_back(loopVals[loopIndex++]);
650 newDecls.push_back(smt::DeclareFunOp::create(
651 builder, loc, newTy, getNameAttr(inputIdx,
false)));
659 if (clockIndexes.size() == 1) {
660 SmallVector<Value> regInputs = circuitCallOuts.take_back(numRegs);
661 if (risingClocksOnly) {
664 newDecls.append(regInputs);
666 auto clockIndex = clockIndexes[0];
667 auto oldClock = iterArgs[clockIndex];
670 auto newClock = loopVals[0];
671 auto oldClockLow = smt::BVNotOp::create(builder, loc, oldClock);
673 smt::BVAndOp::create(builder, loc, oldClockLow, newClock);
675 auto trueBV = smt::BVConstantOp::create(builder, loc, 1, 1);
677 smt::EqOp::create(builder, loc, isPosedgeBV, trueBV);
679 iterArgs.take_front(circuitFuncOp.getNumArguments())
681 SmallVector<Value> nextRegStates;
682 for (
auto [regState, regInput] :
683 llvm::zip(regStates, regInputs)) {
687 nextRegStates.push_back(smt::IteOp::create(
688 builder, loc, isPosedge, regInput, regState));
690 newDecls.append(nextRegStates);
695 for (; loopIndex < loopVals.size(); ++loopIndex)
696 newDecls.push_back(loopVals[loopIndex]);
698 attachDebugVariables(
699 builder, loc, oldCircuitInputTy,
700 ValueRange(newDecls).take_front(circuitFuncOp.getNumArguments()),
703 newDecls.push_back(violated);
705 scf::YieldOp::create(builder, loc, newDecls);
708 Value res = arith::XOrIOp::create(rewriter, loc, forOp->getResults().back(),
710 smt::YieldOp::create(rewriter, loc, res);
711 rewriter.replaceOp(op, solver.getResults());
716 bool risingClocksOnly;
717 SmallVectorImpl<Operation *> &propertylessBMCOps;
727struct ConvertVerifToSMTPass
728 :
public circt::impl::ConvertVerifToSMTBase<ConvertVerifToSMTPass> {
730 void runOnOperation()
override;
736 bool risingClocksOnly, SmallVectorImpl<Operation *> &propertylessBMCOps) {
737 patterns.add<VerifAssertOpConversion, VerifAssumeOpConversion,
738 LogicEquivalenceCheckingOpConversion,
739 RefinementCheckingOpConversion>(converter,
741 patterns.add<VerifBoundedModelCheckingOpConversion>(
742 converter,
patterns.getContext(), names, risingClocksOnly,
746void ConvertVerifToSMTPass::runOnOperation() {
747 ConversionTarget target(getContext());
748 target.addIllegalDialect<verif::VerifDialect>();
749 target.addLegalDialect<debug::DebugDialect, smt::SMTDialect,
750 arith::ArithDialect, scf::SCFDialect,
751 func::FuncDialect>();
752 target.addLegalOp<UnrealizedConversionCastOp>();
756 SymbolTable symbolTable(getOperation());
757 SmallVector<Operation *> propertylessBMCOps;
758 WalkResult assertionCheck = getOperation().walk(
760 if (
auto bmcOp = dyn_cast<verif::BoundedModelCheckingOp>(op)) {
763 auto regTypes = TypeRange(bmcOp.getCircuit().getArgumentTypes())
764 .take_back(bmcOp.getNumRegs());
765 for (
auto [regType, initVal] :
766 llvm::zip(regTypes, bmcOp.getInitialValues())) {
767 if (!isa<UnitAttr>(initVal)) {
768 if (!isa<IntegerType>(regType)) {
769 op->emitError(
"initial values are currently only supported for "
770 "registers with integer types");
771 return WalkResult::interrupt();
773 auto tyAttr = dyn_cast<TypedAttr>(initVal);
774 if (!tyAttr || tyAttr.getType() != regType) {
775 op->emitError(
"type of initial value does not match type of "
776 "initialized register");
777 return WalkResult::interrupt();
782 auto numClockArgs = 0;
783 for (
auto argType : bmcOp.getCircuit().getArgumentTypes())
784 if (isa<
seq::ClockType>(argType))
788 if (numClockArgs > 1) {
790 "only modules with one or zero clocks are currently supported");
791 return WalkResult::interrupt();
793 SmallVector<mlir::Operation *> worklist;
794 int numAssertions = 0;
795 op->walk([&](Operation *curOp) {
796 if (isa<verif::AssertOp>(curOp))
798 if (
auto inst = dyn_cast<InstanceOp>(curOp))
799 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
800 if (
auto func = dyn_cast<func::CallOp>(curOp))
801 worklist.push_back(symbolTable.lookup(func.getCallee()));
805 while (!worklist.empty()) {
806 auto *
module = worklist.pop_back_val();
807 module->walk([&](Operation *curOp) {
808 if (isa<verif::AssertOp>(curOp))
810 if (
auto inst = dyn_cast<InstanceOp>(curOp))
811 worklist.push_back(symbolTable.lookup(inst.getModuleName()));
812 if (
auto func = dyn_cast<func::CallOp>(curOp))
813 worklist.push_back(symbolTable.lookup(func.getCallee()));
815 if (numAssertions > 1)
818 if (numAssertions == 0) {
819 op->emitWarning(
"no property provided to check in module - will "
820 "trivially find no violations.");
821 propertylessBMCOps.push_back(bmcOp);
823 if (numAssertions > 1) {
825 "bounded model checking problems with multiple assertions are "
827 "correctly handled - instead, you can assert the "
828 "conjunction of your assertions");
829 return WalkResult::interrupt();
832 return WalkResult::advance();
834 if (assertionCheck.wasInterrupted())
835 return signalPassFailure();
836 RewritePatternSet
patterns(&getContext());
837 TypeConverter converter;
846 risingClocksOnly, propertylessBMCOps);
848 if (failed(mlir::applyPartialConversion(getOperation(), target,
850 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.