1 //===- Verifier.cpp - MLIR Verifier Implementation ------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the verify() methods on the various IR types, performing
10 // (potentially expensive) checks on the holistic structure of the code. This
11 // can be used for detecting bugs in compiler transformations and hand written
14 // The checks in this file are only for things that can occur as part of IR
15 // transformations: e.g. violation of dominance information, malformed operation
16 // attributes, etc. MLIR supports transformations moving IR through locally
17 // invalid states (e.g. unlinking an operation from a block before re-inserting
18 // it in a new place), but each transformation must complete with the IR in a
21 // This should not check for things that are always wrong by construction (e.g.
22 // attributes or other immutable structures that are incorrect), because those
23 // are not mutable and can be checked at time of construction.
25 //===----------------------------------------------------------------------===//
27 #include "mlir/IR/Verifier.h"
28 #include "mlir/IR/Attributes.h"
29 #include "mlir/IR/Dialect.h"
30 #include "mlir/IR/Dominance.h"
31 #include "mlir/IR/Operation.h"
32 #include "mlir/IR/RegionKindInterface.h"
33 #include "mlir/IR/Threading.h"
34 #include "llvm/ADT/DenseMapInfoVariant.h"
35 #include "llvm/ADT/PointerIntPair.h"
36 #include "llvm/ADT/StringMap.h"
37 #include "llvm/Support/FormatVariadic.h"
38 #include "llvm/Support/PrettyStackTrace.h"
39 #include "llvm/Support/Regex.h"
46 /// This class encapsulates all the state used to verify an operation region.
47 class OperationVerifier
{
49 /// If `verifyRecursively` is true, then this will also recursively verify
50 /// nested operations.
51 explicit OperationVerifier(bool verifyRecursively
)
52 : verifyRecursively(verifyRecursively
) {}
54 /// Verify the given operation.
55 LogicalResult
verifyOpAndDominance(Operation
&op
);
58 using WorkItem
= llvm::PointerUnion
<Operation
*, Block
*>;
59 using WorkItemEntry
= llvm::PointerIntPair
<WorkItem
, 1, bool>;
61 /// This verifier uses a DFS of the tree of operations/blocks. The method
62 /// verifyOnEntrance is invoked when we visit a node for the first time, i.e.
63 /// before visiting its children. The method verifyOnExit is invoked
64 /// upon exit from the subtree, i.e. when we visit a node for the second time.
65 LogicalResult
verifyOnEntrance(Block
&block
);
66 LogicalResult
verifyOnEntrance(Operation
&op
);
68 LogicalResult
verifyOnExit(Block
&block
);
69 LogicalResult
verifyOnExit(Operation
&op
);
71 /// Verify the properties and dominance relationships of this operation.
72 LogicalResult
verifyOperation(Operation
&op
);
74 /// Verify the dominance property of regions contained within the given
76 LogicalResult
verifyDominanceOfContainedRegions(Operation
&op
,
77 DominanceInfo
&domInfo
);
79 /// A flag indicating if this verifier should recursively verify nested
81 bool verifyRecursively
;
85 LogicalResult
OperationVerifier::verifyOpAndDominance(Operation
&op
) {
86 // Verify the operation first, collecting any IsolatedFromAbove operations.
87 if (failed(verifyOperation(op
)))
90 // Since everything looks structurally ok to this point, we do a dominance
91 // check for any nested regions. We do this as a second pass since malformed
92 // CFG's can cause dominator analysis construction to crash and we want the
93 // verifier to be resilient to malformed code.
94 if (op
.getNumRegions() != 0) {
95 DominanceInfo domInfo
;
96 if (failed(verifyDominanceOfContainedRegions(op
, domInfo
)))
103 /// Returns true if this block may be valid without terminator. That is if:
104 /// - it does not have a parent region.
105 /// - Or the parent region have a single block and:
106 /// - This region does not have a parent op.
107 /// - Or the parent op is unregistered.
108 /// - Or the parent op has the NoTerminator trait.
109 static bool mayBeValidWithoutTerminator(Block
*block
) {
110 if (!block
->getParent())
112 if (!llvm::hasSingleElement(*block
->getParent()))
114 Operation
*op
= block
->getParentOp();
115 return !op
|| op
->mightHaveTrait
<OpTrait::NoTerminator
>();
118 LogicalResult
OperationVerifier::verifyOnEntrance(Block
&block
) {
119 for (auto arg
: block
.getArguments())
120 if (arg
.getOwner() != &block
)
121 return emitError(arg
.getLoc(), "block argument not owned by block");
123 // Verify that this block has a terminator.
125 if (mayBeValidWithoutTerminator(&block
))
127 return emitError(block
.getParent()->getLoc(),
128 "empty block: expect at least a terminator");
131 // Check each operation, and make sure there are no branches out of the
132 // middle of this block.
133 for (Operation
&op
: block
) {
134 // Only the last instructions is allowed to have successors.
135 if (op
.getNumSuccessors() != 0 && &op
!= &block
.back())
137 "operation with block successors must terminate its parent block");
143 LogicalResult
OperationVerifier::verifyOnExit(Block
&block
) {
144 // Verify that this block is not branching to a block of a different
146 for (Block
*successor
: block
.getSuccessors())
147 if (successor
->getParent() != block
.getParent())
148 return block
.back().emitOpError(
149 "branching to block of a different region");
151 // If this block doesn't have to have a terminator, don't require it.
152 if (mayBeValidWithoutTerminator(&block
))
155 Operation
&terminator
= block
.back();
156 if (!terminator
.mightHaveTrait
<OpTrait::IsTerminator
>())
157 return block
.back().emitError("block with no terminator, has ")
163 LogicalResult
OperationVerifier::verifyOnEntrance(Operation
&op
) {
164 // Check that operands are non-nil and structurally ok.
165 for (auto operand
: op
.getOperands())
167 return op
.emitError("null operand found");
169 /// Verify that all of the attributes are okay.
170 for (auto attr
: op
.getDiscardableAttrDictionary()) {
171 // Check for any optional dialect specific attributes.
172 if (auto *dialect
= attr
.getNameDialect())
173 if (failed(dialect
->verifyOperationAttribute(&op
, attr
)))
177 // If we can get operation info for this, check the custom hook.
178 OperationName opName
= op
.getName();
179 std::optional
<RegisteredOperationName
> registeredInfo
=
180 opName
.getRegisteredInfo();
181 if (registeredInfo
&& failed(registeredInfo
->verifyInvariants(&op
)))
184 unsigned numRegions
= op
.getNumRegions();
187 auto kindInterface
= dyn_cast
<RegionKindInterface
>(&op
);
188 SmallVector
<Operation
*> opsWithIsolatedRegions
;
189 // Verify that all child regions are ok.
190 MutableArrayRef
<Region
> regions
= op
.getRegions();
191 for (unsigned i
= 0; i
< numRegions
; ++i
) {
192 Region
®ion
= regions
[i
];
194 kindInterface
? kindInterface
.getRegionKind(i
) : RegionKind::SSACFG
;
195 // Check that Graph Regions only have a single basic block. This is
196 // similar to the code in SingleBlockImplicitTerminator, but doesn't
197 // require the trait to be specified. This arbitrary limitation is
198 // designed to limit the number of cases that have to be handled by
199 // transforms and conversions.
200 if (op
.isRegistered() && kind
== RegionKind::Graph
) {
201 // Non-empty regions must contain a single basic block.
202 if (!region
.empty() && !region
.hasOneBlock())
203 return op
.emitOpError("expects graph region #")
204 << i
<< " to have 0 or 1 blocks";
210 // Verify the first block has no predecessors.
211 Block
*firstBB
= ®ion
.front();
212 if (!firstBB
->hasNoPredecessors())
213 return emitError(op
.getLoc(),
214 "entry block of region may not have predecessors");
219 LogicalResult
OperationVerifier::verifyOnExit(Operation
&op
) {
220 SmallVector
<Operation
*> opsWithIsolatedRegions
;
221 if (verifyRecursively
) {
222 for (Region
®ion
: op
.getRegions())
223 for (Block
&block
: region
)
224 for (Operation
&o
: block
)
225 if (o
.getNumRegions() != 0 &&
226 o
.hasTrait
<OpTrait::IsIsolatedFromAbove
>())
227 opsWithIsolatedRegions
.push_back(&o
);
229 if (failed(failableParallelForEach(
230 op
.getContext(), opsWithIsolatedRegions
,
231 [&](Operation
*o
) { return verifyOpAndDominance(*o
); })))
233 OperationName opName
= op
.getName();
234 std::optional
<RegisteredOperationName
> registeredInfo
=
235 opName
.getRegisteredInfo();
236 // After the region ops are verified, run the verifiers that have additional
237 // region invariants need to veirfy.
238 if (registeredInfo
&& failed(registeredInfo
->verifyRegionInvariants(&op
)))
241 // If this is a registered operation, there is nothing left to do.
245 // Otherwise, verify that the parent dialect allows un-registered operations.
246 Dialect
*dialect
= opName
.getDialect();
248 if (!op
.getContext()->allowsUnregisteredDialects()) {
249 return op
.emitOpError()
250 << "created with unregistered dialect. If this is "
251 "intended, please call allowUnregisteredDialects() on the "
252 "MLIRContext, or use -allow-unregistered-dialect with "
253 "the MLIR opt tool used";
258 if (!dialect
->allowsUnknownOperations()) {
259 return op
.emitError("unregistered operation '")
260 << op
.getName() << "' found in dialect ('" << dialect
->getNamespace()
261 << "') that does not allow unknown operations";
267 /// Verify the properties and dominance relationships of this operation,
268 /// stopping region "recursion" at any "isolated from above operations".
269 /// Such ops are collected separately and verified inside
270 /// verifyBlockPostChildren.
271 LogicalResult
OperationVerifier::verifyOperation(Operation
&op
) {
272 SmallVector
<WorkItemEntry
> worklist
{{&op
, false}};
273 while (!worklist
.empty()) {
274 WorkItemEntry
&top
= worklist
.back();
276 auto visit
= [](auto &&visitor
, WorkItem w
) {
277 if (auto *o
= dyn_cast
<Operation
*>(w
))
279 return visitor(cast
<Block
*>(w
));
282 const bool isExit
= top
.getInt();
284 auto item
= top
.getPointer();
286 // 2nd visit of this work item ("exit").
289 visit([this](auto *workItem
) { return verifyOnExit(*workItem
); },
296 // 1st visit of this work item ("entrance").
298 [this](auto *workItem
) { return verifyOnEntrance(*workItem
); },
302 if (Block
*currentBlock
= dyn_cast
<Block
*>(item
)) {
303 // Skip "isolated from above operations".
304 for (Operation
&o
: llvm::reverse(*currentBlock
)) {
305 if (o
.getNumRegions() == 0 ||
306 !o
.hasTrait
<OpTrait::IsIsolatedFromAbove
>())
307 worklist
.emplace_back(&o
);
312 Operation
¤tOp
= *cast
<Operation
*>(item
);
313 if (verifyRecursively
)
314 for (Region
®ion
: llvm::reverse(currentOp
.getRegions()))
315 for (Block
&block
: llvm::reverse(region
))
316 worklist
.emplace_back(&block
);
321 //===----------------------------------------------------------------------===//
322 // Dominance Checking
323 //===----------------------------------------------------------------------===//
325 /// Emit an error when the specified operand of the specified operation is an
326 /// invalid use because of dominance properties.
327 static void diagnoseInvalidOperandDominance(Operation
&op
, unsigned operandNo
) {
328 InFlightDiagnostic diag
= op
.emitError("operand #")
329 << operandNo
<< " does not dominate this use";
331 Value operand
= op
.getOperand(operandNo
);
333 /// Attach a note to an in-flight diagnostic that provide more information
334 /// about where an op operand is defined.
335 if (auto *useOp
= operand
.getDefiningOp()) {
336 Diagnostic
¬e
= diag
.attachNote(useOp
->getLoc());
337 note
<< "operand defined here";
338 Block
*block1
= op
.getBlock();
339 Block
*block2
= useOp
->getBlock();
340 Region
*region1
= block1
->getParent();
341 Region
*region2
= block2
->getParent();
342 if (block1
== block2
)
343 note
<< " (op in the same block)";
344 else if (region1
== region2
)
345 note
<< " (op in the same region)";
346 else if (region2
->isProperAncestor(region1
))
347 note
<< " (op in a parent region)";
348 else if (region1
->isProperAncestor(region2
))
349 note
<< " (op in a child region)";
351 note
<< " (op is neither in a parent nor in a child region)";
354 // Block argument case.
355 Block
*block1
= op
.getBlock();
356 Block
*block2
= llvm::cast
<BlockArgument
>(operand
).getOwner();
357 Region
*region1
= block1
->getParent();
358 Region
*region2
= block2
->getParent();
359 Location loc
= UnknownLoc::get(op
.getContext());
360 if (block2
->getParentOp())
361 loc
= block2
->getParentOp()->getLoc();
362 Diagnostic
¬e
= diag
.attachNote(loc
);
364 note
<< " (block without parent)";
367 if (block1
== block2
)
368 llvm::report_fatal_error("Internal error in dominance verification");
369 int index
= std::distance(region2
->begin(), block2
->getIterator());
370 note
<< "operand defined as a block argument (block #" << index
;
371 if (region1
== region2
)
372 note
<< " in the same region)";
373 else if (region2
->isProperAncestor(region1
))
374 note
<< " in a parent region)";
375 else if (region1
->isProperAncestor(region2
))
376 note
<< " in a child region)";
378 note
<< " neither in a parent nor in a child region)";
381 /// Verify the dominance of each of the nested blocks within the given operation
383 OperationVerifier::verifyDominanceOfContainedRegions(Operation
&op
,
384 DominanceInfo
&domInfo
) {
385 llvm::SmallVector
<Operation
*, 8> worklist
{&op
};
386 while (!worklist
.empty()) {
387 auto *op
= worklist
.pop_back_val();
388 for (auto ®ion
: op
->getRegions())
389 for (auto &block
: region
.getBlocks()) {
390 // Dominance is only meaningful inside reachable blocks.
391 bool isReachable
= domInfo
.isReachableFromEntry(&block
);
392 for (auto &op
: block
) {
394 // Check that operands properly dominate this use.
395 for (const auto &operand
: llvm::enumerate(op
.getOperands())) {
396 if (domInfo
.properlyDominates(operand
.value(), &op
))
399 diagnoseInvalidOperandDominance(op
, operand
.index());
404 // Recursively verify dominance within each operation in the block,
405 // even if the block itself is not reachable, or we are in a region
406 // which doesn't respect dominance.
407 if (verifyRecursively
&& op
.getNumRegions() != 0) {
408 // If this operation is IsolatedFromAbove, then we'll handle it in
409 // the outer verification loop.
410 if (op
.hasTrait
<OpTrait::IsIsolatedFromAbove
>())
412 worklist
.push_back(&op
);
421 //===----------------------------------------------------------------------===//
423 //===----------------------------------------------------------------------===//
425 LogicalResult
mlir::verify(Operation
*op
, bool verifyRecursively
) {
426 OperationVerifier
verifier(verifyRecursively
);
427 return verifier
.verifyOpAndDominance(*op
);