CIRCT 20.0.0git
Loading...
Searching...
No Matches
VerifOps.cpp
Go to the documentation of this file.
1//===- VerifOps.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
15#include "mlir/IR/Builders.h"
16#include "mlir/IR/OpImplementation.h"
17#include "mlir/IR/PatternMatch.h"
18#include "mlir/IR/SymbolTable.h"
19#include "mlir/IR/TypeRange.h"
20#include "mlir/Interfaces/FunctionImplementation.h"
21#include "mlir/Interfaces/SideEffectInterfaces.h"
22#include "llvm/ADT/MapVector.h"
23
24using namespace circt;
25using namespace verif;
26using namespace mlir;
27
28static ClockEdge ltlToVerifClockEdge(ltl::ClockEdge ce) {
29 switch (ce) {
30 case ltl::ClockEdge::Pos:
31 return ClockEdge::Pos;
32 case ltl::ClockEdge::Neg:
33 return ClockEdge::Neg;
34 case ltl::ClockEdge::Both:
35 return ClockEdge::Both;
36 }
37 llvm_unreachable("Unknown event control kind");
38}
39
40//===----------------------------------------------------------------------===//
41// HasBeenResetOp
42//===----------------------------------------------------------------------===//
43
44OpFoldResult HasBeenResetOp::fold(FoldAdaptor adaptor) {
45 // Fold to zero if the reset is a constant. In this case the op is either
46 // permanently in reset or never resets. Both mean that the reset never
47 // finishes, so this op never returns true.
48 if (adaptor.getReset())
49 return BoolAttr::get(getContext(), false);
50
51 // Fold to zero if the clock is a constant and the reset is synchronous. In
52 // that case the reset will never be started.
53 if (!adaptor.getAsync() && adaptor.getClock())
54 return BoolAttr::get(getContext(), false);
55
56 return {};
57}
58
59//===----------------------------------------------------------------------===//
60// AssertLikeOps Canonicalizations
61//===----------------------------------------------------------------------===//
62
63namespace AssertLikeOp {
64// assertlike(ltl.clock(prop, clk), en) -> clocked_assertlike(prop, en, clk)
65template <typename TargetOp, typename Op>
66static LogicalResult canonicalize(Op op, PatternRewriter &rewriter) {
67 // If the property is a block argument, then no canonicalization is possible
68 Value property = op.getProperty();
69 auto clockOp = property.getDefiningOp<ltl::ClockOp>();
70 if (!clockOp)
71 return failure();
72
73 // Check for clock operand
74 // If it exists, fold it into a clocked assertlike
75 rewriter.replaceOpWithNewOp<TargetOp>(
76 op, clockOp.getInput(), ltlToVerifClockEdge(clockOp.getEdge()),
77 clockOp.getClock(), op.getEnable(), op.getLabelAttr());
78
79 return success();
80}
81
82} // namespace AssertLikeOp
83
84LogicalResult AssertOp::canonicalize(AssertOp op, PatternRewriter &rewriter) {
85 return AssertLikeOp::canonicalize<ClockedAssertOp>(op, rewriter);
86}
87
88LogicalResult AssumeOp::canonicalize(AssumeOp op, PatternRewriter &rewriter) {
89 return AssertLikeOp::canonicalize<ClockedAssumeOp>(op, rewriter);
90}
91
92LogicalResult CoverOp::canonicalize(CoverOp op, PatternRewriter &rewriter) {
93 return AssertLikeOp::canonicalize<ClockedCoverOp>(op, rewriter);
94}
95
96//===----------------------------------------------------------------------===//
97// LogicalEquivalenceCheckingOp
98//===----------------------------------------------------------------------===//
99
100LogicalResult LogicEquivalenceCheckingOp::verifyRegions() {
101 if (getFirstCircuit().getArgumentTypes() !=
102 getSecondCircuit().getArgumentTypes())
103 return emitOpError() << "block argument types of both regions must match";
104 if (getFirstCircuit().front().getTerminator()->getOperandTypes() !=
105 getSecondCircuit().front().getTerminator()->getOperandTypes())
106 return emitOpError()
107 << "types of the yielded values of both regions must match";
108
109 return success();
110}
111
112//===----------------------------------------------------------------------===//
113// BoundedModelCheckingOp
114//===----------------------------------------------------------------------===//
115
116LogicalResult BoundedModelCheckingOp::verifyRegions() {
117 if (!getInit().getArgumentTypes().empty())
118 return emitOpError() << "init region must have no arguments";
119 auto *initYieldOp = getInit().front().getTerminator();
120 auto *loopYieldOp = getLoop().front().getTerminator();
121 if (initYieldOp->getOperandTypes() != loopYieldOp->getOperandTypes())
122 return emitOpError()
123 << "init and loop regions must yield the same types of values";
124 if (initYieldOp->getOperandTypes() != getLoop().front().getArgumentTypes())
125 return emitOpError()
126 << "loop region arguments must match the types of the values "
127 "yielded by the init and loop regions";
128 size_t totalClocks = 0;
129 auto circuitArgTy = getCircuit().getArgumentTypes();
130 for (auto input : circuitArgTy)
131 if (isa<seq::ClockType>(input))
132 totalClocks++;
133 auto initYields = initYieldOp->getOperands();
134 // We know init and loop yields match, so only need to check one
135 if (initYields.size() < totalClocks)
136 return emitOpError()
137 << "init and loop regions must yield at least as many clock "
138 "values as there are clock arguments to the circuit region";
139 for (size_t i = 0; i < totalClocks; i++) {
140 if (!isa<seq::ClockType>(initYieldOp->getOperand(i).getType()))
141 return emitOpError()
142 << "init and loop regions must yield as many clock values as "
143 "there are clock arguments in the circuit region "
144 "before any other values";
145 }
146 if (getNumRegs() > 0 && totalClocks == 0)
147 return emitOpError("num_regs is non-zero, but the circuit region has no "
148 "clock inputs to clock the registers");
149 auto initialValues = getInitialValues();
150 if (initialValues.size() != getNumRegs()) {
151 return emitOpError()
152 << "number of initial values must match the number of registers";
153 }
154 for (auto attr : initialValues) {
155 if (!isa<IntegerAttr, UnitAttr>(attr))
156 return emitOpError()
157 << "initial values must be integer or unit attributes";
158 }
159 return success();
160}
161
162//===----------------------------------------------------------------------===//
163// Generated code
164//===----------------------------------------------------------------------===//
165
166#define GET_OP_CLASSES
167#include "circt/Dialect/Verif/Verif.cpp.inc"
static InstancePath empty
static ClockEdge ltlToVerifClockEdge(ltl::ClockEdge ce)
Definition VerifOps.cpp:28
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
Definition VerifOps.cpp:66
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition seq.py:1
Definition verif.py:1