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