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