MLIR 24.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
13#include "llvm/ADT/TypeSwitch.h"
14#include <optional>
15
16using namespace mlir;
17using namespace mlir::pdl;
18
19#include "mlir/Dialect/PDL/IR/PDLOpsDialect.cpp.inc"
20
21//===----------------------------------------------------------------------===//
22// PDLDialect
23//===----------------------------------------------------------------------===//
24
25void PDLDialect::initialize() {
26 addOperations<
27#define GET_OP_LIST
28#include "mlir/Dialect/PDL/IR/PDLOps.cpp.inc"
29 >();
30 registerTypes();
31}
32
33//===----------------------------------------------------------------------===//
34// PDL Operations
35//===----------------------------------------------------------------------===//
36
37/// Returns true if the given operation is used by a "binding" pdl operation.
38static bool hasBindingUse(Operation *op) {
39 for (Operation *user : op->getUsers())
40 // A result by itself is not binding, it must also be bound.
41 if (!isa<ResultOp, ResultsOp>(user) || hasBindingUse(user))
42 return true;
43 return false;
44}
45
46/// Returns success if the given operation is not in the main matcher body or
47/// is used by a "binding" operation. On failure, emits an error.
48static LogicalResult verifyHasBindingUse(Operation *op) {
49 // If the parent is not a pattern, there is nothing to do.
50 if (!llvm::isa_and_nonnull<PatternOp>(op->getParentOp()))
51 return success();
52 if (hasBindingUse(op))
53 return success();
54 return op->emitOpError(
55 "expected a bindable user when defined in the matcher body of a "
56 "`pdl.pattern`");
57}
58
59/// Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s)
60/// connected to the given operation.
61static void visit(Operation *op, DenseSet<Operation *> &visited) {
62 // If the parent is not a pattern, there is nothing to do.
63 if (!isa<PatternOp>(op->getParentOp()) || isa<RewriteOp>(op))
64 return;
65
66 // Ignore if already visited. Otherwise, mark as visited.
67 if (!visited.insert(op).second)
68 return;
69
70 // Traverse the operands / parent.
72 .Case([&visited](OperationOp operation) {
73 for (Value operand : operation.getOperandValues())
74 visit(operand.getDefiningOp(), visited);
75 })
76 .Case<ResultOp, ResultsOp>([&visited](auto result) {
77 visit(result.getParent().getDefiningOp(), visited);
78 });
79
80 // Traverse the users.
81 for (Operation *user : op->getUsers())
82 visit(user, visited);
83}
84
85//===----------------------------------------------------------------------===//
86// pdl::ApplyNativeConstraintOp
87//===----------------------------------------------------------------------===//
88
89LogicalResult ApplyNativeConstraintOp::verify() {
90 if (getNumOperands() == 0)
91 return emitOpError("expected at least one argument");
92 if (llvm::any_of(getResults(), [](OpResult result) {
93 return isa<OperationType>(result.getType());
94 })) {
95 return emitOpError(
96 "returning an operation from a constraint is not supported");
97 }
98 return success();
99}
100
101//===----------------------------------------------------------------------===//
102// pdl::ApplyNativeRewriteOp
103//===----------------------------------------------------------------------===//
104
105LogicalResult ApplyNativeRewriteOp::verify() {
106 if (getNumOperands() == 0 && getNumResults() == 0)
107 return emitOpError("expected at least one argument or result");
108 return success();
109}
110
111//===----------------------------------------------------------------------===//
112// pdl::AttributeOp
113//===----------------------------------------------------------------------===//
114
115LogicalResult AttributeOp::verify() {
116 Value attrType = getValueType();
117 std::optional<Attribute> attrValue = getValue();
118
119 if (!attrValue) {
120 if (isa<RewriteOp>((*this)->getParentOp()))
121 return emitOpError(
122 "expected constant value when specified within a `pdl.rewrite`");
123 return verifyHasBindingUse(*this);
124 }
125 if (attrType)
126 return emitOpError("expected only one of [`type`, `value`] to be set");
127 return success();
128}
129
130//===----------------------------------------------------------------------===//
131// pdl::OperandOp
132//===----------------------------------------------------------------------===//
133
134LogicalResult OperandOp::verify() { return verifyHasBindingUse(*this); }
135
136//===----------------------------------------------------------------------===//
137// pdl::OperandsOp
138//===----------------------------------------------------------------------===//
139
140LogicalResult OperandsOp::verify() { return verifyHasBindingUse(*this); }
141
142//===----------------------------------------------------------------------===//
143// pdl::OperationOp
144//===----------------------------------------------------------------------===//
145
146static ParseResult parseOperationOpAttributes(
147 OpAsmParser &p,
149 ArrayAttr &attrNamesAttr) {
150 Builder &builder = p.getBuilder();
152 if (succeeded(p.parseOptionalLBrace())) {
153 auto parseOperands = [&]() {
154 StringAttr nameAttr;
156 if (p.parseAttribute(nameAttr) || p.parseEqual() ||
157 p.parseOperand(operand))
158 return failure();
159 attrNames.push_back(nameAttr);
160 attrOperands.push_back(operand);
161 return success();
162 };
163 if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())
164 return failure();
165 }
166 attrNamesAttr = builder.getArrayAttr(attrNames);
167 return success();
168}
169
170static void printOperationOpAttributes(OpAsmPrinter &p, OperationOp op,
171 OperandRange attrArgs,
172 ArrayAttr attrNames) {
173 if (attrNames.empty())
174 return;
175 p << " {";
176 interleaveComma(llvm::seq<int>(0, attrNames.size()), p,
177 [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });
178 p << '}';
179}
180
181/// Verifies that the result types of this operation, defined within a
182/// `pdl.rewrite`, can be inferred.
183static LogicalResult verifyResultTypesAreInferrable(OperationOp op,
184 OperandRange resultTypes) {
185 // Functor that returns if the given use can be used to infer a type.
186 Block *rewriterBlock = op->getBlock();
187 auto canInferTypeFromUse = [&](OpOperand &use) {
188 // If the use is within a ReplaceOp and isn't the operation being replaced
189 // (i.e. is not the first operand of the replacement), we can infer a type.
190 ReplaceOp replOpUser = dyn_cast<ReplaceOp>(use.getOwner());
191 if (!replOpUser || use.getOperandNumber() == 0)
192 return false;
193 // Make sure the replaced operation was defined before this one.
194 Operation *replacedOp = replOpUser.getOpValue().getDefiningOp();
195 return replacedOp->getBlock() != rewriterBlock ||
196 replacedOp->isBeforeInBlock(op);
197 };
198
199 // Check to see if the uses of the operation itself can be used to infer
200 // types.
201 if (llvm::any_of(op.getOp().getUses(), canInferTypeFromUse))
202 return success();
203
204 // Handle the case where the operation has no explicit result types.
205 if (resultTypes.empty()) {
206 // If we don't know the concrete operation, don't attempt any verification.
207 // We can't make assumptions if we don't know the concrete operation.
208 std::optional<StringRef> rawOpName = op.getOpName();
209 if (!rawOpName)
210 return success();
211 std::optional<RegisteredOperationName> opName =
212 RegisteredOperationName::lookup(*rawOpName, op.getContext());
213 if (!opName)
214 return success();
215
216 // If no explicit result types were provided, check to see if the operation
217 // expected at least one result. This doesn't cover all cases, but this
218 // should cover many cases in which the user intended to infer the results
219 // of an operation, but it isn't actually possible.
220 bool expectedAtLeastOneResult =
221 !opName->hasTrait<OpTrait::ZeroResults>() &&
222 !opName->hasTrait<OpTrait::VariadicResults>();
223 if (expectedAtLeastOneResult) {
224 return op
225 .emitOpError("must have inferable or constrained result types when "
226 "nested within `pdl.rewrite`")
227 .attachNote()
228 .append("operation is created in a non-inferrable context, but '",
229 *opName, "' does not implement InferTypeOpInterface");
230 }
231 return success();
232 }
233
234 // Otherwise, make sure each of the types can be inferred.
235 for (const auto &it : llvm::enumerate(resultTypes)) {
236 Operation *resultTypeOp = it.value().getDefiningOp();
237 assert(resultTypeOp && "expected valid result type operation");
238
239 // If the op was defined by a `apply_native_rewrite`, it is guaranteed to be
240 // usable.
241 if (isa<ApplyNativeRewriteOp>(resultTypeOp))
242 continue;
243
244 // If the type operation was defined in the matcher and constrains an
245 // operand or the result of an input operation, it can be used.
246 auto constrainsInput = [rewriterBlock](Operation *user) {
247 return user->getBlock() != rewriterBlock &&
248 isa<OperandOp, OperandsOp, OperationOp>(user);
249 };
250 if (TypeOp typeOp = dyn_cast<TypeOp>(resultTypeOp)) {
251 if (typeOp.getConstantType() ||
252 llvm::any_of(typeOp->getUsers(), constrainsInput))
253 continue;
254 } else if (TypesOp typeOp = dyn_cast<TypesOp>(resultTypeOp)) {
255 if (typeOp.getConstantTypes() ||
256 llvm::any_of(typeOp->getUsers(), constrainsInput))
257 continue;
258 }
259
260 return op
261 .emitOpError("must have inferable or constrained result types when "
262 "nested within `pdl.rewrite`")
263 .attachNote()
264 .append("result type #", it.index(), " was not constrained");
265 }
266 return success();
267}
268
269LogicalResult OperationOp::verify() {
270 bool isWithinRewrite = isa_and_nonnull<RewriteOp>((*this)->getParentOp());
271 if (isWithinRewrite && !getOpName())
272 return emitOpError("must have an operation name when nested within "
273 "a `pdl.rewrite`");
274 ArrayAttr attributeNames = getAttributeValueNamesAttr();
275 auto attributeValues = getAttributeValues();
276 if (attributeNames.size() != attributeValues.size()) {
277 return emitOpError()
278 << "expected the same number of attribute values and attribute "
279 "names, got "
280 << attributeNames.size() << " names and " << attributeValues.size()
281 << " values";
282 }
283
284 // If the operation is within a rewrite body and doesn't have type inference,
285 // ensure that the result types can be resolved.
286 if (isWithinRewrite && !mightHaveTypeInference()) {
287 if (failed(verifyResultTypesAreInferrable(*this, getTypeValues())))
288 return failure();
289 }
290
291 return verifyHasBindingUse(*this);
292}
293
294bool OperationOp::hasTypeInference() {
295 if (std::optional<StringRef> rawOpName = getOpName()) {
296 OperationName opName(*rawOpName, getContext());
297 return opName.hasInterface<InferTypeOpInterface>();
298 }
299 return false;
300}
301
302bool OperationOp::mightHaveTypeInference() {
303 if (std::optional<StringRef> rawOpName = getOpName()) {
304 OperationName opName(*rawOpName, getContext());
305 return opName.mightHaveInterface<InferTypeOpInterface>();
306 }
307 return false;
308}
309
310//===----------------------------------------------------------------------===//
311// pdl::PatternOp
312//===----------------------------------------------------------------------===//
313
314LogicalResult PatternOp::verifyRegions() {
315 Region &body = getBodyRegion();
316 Operation *term = body.front().getTerminator();
317 auto rewriteOp = dyn_cast<RewriteOp>(term);
318 if (!rewriteOp) {
319 return emitOpError("expected body to terminate with `pdl.rewrite`")
320 .attachNote(term->getLoc())
321 .append("see terminator defined here");
322 }
323
324 // Check that all values defined in the top-level pattern belong to the PDL
325 // dialect.
326 WalkResult result = body.walk([&](Operation *op) -> WalkResult {
327 if (!isa_and_nonnull<PDLDialect>(op->getDialect())) {
328 emitOpError("expected only `pdl` operations within the pattern body")
329 .attachNote(op->getLoc())
330 .append("see non-`pdl` operation defined here");
331 return WalkResult::interrupt();
332 }
333 return WalkResult::advance();
334 });
335 if (result.wasInterrupted())
336 return failure();
337
338 // Check that there is at least one operation.
339 if (body.front().getOps<OperationOp>().empty())
340 return emitOpError("the pattern must contain at least one `pdl.operation`");
341
342 // Determine if the operations within the pdl.pattern form a connected
343 // component. This is determined by starting the search from the first
344 // operand/result/operation and visiting their users / parents / operands.
345 // We limit our attention to operations that have a user in pdl.rewrite,
346 // those that do not will be detected via other means (expected bindable
347 // user).
348 bool first = true;
349 DenseSet<Operation *> visited;
350 for (Operation &op : body.front()) {
351 // The following are the operations forming the connected component.
352 if (!isa<OperandOp, OperandsOp, ResultOp, ResultsOp, OperationOp>(op))
353 continue;
354
355 // Determine if the operation has a user in `pdl.rewrite`.
356 bool hasUserInRewrite = false;
357 for (Operation *user : op.getUsers()) {
358 Region *region = user->getParentRegion();
359 if (isa<RewriteOp>(user) ||
360 (region && isa<RewriteOp>(region->getParentOp()))) {
361 hasUserInRewrite = true;
362 break;
363 }
364 }
365
366 // If the operation does not have a user in `pdl.rewrite`, ignore it.
367 if (!hasUserInRewrite)
368 continue;
369
370 if (first) {
371 // For the first operation, invoke visit.
372 visit(&op, visited);
373 first = false;
374 } else if (!visited.count(&op)) {
375 // For the subsequent operations, check if already visited.
376 return emitOpError("the operations must form a connected component")
377 .attachNote(op.getLoc())
378 .append("see a disconnected value / operation here");
379 }
380 }
381
382 return success();
383}
384
385void PatternOp::build(OpBuilder &builder, OperationState &state,
386 std::optional<uint16_t> benefit,
387 std::optional<StringRef> name) {
388 build(builder, state, builder.getI16IntegerAttr(benefit.value_or(0)),
389 name ? builder.getStringAttr(*name) : StringAttr(),
390 /*sym_visibility=*/nullptr);
391 state.regions[0]->emplaceBlock();
392}
393
394/// Returns the rewrite operation of this pattern.
395RewriteOp PatternOp::getRewriter() {
396 return cast<RewriteOp>(getBodyRegion().front().getTerminator());
397}
398
399/// The default dialect is `pdl`.
400StringRef PatternOp::getDefaultDialect() {
401 return PDLDialect::getDialectNamespace();
402}
403
404//===----------------------------------------------------------------------===//
405// pdl::RangeOp
406//===----------------------------------------------------------------------===//
407
408static 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
419static void printRangeType(OpAsmPrinter &p, RangeOp op, TypeRange argumentTypes,
420 Type resultType) {
421 if (argumentTypes.empty())
422 p << ": " << resultType;
423}
424
425LogicalResult 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
441LogicalResult 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
452static 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
463static void printResultsValueType(OpAsmPrinter &p, ResultsOp op,
464 IntegerAttr index, Type resultType) {
465 if (index)
466 p << " -> " << resultType;
467}
468
469LogicalResult 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
482LogicalResult 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`.
510StringRef RewriteOp::getDefaultDialect() {
511 return PDLDialect::getDialectNamespace();
512}
513
514//===----------------------------------------------------------------------===//
515// pdl::TypeOp
516//===----------------------------------------------------------------------===//
517
518LogicalResult TypeOp::verify() {
519 if (!getConstantTypeAttr())
520 return verifyHasBindingUse(*this);
521 return success();
522}
523
524//===----------------------------------------------------------------------===//
525// pdl::TypesOp
526//===----------------------------------------------------------------------===//
527
528LogicalResult 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"
return success()
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
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:48
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:61
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:183
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:146
static bool hasBindingUse(Operation *op)
Returns true if the given operation is used by a "binding" pdl operation.
Definition PDL.cpp:38
static void printOperationOpAttributes(OpAsmPrinter &p, OperationOp op, OperandRange attrArgs, ArrayAttr attrNames)
Definition PDL.cpp:170
static void printResultsValueType(OpAsmPrinter &p, ResultsOp op, IntegerAttr index, Type resultType)
Definition PDL.cpp:463
ArrayAttr()
b getContext())
static Type getValueType(Attribute attr)
Definition SPIRVOps.cpp:840
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
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 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:34
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
auto getOps()
Return an iterator range over the operations within this block that are of 'OpT'.
Definition Block.h:213
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
IntegerAttr getI16IntegerAttr(int16_t value)
Definition Builders.cpp:225
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
Definition Builders.h:94
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:271
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition Builders.cpp:275
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 represents an operand of an operation.
Definition Value.h:256
This is a value defined by a result of an operation.
Definition Value.h:456
This class provides the API for ops which have an unknown number of results.
This class provides return value APIs for ops that are known to have zero results.
This class implements the operand iterators for the Operation class.
Definition ValueRange.h:44
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition Operation.h:237
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Block * getBlock()
Returns the operation block that contains this operation.
Definition Operation.h:230
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
user_range getUsers()
Returns a range of all users.
Definition Operation.h:927
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Block & front()
Definition Region.h:65
bool empty()
Definition Region.h:60
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:198
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
Definition Region.h:297
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:40
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
static WalkResult advance()
Definition WalkResult.h:47
static WalkResult interrupt()
Definition WalkResult.h:46
Type getRangeElementTypeOrSelf(Type type)
If the given type is a range, return its element type, otherwise return the type itself.
Definition PDLTypes.cpp:59
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
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:311
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:125
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:147
This is the representation of an operand reference.
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.