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"
47 class OperationVerifier {
51 explicit OperationVerifier(
bool verifyRecursively)
52 : verifyRecursively(verifyRecursively) {}
55 LogicalResult verifyOpAndDominance(
Operation &op);
59 using WorkItemEntry = llvm::PointerIntPair<WorkItem, 1, bool>;
65 LogicalResult verifyOnEntrance(
Block &block);
66 LogicalResult verifyOnEntrance(
Operation &op);
68 LogicalResult verifyOnExit(
Block &block);
69 LogicalResult verifyOnExit(
Operation &op);
72 LogicalResult verifyOperation(
Operation &op);
76 LogicalResult verifyDominanceOfContainedRegions(
Operation &op,
81 bool verifyRecursively;
85 LogicalResult OperationVerifier::verifyOpAndDominance(
Operation &op) {
87 if (failed(verifyOperation(op)))
96 if (failed(verifyDominanceOfContainedRegions(op, domInfo)))
112 if (!llvm::hasSingleElement(*block->
getParent()))
118 LogicalResult OperationVerifier::verifyOnEntrance(
Block &block) {
120 if (arg.getOwner() != &block)
121 return emitError(arg.getLoc(),
"block argument not owned by block");
128 "empty block: expect at least a terminator");
137 "operation with block successors must terminate its parent block");
143 LogicalResult OperationVerifier::verifyOnExit(
Block &block) {
147 if (successor->getParent() != block.
getParent())
149 "branching to block of a different region");
157 return block.
back().
emitError(
"block with no terminator, has ")
163 LogicalResult OperationVerifier::verifyOnEntrance(
Operation &op) {
167 return op.
emitError(
"null operand found");
172 if (
auto *dialect = attr.getNameDialect())
173 if (failed(dialect->verifyOperationAttribute(&op, attr)))
179 std::optional<RegisteredOperationName> registeredInfo =
181 if (registeredInfo && failed(registeredInfo->verifyInvariants(&op)))
187 auto kindInterface = dyn_cast<RegionKindInterface>(&op);
191 for (
unsigned i = 0; i < numRegions; ++i) {
192 Region ®ion = regions[i];
204 << i <<
" to have 0 or 1 blocks";
214 "entry block of region may not have predecessors");
219 LogicalResult OperationVerifier::verifyOnExit(
Operation &op) {
221 if (verifyRecursively) {
223 for (
Block &block : region)
225 if (o.getNumRegions() != 0 &&
227 opsWithIsolatedRegions.push_back(&o);
231 [&](
Operation *o) { return verifyOpAndDominance(*o); })))
234 std::optional<RegisteredOperationName> registeredInfo =
238 if (registeredInfo && failed(registeredInfo->verifyRegionInvariants(&op)))
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";
259 return op.
emitError(
"unregistered operation '")
261 <<
"') that does not allow unknown operations";
271 LogicalResult OperationVerifier::verifyOperation(
Operation &op) {
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();
289 visit([
this](
auto *workItem) {
return verifyOnExit(*workItem); },
298 [
this](
auto *workItem) {
return verifyOnEntrance(*workItem); },
302 if (
Block *currentBlock = dyn_cast<Block *>(item)) {
304 for (
Operation &o : llvm::reverse(*currentBlock)) {
307 worklist.emplace_back(&o);
312 Operation ¤tOp = *cast<Operation *>(item);
313 if (verifyRecursively)
315 for (
Block &block : llvm::reverse(region))
316 worklist.emplace_back(&block);
329 << operandNo <<
" does not dominate this use";
337 note <<
"operand defined here";
339 Block *block2 = useOp->getBlock();
342 if (block1 == block2)
343 note <<
" (op in the same block)";
344 else if (region1 == region2)
345 note <<
" (op in the same region)";
347 note <<
" (op in a parent region)";
349 note <<
" (op in a child region)";
351 note <<
" (op is neither in a parent nor in a child region)";
356 Block *block2 = llvm::cast<BlockArgument>(operand).getOwner();
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)";
374 note <<
" in a parent region)";
376 note <<
" in a child region)";
378 note <<
" neither in a parent nor in a child region)";
383 OperationVerifier::verifyDominanceOfContainedRegions(
Operation &op,
386 while (!worklist.empty()) {
387 auto *op = worklist.pop_back_val();
389 for (
auto &block : region.getBlocks()) {
392 for (
auto &op : block) {
412 worklist.push_back(&op);
426 OperationVerifier verifier(verifyRecursively);
427 return verifier.verifyOpAndDominance(*op);
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static std::string diag(const llvm::Value &value)
static bool mayBeValidWithoutTerminator(Block *block)
Returns true if this block may be valid without terminator.
static void diagnoseInvalidOperandDominance(Operation &op, unsigned operandNo)
Emit an error when the specified operand of the specified operation is an invalid use because of domi...
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
SuccessorRange getSuccessors()
BlockArgListType getArguments()
bool hasNoPredecessors()
Return true if this block has no predecessors.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
StringRef getNamespace() const
bool allowsUnknownOperations() const
Returns true if this dialect allows for unregistered operations, i.e.
A class for computing basic dominance information.
bool properlyDominates(Operation *a, Operation *b, bool enclosingOpOk=true) const
Return true if operation A properly dominates operation B, i.e.
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
This class indicates that the regions associated with this op don't have terminators.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
std::optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, std::nullopt otherwise.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
unsigned getNumSuccessors()
bool isRegistered()
Returns true if this operation has a registered operation description, otherwise false.
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
operand_range getOperands()
Returns an iterator on the underlying Value's.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
bool isProperAncestor(Region *other)
Return true if this region is a proper ancestor of the other region.
Location getLoc()
Return a location for this region.
bool hasOneBlock()
Return true if this region has exactly one block.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
bool isReachableFromEntry(Block *a) const
Return true if the specified block is reachable from the entry block of its region.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
LogicalResult failableParallelForEach(MLIRContext *context, IteratorT begin, IteratorT end, FuncT &&func)
Invoke the given function on the elements between [begin, end) asynchronously.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
RegionKind
The kinds of regions contained in an operation.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...