MLIR 22.0.0git
Async.cpp
Go to the documentation of this file.
1//===- Async.cpp - MLIR Async Operations ----------------------------------===//
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
10
13#include "llvm/ADT/TypeSwitch.h"
14
15using namespace mlir;
16using namespace mlir::async;
17
18#include "mlir/Dialect/Async/IR/AsyncOpsDialect.cpp.inc"
19
20void AsyncDialect::initialize() {
21 addOperations<
22#define GET_OP_LIST
23#include "mlir/Dialect/Async/IR/AsyncOps.cpp.inc"
24 >();
25 addTypes<
26#define GET_TYPEDEF_LIST
27#include "mlir/Dialect/Async/IR/AsyncOpsTypes.cpp.inc"
28 >();
29}
30
31//===----------------------------------------------------------------------===//
32/// ExecuteOp
33//===----------------------------------------------------------------------===//
34
35constexpr char kOperandSegmentSizesAttr[] = "operandSegmentSizes";
36
37OperandRange ExecuteOp::getEntrySuccessorOperands(RegionSuccessor successor) {
38 assert(successor.getSuccessor() == &getBodyRegion() &&
39 "invalid region index");
40 return getBodyOperands();
41}
42
43bool ExecuteOp::areTypesCompatible(Type lhs, Type rhs) {
44 const auto getValueOrTokenType = [](Type type) {
45 if (auto value = llvm::dyn_cast<ValueType>(type))
46 return value.getValueType();
47 return type;
48 };
49 return getValueOrTokenType(lhs) == getValueOrTokenType(rhs);
50}
51
52void ExecuteOp::getSuccessorRegions(RegionBranchPoint point,
54 // The `body` region branch back to the parent operation.
55 if (!point.isParent() &&
57 &getBodyRegion()) {
58 regions.push_back(RegionSuccessor(getOperation(), getBodyResults()));
59 return;
60 }
61
62 // Otherwise the successor is the body region.
63 regions.push_back(
64 RegionSuccessor(&getBodyRegion(), getBodyRegion().getArguments()));
65}
66
67void ExecuteOp::build(OpBuilder &builder, OperationState &result,
68 TypeRange resultTypes, ValueRange dependencies,
69 ValueRange operands, BodyBuilderFn bodyBuilder) {
70 OpBuilder::InsertionGuard guard(builder);
71 result.addOperands(dependencies);
72 result.addOperands(operands);
73
74 // Add derived `operandSegmentSizes` attribute based on parsed operands.
75 int32_t numDependencies = dependencies.size();
76 int32_t numOperands = operands.size();
77 auto operandSegmentSizes =
78 builder.getDenseI32ArrayAttr({numDependencies, numOperands});
79 result.addAttribute(kOperandSegmentSizesAttr, operandSegmentSizes);
80
81 // First result is always a token, and then `resultTypes` wrapped into
82 // `async.value`.
83 result.addTypes({TokenType::get(result.getContext())});
84 for (Type type : resultTypes)
85 result.addTypes(ValueType::get(type));
86
87 // Add a body region with block arguments as unwrapped async value operands.
88 Region *bodyRegion = result.addRegion();
89 Block *bodyBlock = builder.createBlock(bodyRegion);
90 for (Value operand : operands) {
91 auto valueType = llvm::dyn_cast<ValueType>(operand.getType());
92 bodyBlock->addArgument(valueType ? valueType.getValueType()
93 : operand.getType(),
94 operand.getLoc());
95 }
96
97 // Create the default terminator if the builder is not provided and if the
98 // expected result is empty. Otherwise, leave this to the caller
99 // because we don't know which values to return from the execute op.
100 if (resultTypes.empty() && !bodyBuilder) {
101 async::YieldOp::create(builder, result.location, ValueRange());
102 } else if (bodyBuilder) {
103 bodyBuilder(builder, result.location, bodyBlock->getArguments());
104 }
105}
106
107void ExecuteOp::print(OpAsmPrinter &p) {
108 // [%tokens,...]
109 if (!getDependencies().empty())
110 p << " [" << getDependencies() << "]";
111
112 // (%value as %unwrapped: !async.value<!arg.type>, ...)
113 if (!getBodyOperands().empty()) {
114 p << " (";
115 Block *entry = getBodyRegion().empty() ? nullptr : &getBodyRegion().front();
116 llvm::interleaveComma(
117 getBodyOperands(), p, [&, n = 0](Value operand) mutable {
118 Value argument = entry ? entry->getArgument(n++) : Value();
119 p << operand << " as " << argument << ": " << operand.getType();
120 });
121 p << ")";
122 }
123
124 // -> (!async.value<!return.type>, ...)
125 p.printOptionalArrowTypeList(llvm::drop_begin(getResultTypes()));
126 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(),
127 {kOperandSegmentSizesAttr});
128 p << ' ';
129 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
130}
131
132ParseResult ExecuteOp::parse(OpAsmParser &parser, OperationState &result) {
133 MLIRContext *ctx = result.getContext();
134
135 // Sizes of parsed variadic operands, will be updated below after parsing.
136 int32_t numDependencies = 0;
137
138 auto tokenTy = TokenType::get(ctx);
139
140 // Parse dependency tokens.
141 if (succeeded(parser.parseOptionalLSquare())) {
143 if (parser.parseOperandList(tokenArgs) ||
144 parser.resolveOperands(tokenArgs, tokenTy, result.operands) ||
145 parser.parseRSquare())
146 return failure();
147
148 numDependencies = tokenArgs.size();
149 }
150
151 // Parse async value operands (%value as %unwrapped : !async.value<!type>).
154 SmallVector<Type, 4> valueTypes;
155
156 // Parse a single instance of `%value as %unwrapped : !async.value<!type>`.
157 auto parseAsyncValueArg = [&]() -> ParseResult {
158 if (parser.parseOperand(valueArgs.emplace_back()) ||
159 parser.parseKeyword("as") ||
160 parser.parseArgument(unwrappedArgs.emplace_back()) ||
161 parser.parseColonType(valueTypes.emplace_back()))
162 return failure();
163
164 auto valueTy = llvm::dyn_cast<ValueType>(valueTypes.back());
165 unwrappedArgs.back().type = valueTy ? valueTy.getValueType() : Type();
166 return success();
167 };
168
169 auto argsLoc = parser.getCurrentLocation();
171 parseAsyncValueArg) ||
172 parser.resolveOperands(valueArgs, valueTypes, argsLoc, result.operands))
173 return failure();
174
175 int32_t numOperands = valueArgs.size();
176
177 // Add derived `operandSegmentSizes` attribute based on parsed operands.
178 auto operandSegmentSizes =
179 parser.getBuilder().getDenseI32ArrayAttr({numDependencies, numOperands});
180 result.addAttribute(kOperandSegmentSizesAttr, operandSegmentSizes);
181
182 // Parse the types of results returned from the async execute op.
183 SmallVector<Type, 4> resultTypes;
184 NamedAttrList attrs;
185 if (parser.parseOptionalArrowTypeList(resultTypes) ||
186 // Async execute first result is always a completion token.
187 parser.addTypeToList(tokenTy, result.types) ||
188 parser.addTypesToList(resultTypes, result.types) ||
189 // Parse operation attributes.
191 return failure();
192
193 result.addAttributes(attrs);
194
195 // Parse asynchronous region.
196 Region *body = result.addRegion();
197 return parser.parseRegion(*body, /*arguments=*/unwrappedArgs);
198}
199
200LogicalResult ExecuteOp::verifyRegions() {
201 // Unwrap async.execute value operands types.
202 auto unwrappedTypes = llvm::map_range(getBodyOperands(), [](Value operand) {
203 return llvm::cast<ValueType>(operand.getType()).getValueType();
204 });
205
206 // Verify that unwrapped argument types matches the body region arguments.
207 if (getBodyRegion().getArgumentTypes() != unwrappedTypes)
208 return emitOpError("async body region argument types do not match the "
209 "execute operation arguments types");
210
211 return success();
212}
213
214//===----------------------------------------------------------------------===//
215/// CreateGroupOp
216//===----------------------------------------------------------------------===//
217
218LogicalResult CreateGroupOp::canonicalize(CreateGroupOp op,
219 PatternRewriter &rewriter) {
220 // Find all `await_all` users of the group.
221 llvm::SmallVector<AwaitAllOp> awaitAllUsers;
222
223 auto isAwaitAll = [&](Operation *op) -> bool {
224 if (AwaitAllOp awaitAll = dyn_cast<AwaitAllOp>(op)) {
225 awaitAllUsers.push_back(awaitAll);
226 return true;
227 }
228 return false;
229 };
230
231 // Check if all users of the group are `await_all` operations.
232 if (!llvm::all_of(op->getUsers(), isAwaitAll))
233 return failure();
234
235 // If group is only awaited without adding anything to it, we can safely erase
236 // the create operation and all users.
237 for (AwaitAllOp awaitAll : awaitAllUsers)
238 rewriter.eraseOp(awaitAll);
239 rewriter.eraseOp(op);
240
241 return success();
242}
243
244//===----------------------------------------------------------------------===//
245/// AwaitOp
246//===----------------------------------------------------------------------===//
247
248void AwaitOp::build(OpBuilder &builder, OperationState &result, Value operand,
250 result.addOperands({operand});
251 result.attributes.append(attrs.begin(), attrs.end());
252
253 // Add unwrapped async.value type to the returned values types.
254 if (auto valueType = llvm::dyn_cast<ValueType>(operand.getType()))
255 result.addTypes(valueType.getValueType());
256}
257
258static ParseResult parseAwaitResultType(OpAsmParser &parser, Type &operandType,
259 Type &resultType) {
260 if (parser.parseType(operandType))
261 return failure();
262
263 // Add unwrapped async.value type to the returned values types.
264 if (auto valueType = llvm::dyn_cast<ValueType>(operandType))
265 resultType = valueType.getValueType();
266
267 return success();
268}
269
271 Type operandType, Type resultType) {
272 p << operandType;
273}
274
275LogicalResult AwaitOp::verify() {
276 Type argType = getOperand().getType();
277
278 // Awaiting on a token does not have any results.
279 if (llvm::isa<TokenType>(argType) && !getResultTypes().empty())
280 return emitOpError("awaiting on a token must have empty result");
281
282 // Awaiting on a value unwraps the async value type.
283 if (auto value = llvm::dyn_cast<ValueType>(argType)) {
284 if (*getResultType() != value.getValueType())
285 return emitOpError() << "result type " << *getResultType()
286 << " does not match async value type "
287 << value.getValueType();
288 }
289
290 return success();
291}
292
293//===----------------------------------------------------------------------===//
294// FuncOp
295//===----------------------------------------------------------------------===//
296
297void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
298 FunctionType type, ArrayRef<NamedAttribute> attrs,
299 ArrayRef<DictionaryAttr> argAttrs) {
301 builder.getStringAttr(name));
302 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
303
304 state.attributes.append(attrs.begin(), attrs.end());
305 state.addRegion();
306
307 if (argAttrs.empty())
308 return;
309 assert(type.getNumInputs() == argAttrs.size());
311 builder, state, argAttrs, /*resultAttrs=*/{},
312 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
313}
314
315ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
316 auto buildFuncType =
317 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
319 std::string &) { return builder.getFunctionType(argTypes, results); };
320
322 parser, result, /*allowVariadic=*/false,
323 getFunctionTypeAttrName(result.name), buildFuncType,
324 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
325}
326
327void FuncOp::print(OpAsmPrinter &p) {
329 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
330 getArgAttrsAttrName(), getResAttrsAttrName());
331}
332
333/// Check that the result type of async.func is not void and must be
334/// some async token or async values.
335LogicalResult FuncOp::verify() {
336 auto resultTypes = getResultTypes();
337 if (resultTypes.empty())
338 return emitOpError()
339 << "result is expected to be at least of size 1, but got "
340 << resultTypes.size();
341
342 for (unsigned i = 0, e = resultTypes.size(); i != e; ++i) {
343 auto type = resultTypes[i];
344 if (!llvm::isa<TokenType>(type) && !llvm::isa<ValueType>(type))
345 return emitOpError() << "result type must be async value type or async "
346 "token type, but got "
347 << type;
348 // We only allow AsyncToken appear as the first return value
349 if (llvm::isa<TokenType>(type) && i != 0) {
350 return emitOpError()
351 << " results' (optional) async token type is expected "
352 "to appear as the 1st return value, but got "
353 << i + 1;
354 }
355 }
356
357 return success();
358}
359
360//===----------------------------------------------------------------------===//
361/// CallOp
362//===----------------------------------------------------------------------===//
363
364LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
365 // Check that the callee attribute was specified.
366 auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");
367 if (!fnAttr)
368 return emitOpError("requires a 'callee' symbol reference attribute");
369 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
370 if (!fn)
371 return emitOpError() << "'" << fnAttr.getValue()
372 << "' does not reference a valid async function";
373
374 // Verify that the operand and result types match the callee.
375 auto fnType = fn.getFunctionType();
376 if (fnType.getNumInputs() != getNumOperands())
377 return emitOpError("incorrect number of operands for callee");
378
379 for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)
380 if (getOperand(i).getType() != fnType.getInput(i))
381 return emitOpError("operand type mismatch: expected operand type ")
382 << fnType.getInput(i) << ", but provided "
383 << getOperand(i).getType() << " for operand number " << i;
384
385 if (fnType.getNumResults() != getNumResults())
386 return emitOpError("incorrect number of results for callee");
387
388 for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)
389 if (getResult(i).getType() != fnType.getResult(i)) {
390 auto diag = emitOpError("result type mismatch at index ") << i;
391 diag.attachNote() << " op result types: " << getResultTypes();
392 diag.attachNote() << "function result types: " << fnType.getResults();
393 return diag;
394 }
395
396 return success();
397}
398
399FunctionType CallOp::getCalleeType() {
400 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
401}
402
403//===----------------------------------------------------------------------===//
404/// ReturnOp
405//===----------------------------------------------------------------------===//
406
407LogicalResult ReturnOp::verify() {
408 auto funcOp = (*this)->getParentOfType<FuncOp>();
409 ArrayRef<Type> resultTypes = funcOp.isStateful()
410 ? funcOp.getResultTypes().drop_front()
411 : funcOp.getResultTypes();
412 // Get the underlying value types from async types returned from the
413 // parent `async.func` operation.
414 auto types = llvm::map_range(resultTypes, [](const Type &result) {
415 return llvm::cast<ValueType>(result).getValueType();
416 });
417
418 if (getOperandTypes() != types)
419 return emitOpError("operand types do not match the types returned from "
420 "the parent FuncOp");
421
422 return success();
423}
424
425//===----------------------------------------------------------------------===//
426// TableGen'd op method definitions
427//===----------------------------------------------------------------------===//
428
429#define GET_OP_CLASSES
430#include "mlir/Dialect/Async/IR/AsyncOps.cpp.inc"
431
432//===----------------------------------------------------------------------===//
433// TableGen'd type method definitions
434//===----------------------------------------------------------------------===//
435
436#define GET_TYPEDEF_CLASSES
437#include "mlir/Dialect/Async/IR/AsyncOpsTypes.cpp.inc"
438
439void ValueType::print(AsmPrinter &printer) const {
440 printer << "<";
441 printer.printType(getValueType());
442 printer << '>';
443}
444
445Type ValueType::parse(mlir::AsmParser &parser) {
446 Type ty;
447 if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) {
448 parser.emitError(parser.getNameLoc(), "failed to parse async value type");
449 return Type();
450 }
451 return ValueType::get(ty);
452}
return success()
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static ParseResult parseAwaitResultType(OpAsmParser &parser, Type &operandType, Type &resultType)
Definition Async.cpp:258
constexpr char kOperandSegmentSizesAttr[]
ExecuteOp.
Definition Async.cpp:35
static void printAwaitResultType(OpAsmPrinter &p, Operation *op, Type operandType, Type resultType)
Definition Async.cpp:270
lhs
b getContext())
static std::string diag(const llvm::Value &value)
static Type getValueType(Attribute attr)
Definition SPIRVOps.cpp:775
This base class exposes generic asm parser hooks, usable across the various derived parsers.
@ OptionalParen
Parens supporting zero or more operands, or nothing.
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 InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult addTypeToList(Type type, SmallVectorImpl< Type > &result)
Add the specified type to the end of the specified type list and return success.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ParseResult addTypesToList(ArrayRef< Type > types, SmallVectorImpl< Type > &result)
Add the specified types to the end of the specified type list and return success.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseOptionalArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional arrow followed by a type list.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printType(Type type)
void printOptionalArrowTypeList(TypeRange &&types)
Print an optional arrow followed by a type list.
Block represents an ordered list of Operations.
Definition Block.h:33
bool empty()
Definition Block.h:148
BlockArgument getArgument(unsigned i)
Definition Block.h:129
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition Block.cpp:153
BlockArgListType getArguments()
Definition Block.h:87
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
Definition Builders.cpp:163
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition Builders.cpp:76
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:262
A symbol reference with a reference path containing a single element.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult parseArgument(Argument &result, bool allowType=false, bool allowAttrs=false)=0
Parse a single argument with the following syntax:
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
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.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with 'attribute...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
RAII guard to reset the insertion point of the builder when destroyed.
Definition Builders.h:348
This class helps build Operations.
Definition Builders.h:207
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition Builders.cpp:430
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
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition Operation.h:230
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
Operation * getTerminatorPredecessorOrNull() const
Returns the terminator if branching from a region.
This class represents a successor of a region.
Region * getSuccessor() const
Return the given region successor.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
This class represents a collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition SymbolTable.h:76
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 provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
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 named class for passing around the variadic flag.
void addArgAndResultAttrs(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs, StringAttr argAttrsName, StringAttr resAttrsName)
Adds argument and result attributes, provided as argAttrs and resultAttrs arguments,...
void printFunctionOp(OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic, StringRef typeAttrName, StringAttr argAttrsName, StringAttr resAttrsName)
Printer implementation for function-like operations.
ParseResult parseFunctionOp(OpAsmParser &parser, OperationState &result, bool allowVariadic, StringAttr typeAttrName, FuncTypeBuilder funcTypeBuilder, StringAttr argAttrsName, StringAttr resAttrsName)
Parser implementation for function-like operations.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:304
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
Region * addRegion()
Create a region that should be attached to the operation.