16#include "mlir/IR/Builders.h"
17#include "mlir/IR/OpImplementation.h"
18#include "mlir/IR/PatternMatch.h"
19#include "mlir/IR/SymbolTable.h"
20#include "mlir/IR/TypeRange.h"
21#include "mlir/Interfaces/FunctionImplementation.h"
22#include "mlir/Interfaces/SideEffectInterfaces.h"
23#include "llvm/ADT/MapVector.h"
31 case ltl::ClockEdge::Pos:
32 return ClockEdge::Pos;
33 case ltl::ClockEdge::Neg:
34 return ClockEdge::Neg;
35 case ltl::ClockEdge::Both:
36 return ClockEdge::Both;
38 llvm_unreachable(
"Unknown event control kind");
45OpFoldResult HasBeenResetOp::fold(FoldAdaptor adaptor) {
49 if (adaptor.getReset())
50 return BoolAttr::get(getContext(),
false);
54 if (!adaptor.getAsync() && adaptor.getClock())
55 return BoolAttr::get(getContext(),
false);
70 LogicalResult matchAndRewrite(Op op,
71 PatternRewriter &rewriter)
const override {
72 Value enable = op.getEnable();
76 if (!enableConst || !enableConst.getValue().isOne())
79 rewriter.modifyOpInPlace(op, [&]() { op.getEnableMutable().clear(); });
89 LogicalResult matchAndRewrite(Op op,
90 PatternRewriter &rewriter)
const override {
91 Value enable = op.getEnable();
95 if (!enableConst || !enableConst.getValue().isZero())
105template <
typename Op>
109 LogicalResult matchAndRewrite(Op op,
110 PatternRewriter &rewriter)
const override {
111 Value
property = op.getProperty();
115 property.template getDefiningOp<ltl::BooleanConstantOp>()) {
116 if (boolConst.getValueAttr().getValue()) {
117 rewriter.eraseOp(op);
123 if (
auto hwConst = property.template getDefiningOp<hw::ConstantOp>()) {
124 if (hwConst.getValue().isOne()) {
125 rewriter.eraseOp(op);
135template <
typename TargetOp,
typename Op>
139 LogicalResult matchAndRewrite(Op op,
140 PatternRewriter &rewriter)
const override {
141 auto clockOp = op.getProperty().template getDefiningOp<ltl::ClockOp>();
145 rewriter.replaceOpWithNewOp<TargetOp>(
147 clockOp.getClock(), op.getEnable(), op.getLabelAttr());
157void AssertOp::getCanonicalizationPatterns(RewritePatternSet &results,
159 results.add<EraseIfEnableFalse<AssertOp>, EraseIfPropertyTrue<AssertOp>,
160 RemoveEnableTrue<AssertOp>,
161 LowerToClocked<ClockedAssertOp, AssertOp>>(
context);
168void AssumeOp::getCanonicalizationPatterns(RewritePatternSet &results,
170 results.add<EraseIfEnableFalse<AssumeOp>, EraseIfPropertyTrue<AssumeOp>,
171 RemoveEnableTrue<AssumeOp>,
172 LowerToClocked<ClockedAssumeOp, AssumeOp>>(
context);
179void CoverOp::getCanonicalizationPatterns(RewritePatternSet &results,
184 .add<RemoveEnableTrue<CoverOp>, LowerToClocked<ClockedCoverOp, CoverOp>>(
192void ClockedAssertOp::getCanonicalizationPatterns(RewritePatternSet &results,
194 results.add<RemoveEnableTrue<ClockedAssertOp>,
195 EraseIfEnableFalse<ClockedAssertOp>,
196 EraseIfPropertyTrue<ClockedAssertOp>>(
context);
203void ClockedAssumeOp::getCanonicalizationPatterns(RewritePatternSet &results,
205 results.add<RemoveEnableTrue<ClockedAssumeOp>,
206 EraseIfEnableFalse<ClockedAssumeOp>,
207 EraseIfPropertyTrue<ClockedAssumeOp>>(
context);
214void ClockedCoverOp::getCanonicalizationPatterns(RewritePatternSet &results,
218 results.add<RemoveEnableTrue<ClockedCoverOp>>(
context);
225template <
typename OpTy>
227 if (op.getFirstCircuit().getArgumentTypes() !=
228 op.getSecondCircuit().getArgumentTypes())
229 return op.emitOpError()
230 <<
"block argument types of both regions must match";
231 if (op.getFirstCircuit().front().getTerminator()->getOperandTypes() !=
232 op.getSecondCircuit().front().getTerminator()->getOperandTypes())
233 return op.emitOpError()
234 <<
"types of the yielded values of both regions must match";
243LogicalResult LogicEquivalenceCheckingOp::verifyRegions() {
251LogicalResult RefinementCheckingOp::verifyRegions() {
259LogicalResult BoundedModelCheckingOp::verifyRegions() {
260 if (!getInit().getArgumentTypes().
empty())
261 return emitOpError() <<
"init region must have no arguments";
262 auto *initYieldOp = getInit().front().getTerminator();
263 auto *loopYieldOp = getLoop().front().getTerminator();
264 if (initYieldOp->getOperandTypes() != loopYieldOp->getOperandTypes())
266 <<
"init and loop regions must yield the same types of values";
267 if (initYieldOp->getOperandTypes() != getLoop().front().getArgumentTypes())
269 <<
"loop region arguments must match the types of the values "
270 "yielded by the init and loop regions";
271 size_t totalClocks = 0;
272 auto circuitArgTy = getCircuit().getArgumentTypes();
273 for (
auto input : circuitArgTy)
274 if (isa<
seq::ClockType>(input))
276 auto initYields = initYieldOp->getOperands();
278 if (initYields.size() < totalClocks)
280 <<
"init and loop regions must yield at least as many clock "
281 "values as there are clock arguments to the circuit region";
282 for (
size_t i = 0; i < totalClocks; i++) {
283 if (!isa<seq::ClockType>(initYieldOp->getOperand(i).getType()))
285 <<
"init and loop regions must yield as many clock values as "
286 "there are clock arguments in the circuit region "
287 "before any other values";
289 if (getNumRegs() > 0 && totalClocks == 0)
290 return emitOpError(
"num_regs is non-zero, but the circuit region has no "
291 "clock inputs to clock the registers");
292 auto initialValues = getInitialValues();
293 if (initialValues.size() != getNumRegs()) {
295 <<
"number of initial values must match the number of registers";
297 for (
auto attr : initialValues) {
298 if (!isa<IntegerAttr, UnitAttr>(attr))
300 <<
"initial values must be integer or unit attributes";
309LogicalResult SimulationOp::verifyRegions() {
310 if (getBody()->getNumArguments() != 2)
311 return emitOpError() <<
"must have two block arguments";
312 if (!isa<seq::ClockType>(getBody()->getArgument(0).getType()))
313 return emitOpError() <<
"block argument #0 must be of type `!seq.clock`";
314 if (!getBody()->getArgument(1).getType().isSignlessInteger(1))
315 return emitOpError() <<
"block argument #1 must be of type `i1`";
317 auto *yieldOp = getBody()->getTerminator();
318 if (yieldOp->getNumOperands() != 2)
319 return yieldOp->emitOpError() <<
"must have two operands";
320 if (!yieldOp->getOperand(0).getType().isSignlessInteger(1))
321 return yieldOp->emitOpError() <<
"operand #0 must be of type `i1`";
322 if (!yieldOp->getOperand(1).getType().isSignlessInteger(1))
323 return yieldOp->emitOpError() <<
"operand #1 must be of type `i1`";
328void SimulationOp::getAsmBlockArgumentNames(Region ®ion,
330 if (region.empty() || region.getNumArguments() != 2)
332 setNameFn(region.getArgument(0),
"clock");
333 setNameFn(region.getArgument(1),
"init");
340#define GET_OP_CLASSES
341#include "circt/Dialect/Verif/Verif.cpp.inc"
static std::unique_ptr< Context > context
static InstancePath empty
static ClockEdge ltlToVerifClockEdge(ltl::ClockEdge ce)
static LogicalResult verifyCircuitRelationCheckOpRegions(OpTy &op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn