MLIR  16.0.0git
PDL.cpp
Go to the documentation of this file.
1 //===- PDL.cpp - Pattern Descriptor Language Dialect ----------------------===//
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 
12 #include "mlir/IR/BuiltinTypes.h"
14 #include "llvm/ADT/DenseSet.h"
15 #include "llvm/ADT/TypeSwitch.h"
16 
17 using namespace mlir;
18 using namespace mlir::pdl;
19 
20 #include "mlir/Dialect/PDL/IR/PDLOpsDialect.cpp.inc"
21 
22 //===----------------------------------------------------------------------===//
23 // PDLDialect
24 //===----------------------------------------------------------------------===//
25 
26 void PDLDialect::initialize() {
27  addOperations<
28 #define GET_OP_LIST
29 #include "mlir/Dialect/PDL/IR/PDLOps.cpp.inc"
30  >();
31  registerTypes();
32 }
33 
34 //===----------------------------------------------------------------------===//
35 // PDL Operations
36 //===----------------------------------------------------------------------===//
37 
38 /// Returns true if the given operation is used by a "binding" pdl operation.
39 static bool hasBindingUse(Operation *op) {
40  for (Operation *user : op->getUsers())
41  // A result by itself is not binding, it must also be bound.
42  if (!isa<ResultOp, ResultsOp>(user) || hasBindingUse(user))
43  return true;
44  return false;
45 }
46 
47 /// Returns success if the given operation is not in the main matcher body or
48 /// is used by a "binding" operation. On failure, emits an error.
50  // If the parent is not a pattern, there is nothing to do.
51  if (!isa<PatternOp>(op->getParentOp()))
52  return success();
53  if (hasBindingUse(op))
54  return success();
55  return op->emitOpError(
56  "expected a bindable user when defined in the matcher body of a "
57  "`pdl.pattern`");
58 }
59 
60 /// Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s)
61 /// connected to the given operation.
62 static void visit(Operation *op, DenseSet<Operation *> &visited) {
63  // If the parent is not a pattern, there is nothing to do.
64  if (!isa<PatternOp>(op->getParentOp()) || isa<RewriteOp>(op))
65  return;
66 
67  // Ignore if already visited.
68  if (visited.contains(op))
69  return;
70 
71  // Mark as visited.
72  visited.insert(op);
73 
74  // Traverse the operands / parent.
76  .Case<OperationOp>([&visited](auto operation) {
77  for (Value operand : operation.getOperandValues())
78  visit(operand.getDefiningOp(), visited);
79  })
80  .Case<ResultOp, ResultsOp>([&visited](auto result) {
81  visit(result.getParent().getDefiningOp(), visited);
82  });
83 
84  // Traverse the users.
85  for (Operation *user : op->getUsers())
86  visit(user, visited);
87 }
88 
89 //===----------------------------------------------------------------------===//
90 // pdl::ApplyNativeConstraintOp
91 //===----------------------------------------------------------------------===//
92 
94  if (getNumOperands() == 0)
95  return emitOpError("expected at least one argument");
96  return success();
97 }
98 
99 //===----------------------------------------------------------------------===//
100 // pdl::ApplyNativeRewriteOp
101 //===----------------------------------------------------------------------===//
102 
104  if (getNumOperands() == 0 && getNumResults() == 0)
105  return emitOpError("expected at least one argument or result");
106  return success();
107 }
108 
109 //===----------------------------------------------------------------------===//
110 // pdl::AttributeOp
111 //===----------------------------------------------------------------------===//
112 
114  Value attrType = getValueType();
115  Optional<Attribute> attrValue = getValue();
116 
117  if (!attrValue) {
118  if (isa<RewriteOp>((*this)->getParentOp()))
119  return emitOpError(
120  "expected constant value when specified within a `pdl.rewrite`");
121  return verifyHasBindingUse(*this);
122  }
123  if (attrType)
124  return emitOpError("expected only one of [`type`, `value`] to be set");
125  return success();
126 }
127 
128 //===----------------------------------------------------------------------===//
129 // pdl::OperandOp
130 //===----------------------------------------------------------------------===//
131 
133 
134 //===----------------------------------------------------------------------===//
135 // pdl::OperandsOp
136 //===----------------------------------------------------------------------===//
137 
139 
140 //===----------------------------------------------------------------------===//
141 // pdl::OperationOp
142 //===----------------------------------------------------------------------===//
143 
145  OpAsmParser &p,
147  ArrayAttr &attrNamesAttr) {
148  Builder &builder = p.getBuilder();
149  SmallVector<Attribute, 4> attrNames;
150  if (succeeded(p.parseOptionalLBrace())) {
151  auto parseOperands = [&]() {
152  StringAttr nameAttr;
154  if (p.parseAttribute(nameAttr) || p.parseEqual() ||
155  p.parseOperand(operand))
156  return failure();
157  attrNames.push_back(nameAttr);
158  attrOperands.push_back(operand);
159  return success();
160  };
161  if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())
162  return failure();
163  }
164  attrNamesAttr = builder.getArrayAttr(attrNames);
165  return success();
166 }
167 
168 static void printOperationOpAttributes(OpAsmPrinter &p, OperationOp op,
169  OperandRange attrArgs,
170  ArrayAttr attrNames) {
171  if (attrNames.empty())
172  return;
173  p << " {";
174  interleaveComma(llvm::seq<int>(0, attrNames.size()), p,
175  [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });
176  p << '}';
177 }
178 
179 /// Verifies that the result types of this operation, defined within a
180 /// `pdl.rewrite`, can be inferred.
182  OperandRange resultTypes) {
183  // Functor that returns if the given use can be used to infer a type.
184  Block *rewriterBlock = op->getBlock();
185  auto canInferTypeFromUse = [&](OpOperand &use) {
186  // If the use is within a ReplaceOp and isn't the operation being replaced
187  // (i.e. is not the first operand of the replacement), we can infer a type.
188  ReplaceOp replOpUser = dyn_cast<ReplaceOp>(use.getOwner());
189  if (!replOpUser || use.getOperandNumber() == 0)
190  return false;
191  // Make sure the replaced operation was defined before this one.
192  Operation *replacedOp = replOpUser.getOpValue().getDefiningOp();
193  return replacedOp->getBlock() != rewriterBlock ||
194  replacedOp->isBeforeInBlock(op);
195  };
196 
197  // Check to see if the uses of the operation itself can be used to infer
198  // types.
199  if (llvm::any_of(op.getOp().getUses(), canInferTypeFromUse))
200  return success();
201 
202  // Handle the case where the operation has no explicit result types.
203  if (resultTypes.empty()) {
204  // If we don't know the concrete operation, don't attempt any verification.
205  // We can't make assumptions if we don't know the concrete operation.
206  Optional<StringRef> rawOpName = op.getOpName();
207  if (!rawOpName)
208  return success();
210  RegisteredOperationName::lookup(*rawOpName, op.getContext());
211  if (!opName)
212  return success();
213 
214  // If no explicit result types were provided, check to see if the operation
215  // expected at least one result. This doesn't cover all cases, but this
216  // should cover many cases in which the user intended to infer the results
217  // of an operation, but it isn't actually possible.
218  bool expectedAtLeastOneResult =
219  !opName->hasTrait<OpTrait::ZeroResults>() &&
220  !opName->hasTrait<OpTrait::VariadicResults>();
221  if (expectedAtLeastOneResult) {
222  return op
223  .emitOpError("must have inferable or constrained result types when "
224  "nested within `pdl.rewrite`")
225  .attachNote()
226  .append("operation is created in a non-inferrable context, but '",
227  *opName, "' does not implement InferTypeOpInterface");
228  }
229  return success();
230  }
231 
232  // Otherwise, make sure each of the types can be inferred.
233  for (const auto &it : llvm::enumerate(resultTypes)) {
234  Operation *resultTypeOp = it.value().getDefiningOp();
235  assert(resultTypeOp && "expected valid result type operation");
236 
237  // If the op was defined by a `apply_native_rewrite`, it is guaranteed to be
238  // usable.
239  if (isa<ApplyNativeRewriteOp>(resultTypeOp))
240  continue;
241 
242  // If the type operation was defined in the matcher and constrains an
243  // operand or the result of an input operation, it can be used.
244  auto constrainsInput = [rewriterBlock](Operation *user) {
245  return user->getBlock() != rewriterBlock &&
246  isa<OperandOp, OperandsOp, OperationOp>(user);
247  };
248  if (TypeOp typeOp = dyn_cast<TypeOp>(resultTypeOp)) {
249  if (typeOp.getConstantType() ||
250  llvm::any_of(typeOp->getUsers(), constrainsInput))
251  continue;
252  } else if (TypesOp typeOp = dyn_cast<TypesOp>(resultTypeOp)) {
253  if (typeOp.getConstantTypes() ||
254  llvm::any_of(typeOp->getUsers(), constrainsInput))
255  continue;
256  }
257 
258  return op
259  .emitOpError("must have inferable or constrained result types when "
260  "nested within `pdl.rewrite`")
261  .attachNote()
262  .append("result type #", it.index(), " was not constrained");
263  }
264  return success();
265 }
266 
268  bool isWithinRewrite = isa<RewriteOp>((*this)->getParentOp());
269  if (isWithinRewrite && !getOpName())
270  return emitOpError("must have an operation name when nested within "
271  "a `pdl.rewrite`");
272  ArrayAttr attributeNames = getAttributeValueNamesAttr();
273  auto attributeValues = getAttributeValues();
274  if (attributeNames.size() != attributeValues.size()) {
275  return emitOpError()
276  << "expected the same number of attribute values and attribute "
277  "names, got "
278  << attributeNames.size() << " names and " << attributeValues.size()
279  << " values";
280  }
281 
282  // If the operation is within a rewrite body and doesn't have type inference,
283  // ensure that the result types can be resolved.
284  if (isWithinRewrite && !mightHaveTypeInference()) {
285  if (failed(verifyResultTypesAreInferrable(*this, getTypeValues())))
286  return failure();
287  }
288 
289  return verifyHasBindingUse(*this);
290 }
291 
292 bool OperationOp::hasTypeInference() {
293  if (Optional<StringRef> rawOpName = getOpName()) {
294  OperationName opName(*rawOpName, getContext());
295  return opName.hasInterface<InferTypeOpInterface>();
296  }
297  return false;
298 }
299 
300 bool OperationOp::mightHaveTypeInference() {
301  if (Optional<StringRef> rawOpName = getOpName()) {
302  OperationName opName(*rawOpName, getContext());
303  return opName.mightHaveInterface<InferTypeOpInterface>();
304  }
305  return false;
306 }
307 
308 //===----------------------------------------------------------------------===//
309 // pdl::PatternOp
310 //===----------------------------------------------------------------------===//
311 
312 LogicalResult PatternOp::verifyRegions() {
313  Region &body = getBodyRegion();
314  Operation *term = body.front().getTerminator();
315  auto rewriteOp = dyn_cast<RewriteOp>(term);
316  if (!rewriteOp) {
317  return emitOpError("expected body to terminate with `pdl.rewrite`")
318  .attachNote(term->getLoc())
319  .append("see terminator defined here");
320  }
321 
322  // Check that all values defined in the top-level pattern belong to the PDL
323  // dialect.
324  WalkResult result = body.walk([&](Operation *op) -> WalkResult {
325  if (!isa_and_nonnull<PDLDialect>(op->getDialect())) {
326  emitOpError("expected only `pdl` operations within the pattern body")
327  .attachNote(op->getLoc())
328  .append("see non-`pdl` operation defined here");
329  return WalkResult::interrupt();
330  }
331  return WalkResult::advance();
332  });
333  if (result.wasInterrupted())
334  return failure();
335 
336  // Check that there is at least one operation.
337  if (body.front().getOps<OperationOp>().empty())
338  return emitOpError("the pattern must contain at least one `pdl.operation`");
339 
340  // Determine if the operations within the pdl.pattern form a connected
341  // component. This is determined by starting the search from the first
342  // operand/result/operation and visiting their users / parents / operands.
343  // We limit our attention to operations that have a user in pdl.rewrite,
344  // those that do not will be detected via other means (expected bindable
345  // user).
346  bool first = true;
347  DenseSet<Operation *> visited;
348  for (Operation &op : body.front()) {
349  // The following are the operations forming the connected component.
350  if (!isa<OperandOp, OperandsOp, ResultOp, ResultsOp, OperationOp>(op))
351  continue;
352 
353  // Determine if the operation has a user in `pdl.rewrite`.
354  bool hasUserInRewrite = false;
355  for (Operation *user : op.getUsers()) {
356  Region *region = user->getParentRegion();
357  if (isa<RewriteOp>(user) ||
358  (region && isa<RewriteOp>(region->getParentOp()))) {
359  hasUserInRewrite = true;
360  break;
361  }
362  }
363 
364  // If the operation does not have a user in `pdl.rewrite`, ignore it.
365  if (!hasUserInRewrite)
366  continue;
367 
368  if (first) {
369  // For the first operation, invoke visit.
370  visit(&op, visited);
371  first = false;
372  } else if (!visited.count(&op)) {
373  // For the subsequent operations, check if already visited.
374  return emitOpError("the operations must form a connected component")
375  .attachNote(op.getLoc())
376  .append("see a disconnected value / operation here");
377  }
378  }
379 
380  return success();
381 }
382 
383 void PatternOp::build(OpBuilder &builder, OperationState &state,
384  Optional<uint16_t> benefit, Optional<StringRef> name) {
385  build(builder, state, builder.getI16IntegerAttr(benefit ? *benefit : 0),
386  name ? builder.getStringAttr(*name) : StringAttr());
387  state.regions[0]->emplaceBlock();
388 }
389 
390 /// Returns the rewrite operation of this pattern.
391 RewriteOp PatternOp::getRewriter() {
392  return cast<RewriteOp>(getBodyRegion().front().getTerminator());
393 }
394 
395 /// The default dialect is `pdl`.
396 StringRef PatternOp::getDefaultDialect() {
397  return PDLDialect::getDialectNamespace();
398 }
399 
400 //===----------------------------------------------------------------------===//
401 // pdl::RangeOp
402 //===----------------------------------------------------------------------===//
403 
405  Type &resultType) {
406  // If arguments were provided, infer the result type from the argument list.
407  if (!argumentTypes.empty()) {
408  resultType = RangeType::get(getRangeElementTypeOrSelf(argumentTypes[0]));
409  return success();
410  }
411  // Otherwise, parse the type as a trailing type.
412  return p.parseColonType(resultType);
413 }
414 
415 static void printRangeType(OpAsmPrinter &p, RangeOp op, TypeRange argumentTypes,
416  Type resultType) {
417  if (argumentTypes.empty())
418  p << ": " << resultType;
419 }
420 
422  Type elementType = getType().getElementType();
423  for (Type operandType : getOperandTypes()) {
424  Type operandElementType = getRangeElementTypeOrSelf(operandType);
425  if (operandElementType != elementType) {
426  return emitOpError("expected operand to have element type ")
427  << elementType << ", but got " << operandElementType;
428  }
429  }
430  return success();
431 }
432 
433 //===----------------------------------------------------------------------===//
434 // pdl::ReplaceOp
435 //===----------------------------------------------------------------------===//
436 
438  if (getReplOperation() && !getReplValues().empty())
439  return emitOpError() << "expected no replacement values to be provided"
440  " when the replacement operation is present";
441  return success();
442 }
443 
444 //===----------------------------------------------------------------------===//
445 // pdl::ResultsOp
446 //===----------------------------------------------------------------------===//
447 
448 static ParseResult parseResultsValueType(OpAsmParser &p, IntegerAttr index,
449  Type &resultType) {
450  if (!index) {
451  resultType = RangeType::get(p.getBuilder().getType<ValueType>());
452  return success();
453  }
454  if (p.parseArrow() || p.parseType(resultType))
455  return failure();
456  return success();
457 }
458 
459 static void printResultsValueType(OpAsmPrinter &p, ResultsOp op,
460  IntegerAttr index, Type resultType) {
461  if (index)
462  p << " -> " << resultType;
463 }
464 
466  if (!getIndex() && getType().isa<pdl::ValueType>()) {
467  return emitOpError() << "expected `pdl.range<value>` result type when "
468  "no index is specified, but got: "
469  << getType();
470  }
471  return success();
472 }
473 
474 //===----------------------------------------------------------------------===//
475 // pdl::RewriteOp
476 //===----------------------------------------------------------------------===//
477 
478 LogicalResult RewriteOp::verifyRegions() {
479  Region &rewriteRegion = getBodyRegion();
480 
481  // Handle the case where the rewrite is external.
482  if (getName()) {
483  if (!rewriteRegion.empty()) {
484  return emitOpError()
485  << "expected rewrite region to be empty when rewrite is external";
486  }
487  return success();
488  }
489 
490  // Otherwise, check that the rewrite region only contains a single block.
491  if (rewriteRegion.empty()) {
492  return emitOpError() << "expected rewrite region to be non-empty if "
493  "external name is not specified";
494  }
495 
496  // Check that no additional arguments were provided.
497  if (!getExternalArgs().empty()) {
498  return emitOpError() << "expected no external arguments when the "
499  "rewrite is specified inline";
500  }
501 
502  return success();
503 }
504 
505 /// The default dialect is `pdl`.
506 StringRef RewriteOp::getDefaultDialect() {
507  return PDLDialect::getDialectNamespace();
508 }
509 
510 //===----------------------------------------------------------------------===//
511 // pdl::TypeOp
512 //===----------------------------------------------------------------------===//
513 
515  if (!getConstantTypeAttr())
516  return verifyHasBindingUse(*this);
517  return success();
518 }
519 
520 //===----------------------------------------------------------------------===//
521 // pdl::TypesOp
522 //===----------------------------------------------------------------------===//
523 
525  if (!getConstantTypesAttr())
526  return verifyHasBindingUse(*this);
527  return success();
528 }
529 
530 //===----------------------------------------------------------------------===//
531 // TableGen'd op method definitions
532 //===----------------------------------------------------------------------===//
533 
534 #define GET_OP_CLASSES
535 #include "mlir/Dialect/PDL/IR/PDLOps.cpp.inc"
static ParseResult parseResultsValueType(OpAsmParser &p, IntegerAttr index, Type &resultType)
Definition: PDL.cpp:448
static LogicalResult verifyHasBindingUse(Operation *op)
Returns success if the given operation is not in the main matcher body or is used by a "binding" oper...
Definition: PDL.cpp:49
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.
Definition: PDL.cpp:62
static LogicalResult verifyResultTypesAreInferrable(OperationOp op, OperandRange resultTypes)
Verifies that the result types of this operation, defined within a pdl.rewrite, can be inferred.
Definition: PDL.cpp:181
static void printRangeType(OpAsmPrinter &p, RangeOp op, TypeRange argumentTypes, Type resultType)
Definition: PDL.cpp:415
static ParseResult parseRangeType(OpAsmParser &p, TypeRange argumentTypes, Type &resultType)
Definition: PDL.cpp:404
static ParseResult parseOperationOpAttributes(OpAsmParser &p, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &attrOperands, ArrayAttr &attrNamesAttr)
Definition: PDL.cpp:144
static bool hasBindingUse(Operation *op)
Returns true if the given operation is used by a "binding" pdl operation.
Definition: PDL.cpp:39
static void printOperationOpAttributes(OpAsmPrinter &p, OperationOp op, OperandRange attrArgs, ArrayAttr attrNames)
Definition: PDL.cpp:168
static void printResultsValueType(OpAsmPrinter &p, ResultsOp op, IntegerAttr index, Type resultType)
Definition: PDL.cpp:459
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseRBrace()=0
Parse a } token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual ParseResult parseOptionalLBrace()=0
Parse a { token if present.
Block represents an ordered list of Operations.
Definition: Block.h:30
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:232
iterator_range< op_iterator< OpT > > getOps()
Return an iterator range over the operations within this block that are of 'OpT'.
Definition: Block.h:182
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:49
IntegerAttr getI16IntegerAttr(int16_t value)
Definition: Builders.cpp:204
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
Definition: Builders.h:88
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:243
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:247
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This class helps build Operations.
Definition: Builders.h:198
This class represents an operand of an operation.
Definition: Value.h:247
This class provides the API for ops which have an unknown number of results.
Definition: OpDefinition.h:689
This class provides return value APIs for ops that are known to have zero results.
Definition: OpDefinition.h:546
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:41
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition: Operation.h:151
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Definition: Operation.cpp:265
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:154
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:165
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:144
user_range getUsers()
Returns a range of all users.
Definition: Operation.h:650
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:512
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
Definition: Region.cpp:45
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
bool empty()
Definition: Region.h:60
Block & front()
Definition: Region.h:65
std::enable_if_t< std::is_same< RetT, void >::value, RetT > walk(FnT &&callback)
Walk the operations in this region.
Definition: Region.h:278
static Optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
static WalkResult advance()
Definition: Visitors.h:51
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:230
Type getRangeElementTypeOrSelf(Type type)
If the given type is a range, return its element type, otherwise return the type itself.
Definition: PDLTypes.cpp:62
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:372
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.