Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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// CircuitRelationCheckOp
98//===----------------------------------------------------------------------===//
99
100template <typename OpTy>
101static LogicalResult verifyCircuitRelationCheckOpRegions(OpTy &op) {
102 if (op.getFirstCircuit().getArgumentTypes() !=
103 op.getSecondCircuit().getArgumentTypes())
104 return op.emitOpError()
105 << "block argument types of both regions must match";
106 if (op.getFirstCircuit().front().getTerminator()->getOperandTypes() !=
107 op.getSecondCircuit().front().getTerminator()->getOperandTypes())
108 return op.emitOpError()
109 << "types of the yielded values of both regions must match";
110
111 return success();
112}
113
114//===----------------------------------------------------------------------===//
115// LogicalEquivalenceCheckingOp
116//===----------------------------------------------------------------------===//
117
118LogicalResult LogicEquivalenceCheckingOp::verifyRegions() {
120}
121
122//===----------------------------------------------------------------------===//
123// RefinementCheckingOp
124//===----------------------------------------------------------------------===//
125
126LogicalResult RefinementCheckingOp::verifyRegions() {
128}
129
130//===----------------------------------------------------------------------===//
131// BoundedModelCheckingOp
132//===----------------------------------------------------------------------===//
133
134LogicalResult BoundedModelCheckingOp::verifyRegions() {
135 if (!getInit().getArgumentTypes().empty())
136 return emitOpError() << "init region must have no arguments";
137 auto *initYieldOp = getInit().front().getTerminator();
138 auto *loopYieldOp = getLoop().front().getTerminator();
139 if (initYieldOp->getOperandTypes() != loopYieldOp->getOperandTypes())
140 return emitOpError()
141 << "init and loop regions must yield the same types of values";
142 if (initYieldOp->getOperandTypes() != getLoop().front().getArgumentTypes())
143 return emitOpError()
144 << "loop region arguments must match the types of the values "
145 "yielded by the init and loop regions";
146 size_t totalClocks = 0;
147 auto circuitArgTy = getCircuit().getArgumentTypes();
148 for (auto input : circuitArgTy)
149 if (isa<seq::ClockType>(input))
150 totalClocks++;
151 auto initYields = initYieldOp->getOperands();
152 // We know init and loop yields match, so only need to check one
153 if (initYields.size() < totalClocks)
154 return emitOpError()
155 << "init and loop regions must yield at least as many clock "
156 "values as there are clock arguments to the circuit region";
157 for (size_t i = 0; i < totalClocks; i++) {
158 if (!isa<seq::ClockType>(initYieldOp->getOperand(i).getType()))
159 return emitOpError()
160 << "init and loop regions must yield as many clock values as "
161 "there are clock arguments in the circuit region "
162 "before any other values";
163 }
164 if (getNumRegs() > 0 && totalClocks == 0)
165 return emitOpError("num_regs is non-zero, but the circuit region has no "
166 "clock inputs to clock the registers");
167 auto initialValues = getInitialValues();
168 if (initialValues.size() != getNumRegs()) {
169 return emitOpError()
170 << "number of initial values must match the number of registers";
171 }
172 for (auto attr : initialValues) {
173 if (!isa<IntegerAttr, UnitAttr>(attr))
174 return emitOpError()
175 << "initial values must be integer or unit attributes";
176 }
177 return success();
178}
179
180//===----------------------------------------------------------------------===//
181// SimulationOp
182//===----------------------------------------------------------------------===//
183
184LogicalResult SimulationOp::verifyRegions() {
185 if (getBody()->getNumArguments() != 2)
186 return emitOpError() << "must have two block arguments";
187 if (!isa<seq::ClockType>(getBody()->getArgument(0).getType()))
188 return emitOpError() << "block argument #0 must be of type `!seq.clock`";
189 if (!getBody()->getArgument(1).getType().isSignlessInteger(1))
190 return emitOpError() << "block argument #1 must be of type `i1`";
191
192 auto *yieldOp = getBody()->getTerminator();
193 if (yieldOp->getNumOperands() != 2)
194 return yieldOp->emitOpError() << "must have two operands";
195 if (!yieldOp->getOperand(0).getType().isSignlessInteger(1))
196 return yieldOp->emitOpError() << "operand #0 must be of type `i1`";
197 if (!yieldOp->getOperand(1).getType().isSignlessInteger(1))
198 return yieldOp->emitOpError() << "operand #1 must be of type `i1`";
199
200 return success();
201}
202
203void SimulationOp::getAsmBlockArgumentNames(Region &region,
204 OpAsmSetValueNameFn setNameFn) {
205 if (region.empty() || region.getNumArguments() != 2)
206 return;
207 setNameFn(region.getArgument(0), "clock");
208 setNameFn(region.getArgument(1), "init");
209}
210
211//===----------------------------------------------------------------------===//
212// Generated code
213//===----------------------------------------------------------------------===//
214
215#define GET_OP_CLASSES
216#include "circt/Dialect/Verif/Verif.cpp.inc"
static InstancePath empty
static ClockEdge ltlToVerifClockEdge(ltl::ClockEdge ce)
Definition VerifOps.cpp:28
static LogicalResult verifyCircuitRelationCheckOpRegions(OpTy &op)
Definition VerifOps.cpp:101
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
Definition VerifOps.cpp:66
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:183
Definition seq.py:1
Definition verif.py:1