MLIR  22.0.0git
FuncBufferizableOpInterfaceImpl.cpp
Go to the documentation of this file.
1 //===- BufferizableOpInterfaceImpl.cpp - Impl. of BufferizableOpInterface -===//
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 
16 #include "mlir/IR/Dialect.h"
17 #include "mlir/IR/Operation.h"
18 #include <optional>
19 
20 namespace mlir {
21 /// Return all func.return ops in the given function.
24  for (Block &b : funcOp.getBody())
25  if (auto returnOp = dyn_cast<func::ReturnOp>(b.getTerminator()))
26  result.push_back(returnOp);
27  return result;
28 }
29 
30 namespace bufferization {
31 namespace func_ext {
32 
35  auto createdEquiv = equivalentFuncArgs.try_emplace(funcOp, IndexMapping());
36  auto createdAliasingResults =
37  aliasingReturnVals.try_emplace(funcOp, IndexToIndexListMapping());
38  auto createdRead = readBbArgs.try_emplace(funcOp, BbArgIndexSet());
39  auto createdWritten = writtenBbArgs.try_emplace(funcOp, BbArgIndexSet());
40  (void)createdEquiv;
41  (void)createdAliasingResults;
42  (void)createdRead;
43  (void)createdWritten;
44 #ifndef NDEBUG
45  assert(createdEquiv.second && "equivalence info exists already");
46  assert(createdAliasingResults.second && "aliasing info exists already");
47  assert(createdRead.second && "bbarg access info exists already");
48  assert(createdWritten.second && "bbarg access info exists already");
49 #endif // NDEBUG
50 }
51 
52 /// Return the index-th bufferized function argument type. This assumes that the
53 /// specified argument is a tensor. If the tensor is ranked, a layout map may be
54 /// specified by the user (as per `options.functionArgTypeConverterFn`).
55 static BaseMemRefType
56 getBufferizedFunctionArgType(FuncOp funcOp, int64_t index,
58  auto tensorType =
59  dyn_cast<TensorType>(funcOp.getFunctionType().getInput(index));
60  assert(tensorType && "expected TensorType");
61 
62  BaseMemRefType memrefType = options.functionArgTypeConverterFn(
63  tensorType, *options.defaultMemorySpaceFn(tensorType), funcOp, options);
64 
65  auto layoutAttr = funcOp.getArgAttrOfType<MemRefLayoutAttrInterface>(
66  index, BufferizationDialect::kBufferLayoutAttrName);
67  if (!layoutAttr)
68  return memrefType;
69 
70  auto rankedMemrefType = dyn_cast<MemRefType>(memrefType);
71  assert(rankedMemrefType && "buffer layout not supported on unranked tensors");
72  return MemRefType::get(rankedMemrefType.getShape(),
73  rankedMemrefType.getElementType(), layoutAttr,
74  rankedMemrefType.getMemorySpace());
75 }
76 
77 /// Return the FuncOp called by `callOp`.
78 static FuncOp getCalledFunction(CallOpInterface callOp,
79  SymbolTableCollection &symbolTables) {
80  SymbolRefAttr sym =
81  llvm::dyn_cast_if_present<SymbolRefAttr>(callOp.getCallableForCallee());
82  if (!sym)
83  return nullptr;
84  return dyn_cast_or_null<FuncOp>(
85  symbolTables.lookupNearestSymbolFrom(callOp, sym));
86 }
87 
88 /// Return the FuncOp called by `callOp`.
89 static FuncOp getCalledFunction(CallOpInterface callOp,
90  const AnalysisState &state) {
91  auto &oneShotAnalysisState = static_cast<const OneShotAnalysisState &>(state);
92 
93  if (auto *funcAnalysisState =
94  oneShotAnalysisState.getExtension<FuncAnalysisState>()) {
95  // Use the cached symbol tables.
96  return getCalledFunction(callOp, funcAnalysisState->symbolTables);
97  }
98 
99  SymbolTableCollection symbolTables;
100  return getCalledFunction(callOp, symbolTables);
101 }
102 
103 /// Get FuncAnalysisState.
104 static const FuncAnalysisState &
106  assert(isa<OneShotAnalysisState>(state) && "expected OneShotAnalysisState");
107  auto *result = static_cast<const OneShotAnalysisState &>(state)
108  .getExtension<FuncAnalysisState>();
109  assert(result && "FuncAnalysisState does not exist");
110  return *result;
111 }
112 
113 /// Return the state (phase) of analysis of the FuncOp.
115  FuncOp funcOp) {
116  if (!isa<OneShotAnalysisState>(state))
118  auto *funcState = static_cast<const OneShotAnalysisState &>(state)
119  .getExtension<FuncAnalysisState>();
120  if (!funcState)
122  const auto &analyzedFuncOps = funcState->analyzedFuncOps;
123  auto it = analyzedFuncOps.find(funcOp);
124  if (it == analyzedFuncOps.end())
126  return it->second;
127 }
128 
129 /// Return the index of the bbArg in the given FuncOp that is equivalent to the
130 /// specified return value (if any).
131 static std::optional<int64_t>
132 getEquivalentFuncArgIdx(FuncOp funcOp, const FuncAnalysisState &state,
133  int64_t returnValIdx) {
134  auto funcOpIt = state.equivalentFuncArgs.find(funcOp);
135  if (funcOpIt == state.equivalentFuncArgs.end())
136  // No equivalence info stores for funcOp.
137  return std::nullopt;
138 
139  auto retValIt = funcOpIt->getSecond().find(returnValIdx);
140  if (retValIt == funcOpIt->getSecond().end())
141  // Return value has no equivalent bbArg.
142  return std::nullopt;
143 
144  return retValIt->getSecond();
145 }
146 
148  : public BufferizableOpInterface::ExternalModel<CallOpInterface,
149  func::CallOp> {
151  const AnalysisState &state) const {
152  func::CallOp callOp = cast<func::CallOp>(op);
153  FuncOp funcOp = getCalledFunction(callOp, state);
154  assert(funcOp && "expected CallOp to a FuncOp");
155 
157  // FuncOp not analyzed yet. Assume that OpOperand is read.
158  return true;
159 
160  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
161  return funcState.readBbArgs.lookup(funcOp).contains(
162  opOperand.getOperandNumber());
163  }
164 
166  const AnalysisState &state) const {
167  func::CallOp callOp = cast<func::CallOp>(op);
168  FuncOp funcOp = getCalledFunction(callOp, state);
169  assert(funcOp && "expected CallOp to a FuncOp");
170 
172  // FuncOp not analyzed yet. Assume that OpOperand is written.
173  return true;
174 
175  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
176  return funcState.writtenBbArgs.lookup(funcOp).contains(
177  opOperand.getOperandNumber());
178  }
179 
181  const AnalysisState &state) const {
182  func::CallOp callOp = cast<func::CallOp>(op);
183  FuncOp funcOp = getCalledFunction(callOp, state);
184  assert(funcOp && "expected CallOp to a FuncOp");
186  // FuncOp not analyzed yet. Any OpResult may be aliasing.
187  return detail::unknownGetAliasingValues(opOperand);
188 
189  // Get aliasing results from state.
190  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
191  auto aliasingReturnVals =
192  funcState.aliasingReturnVals.lookup(funcOp).lookup(
193  opOperand.getOperandNumber());
194 
195  // Check if the aliasing OpResult is equivalent to the OpOperand.
196  std::optional<int64_t> equivalent = {};
197  if (aliasingReturnVals.size() == 1) {
198  equivalent = getEquivalentFuncArgIdx(funcOp, funcState,
199  aliasingReturnVals.front());
200  assert((!equivalent.has_value() ||
201  *equivalent == opOperand.getOperandNumber()) &&
202  "inconsistent analysis state");
203  }
204  AliasingValueList result;
205  for (int64_t resultIdx : aliasingReturnVals)
206  result.addAlias({callOp->getOpResult(resultIdx),
207  equivalent.has_value() ? BufferRelation::Equivalent
209  /*isDefinite=*/equivalent.has_value()});
210  return result;
211  }
212 
213  FailureOr<BufferLikeType>
215  const BufferizationState &state,
216  SmallVector<Value> &invocationStack) const {
217  auto callOp = cast<func::CallOp>(op);
218 
219  // TODO Avoid recomputing the symbol tables every time.
220  SymbolTableCollection symbolTable;
221 
222  FuncOp funcOp = getCalledFunction(callOp, symbolTable);
223  assert(funcOp && "expected CallOp to a FuncOp");
224 
225  // If the callee was already bufferized, we can directly take the type from
226  // its signature.
227  FunctionType funcType = funcOp.getFunctionType();
228  Type resultType =
229  funcType.getResult(cast<OpResult>(value).getResultNumber());
230  if (auto bufferizedType = dyn_cast<BaseMemRefType>(resultType))
231  return cast<BufferLikeType>(bufferizedType);
232 
233  // Otherwise, call the type converter to compute the bufferized type.
234  auto tensorType = cast<TensorType>(resultType);
235  return cast<BufferLikeType>(options.functionArgTypeConverterFn(
236  tensorType, *options.defaultMemorySpaceFn(tensorType), funcOp,
237  options));
238  }
239 
240  /// All function arguments are writable. It is the responsibility of the
241  /// CallOp to insert buffer copies where necessary.
242  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
244  BufferizationState &state) const {
245  func::CallOp callOp = cast<func::CallOp>(op);
246 
247  // 1. Compute the result types of the new CallOp.
248  SmallVector<Type> resultTypes;
249  for (Value result : callOp.getResults()) {
250  Type returnType = result.getType();
251  if (!isa<TensorType>(returnType)) {
252  // Non-tensor values are returned.
253  resultTypes.push_back(returnType);
254  continue;
255  }
256 
257  // Returning a memref.
258  FailureOr<BufferLikeType> resultType =
259  bufferization::getBufferType(result, options, state);
260  if (failed(resultType))
261  return failure();
262  resultTypes.push_back(*resultType);
263  }
264 
265  // 2. Rewrite tensor operands as memrefs based on type of the already
266  // bufferized callee.
267  SmallVector<Value> newOperands;
268 
269  FuncOp funcOp = getCalledFunction(callOp, state.getSymbolTables());
270  assert(funcOp && "expected CallOp to a FuncOp");
271  FunctionType funcType = funcOp.getFunctionType();
272 
273  for (OpOperand &opOperand : callOp->getOpOperands()) {
274  // Non-tensor operands are just copied.
275  if (!isa<TensorType>(opOperand.get().getType())) {
276  newOperands.push_back(opOperand.get());
277  continue;
278  }
279 
280  // Retrieve buffers for tensor operands.
281  FailureOr<Value> maybeBuffer =
282  getBuffer(rewriter, opOperand.get(), options, state);
283  if (failed(maybeBuffer))
284  return failure();
285  Value buffer = *maybeBuffer;
286 
287  // Caller / callee type mismatch is handled with castOrReallocMemRefValue.
288  auto memRefType = funcType.getInput(opOperand.getOperandNumber());
289  if (!isa<BaseMemRefType>(memRefType)) {
290  // The called function was not bufferized yet. This can happen when
291  // there cycles in the function call graph. Compute the bufferized
292  // result type.
293  FailureOr<BufferLikeType> maybeBufferType =
295  funcOp.getArgument(opOperand.getOperandNumber()), options,
296  state);
297  if (failed(maybeBufferType))
298  return failure();
299  memRefType = *maybeBufferType;
300  }
301 
302  // Since we don't yet have a clear layout story, to_buffer may
303  // conservatively turn tensors into more dynamic memref than necessary.
304  // If the memref type of the callee fails, introduce an extra memref.cast
305  // that will either canonicalize away or fail compilation until we can do
306  // something better. Insert a reallocation + copy if it cannot be
307  // statically guaranteed that a direct cast would be valid.
308  if (buffer.getType() != memRefType) {
309  auto memrefDstType = dyn_cast<MemRefType>(memRefType);
310  assert(memrefDstType &&
311  "buffer layout not supported on unranked tensors");
312  FailureOr<Value> replacement = bufferization::castOrReallocMemRefValue(
313  rewriter, buffer, memrefDstType, options);
314  if (failed(replacement))
315  return failure();
316  buffer = *replacement;
317  }
318  newOperands.push_back(buffer);
319  }
320 
321  // 3. Create the new CallOp.
322  Operation *newCallOp =
323  func::CallOp::create(rewriter, callOp.getLoc(), funcOp.getSymName(),
324  resultTypes, newOperands);
325  newCallOp->setAttrs(callOp->getAttrs());
326 
327  // 4. Replace the old op with the new op.
328  replaceOpWithBufferizedValues(rewriter, callOp, newCallOp->getResults());
329 
330  return success();
331  }
332 };
333 
335  : public BufferizableOpInterface::ExternalModel<ReturnOpInterface,
336  func::ReturnOp> {
338  const AnalysisState &state) const {
339  return true;
340  }
341 
343  const AnalysisState &state) const {
344  return false;
345  }
346 
348  const AnalysisState &state) const {
349  return {};
350  }
351 
352  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
354  BufferizationState &state) const {
355 #ifndef NDEBUG
356  auto returnOp = cast<func::ReturnOp>(op);
357  assert(isa<FuncOp>(returnOp->getParentOp()) &&
358  "only support FuncOp parent for ReturnOp");
359 #endif // NDEBUG
360 
361  // ReturnOps are bufferized as part of FuncOps.
362  return success();
363  }
364 };
365 
368  FuncOpInterface, FuncOp> {
369 
370  static bool supportsUnstructuredControlFlow() { return true; }
371 
372  bool hasTensorSemantics(Operation *op) const {
373  auto isaTensor = llvm::IsaPred<TensorType>;
374 
375  // A function has tensor semantics if it has tensor arguments/results.
376  auto funcOp = cast<FuncOp>(op);
377  bool hasTensorArg = any_of(funcOp.getArgumentTypes(), isaTensor);
378  bool hasTensorResult = any_of(funcOp.getResultTypes(), isaTensor);
379  if (hasTensorArg || hasTensorResult)
380  return true;
381 
382  // It also has tensor semantics if it has tensor block arguments.
383  // TODO: Decouple bufferization of unstructured control flow from
384  // BufferizableOpInterface implementations. We should only care about
385  // region entry block arguments here (which are already covered by the
386  // argument types of the function).
387  for (Block &block : funcOp.getBody())
388  if (any_of(block.getArgumentTypes(), isaTensor))
389  return true;
390 
391  return false;
392  }
393 
396  const AnalysisState &state) const {
397  return getAliasingBranchOpOperands(op, cast<BlockArgument>(value), state);
398  }
399 
400  FailureOr<BufferLikeType>
402  const BufferizationState &state,
403  SmallVector<Value> &invocationStack) const {
404  auto funcOp = cast<FuncOp>(op);
405  auto bbArg = cast<BlockArgument>(value);
406 
407  // Function arguments are special.
408  if (bbArg.getOwner() == &funcOp.getBody().front())
409  return cast<BufferLikeType>(
410  getBufferizedFunctionArgType(funcOp, bbArg.getArgNumber(), options));
411 
413  getBufferType(op, value, options, state, invocationStack);
414  }
415 
416  /// Rewrite function bbArgs and return values into buffer form. This function
417  /// bufferizes the function signature and the ReturnOp. When the entire
418  /// function body has been bufferized, function return types can be switched
419  /// to more concise memref types as part of `foldMemRefCasts`.
420  ///
421  /// All function bbArgs are writable unless they are explicitly marked as
422  /// read-only. Callers must insert copies when needed.
423  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
425  BufferizationState &state) const {
426  auto funcOp = cast<FuncOp>(op);
427  FunctionType funcType = funcOp.getFunctionType();
428 
429  // Compute the argument types.
430  SmallVector<Type> argTypes;
431  for (const auto &it : llvm::enumerate(funcType.getInputs())) {
432  Type argType = it.value();
433  if (isa<TensorType>(argType)) {
434  argTypes.push_back(
435  getBufferizedFunctionArgType(funcOp, it.index(), options));
436  continue;
437  }
438  argTypes.push_back(argType);
439  }
440 
441  // Compute the result types.
442  SmallVector<Type> retTypes;
443  for (Type resultType : funcType.getResults()) {
444  if (auto tensorType = dyn_cast<TensorType>(resultType)) {
445  BaseMemRefType resultType = options.functionArgTypeConverterFn(
446  tensorType, *options.defaultMemorySpaceFn(tensorType), funcOp,
447  options);
448  retTypes.push_back(resultType);
449  continue;
450  }
451  retTypes.push_back(resultType);
452  }
453 
454  // Compute the new function type.
455  auto newFuncType = FunctionType::get(op->getContext(), argTypes, retTypes);
456 
457  // If the function has no body, set the new function type and we are done.
458  if (funcOp.isExternal()) {
459  funcOp.setType(newFuncType);
460  return success();
461  }
462 
463  // 1. Bufferize every block.
464  for (Block &block : funcOp.getBody())
465  if (failed(bufferization::bufferizeBlockSignature(&block, rewriter,
466  options, state)))
467  return failure();
468 
469  // 2. Bufferize the operands of the all return op.
470  for (func::ReturnOp returnOp : getReturnOps(funcOp)) {
471  assert(returnOp->getNumOperands() == retTypes.size() &&
472  "incorrect number of return values");
473  SmallVector<Value> returnValues;
474  for (auto [returnVal, bufferizedType] :
475  llvm::zip_equal(returnOp->getOperands(), retTypes)) {
476  auto tensorType = dyn_cast<TensorType>(returnVal.getType());
477  rewriter.setInsertionPoint(returnOp);
478 
479  // If not a tensor type just forward it.
480  if (!tensorType) {
481  returnValues.push_back(returnVal);
482  continue;
483  }
484 
485  // Note: If `inferFunctionResultLayout = true`, casts are later folded
486  // away.
487  Value toBufferOp = bufferization::ToBufferOp::create(
488  rewriter, returnOp.getLoc(), bufferizedType, returnVal);
489  returnValues.push_back(toBufferOp);
490  }
491 
492  returnOp.getOperandsMutable().assign(returnValues);
493  }
494 
495  // 3. Set the new function type.
496  funcOp.setType(newFuncType);
497  return success();
498  }
499 
500  /// Return `true` if the given function argument is writable.
501  bool isWritable(Operation *op, Value value,
502  const AnalysisState &state) const {
503  auto funcOp = cast<FuncOp>(op);
504  BlockArgument bbArg = dyn_cast<BlockArgument>(value);
505  assert(bbArg && "expected BlockArgument");
506 
507  // Non-entry block arguments are always writable. (They may alias with
508  // values that are not writable, which will turn them into read-only.)
509  if (bbArg.getOwner() != &funcOp.getBody().front())
510  return true;
511 
512  // "bufferization.writable" overrides other writability decisions. This is
513  // currently used for testing only.
514  if (BoolAttr writable = funcOp.getArgAttrOfType<BoolAttr>(
515  bbArg.getArgNumber(), BufferizationDialect::kWritableAttrName))
516  return writable.getValue();
517 
518  // All function arguments are writable by default.
519  return true;
520  }
521 };
522 
523 } // namespace func_ext
524 } // namespace bufferization
525 } // namespace mlir
526 
529  registry.addExtension(+[](MLIRContext *ctx, func::FuncDialect *dialect) {
530  func::CallOp::attachInterface<func_ext::CallOpInterface>(*ctx);
531  func::FuncOp::attachInterface<func_ext::FuncOpInterface>(*ctx);
532  func::ReturnOp::attachInterface<func_ext::ReturnOpInterface>(*ctx);
533  });
534 }
static bool isaTensor(Type t)
static llvm::ManagedStatic< PassManagerOptions > options
This class provides a shared interface for ranked and unranked memref types.
Definition: BuiltinTypes.h:104
This class represents an argument of a Block.
Definition: Value.h:309
Block * getOwner() const
Returns the block that owns this argument.
Definition: Value.h:318
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:321
Block represents an ordered list of Operations.
Definition: Block.h:33
Operation & front()
Definition: Block.h:153
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition: Builders.h:396
This class represents an operand of an operation.
Definition: Value.h:257
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Definition: Value.cpp:226
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
void setAttrs(DictionaryAttr newAttrs)
Set the attributes from a dictionary on this operation.
Definition: Operation.cpp:304
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
result_range getResults()
Definition: Operation.h:415
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:358
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,...
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
AnalysisState provides a variety of helper functions for dealing with tensor values.
BufferizationState provides information about the state of the IR during the bufferization process.
State for analysis-enabled bufferization.
AliasingValueList unknownGetAliasingValues(OpOperand &opOperand)
This is the default implementation of getAliasingValues in case the owner op does not implement the B...
static std::optional< int64_t > getEquivalentFuncArgIdx(FuncOp funcOp, const FuncAnalysisState &state, int64_t returnValIdx)
Return the index of the bbArg in the given FuncOp that is equivalent to the specified return value (i...
FuncOpAnalysisState
The state of analysis of a FuncOp.
void registerBufferizableOpInterfaceExternalModels(DialectRegistry &registry)
static FuncOp getCalledFunction(CallOpInterface callOp, SymbolTableCollection &symbolTables)
Return the FuncOp called by callOp.
static FuncOpAnalysisState getFuncOpAnalysisState(const AnalysisState &state, FuncOp funcOp)
Return the state (phase) of analysis of the FuncOp.
static const FuncAnalysisState & getFuncAnalysisState(const AnalysisState &state)
Get FuncAnalysisState.
static BaseMemRefType getBufferizedFunctionArgType(FuncOp funcOp, int64_t index, const BufferizationOptions &options)
Return the index-th bufferized function argument type.
void replaceOpWithBufferizedValues(RewriterBase &rewriter, Operation *op, ValueRange values)
Replace an op with replacement values.
FailureOr< Value > castOrReallocMemRefValue(OpBuilder &b, Value value, MemRefType type, const BufferizationOptions &options)
Try to cast the given ranked MemRef-typed value to the given ranked MemRef type.
SmallVector< func::ReturnOp > getReturnOps(func::FuncOp funcOp)
Helper function that returns all func.return ops in the given function.
LogicalResult bufferizeBlockSignature(Block *block, RewriterBase &rewriter, const BufferizationOptions &options, BufferizationState &state)
Bufferize the signature of block and its callers (i.e., ops that have the given block as a successor)...
Definition: Bufferize.cpp:393
FailureOr< Value > getBuffer(RewriterBase &rewriter, Value value, const BufferizationOptions &options, const BufferizationState &state)
Lookup the buffer for the given value.
FailureOr< BufferLikeType > getBufferType(Value value, const BufferizationOptions &options, const BufferizationState &state)
Return the buffer type for a given Value (tensor) after bufferization without bufferizing any IR.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Options for BufferizableOpInterface-based bufferization.
A template that provides a default implementation of getAliasingOpOperands for ops that support unstr...
AliasingOpOperandList getAliasingBranchOpOperands(Operation *op, BlockArgument bbArg, const AnalysisState &state) const
Assuming that bbArg is a block argument of a block that belongs to the given op, return all OpOperand...
FailureOr< BufferLikeType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, const BufferizationState &state, SmallVector< Value > &invocationStack) const
FailureOr< BufferLikeType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, const BufferizationState &state, SmallVector< Value > &invocationStack) const
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options, BufferizationState &state) const
All function arguments are writable.
bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
Extra analysis state that is required for bufferization of function boundaries.
DenseMap< FuncOp, IndexMapping > equivalentFuncArgs
A mapping of ReturnOp OpOperand indices to equivalent FuncOp BBArg indices.
DenseMap< FuncOp, IndexToIndexListMapping > aliasingReturnVals
A mapping of FuncOp BBArg indices to aliasing ReturnOp OpOperand indices.
DenseMap< int64_t, SmallVector< int64_t > > IndexToIndexListMapping
A mapping of indices to a list of indices.
DenseMap< FuncOp, BbArgIndexSet > readBbArgs
A set of all read BlockArguments of FuncOps.
DenseSet< int64_t > BbArgIndexSet
A set of block argument indices.
DenseMap< FuncOp, BbArgIndexSet > writtenBbArgs
A set of all written-to BlockArguments of FuncOps.
DenseMap< FuncOp, FuncOpAnalysisState > analyzedFuncOps
Keep track of which FuncOps are fully analyzed or currently being analyzed.
void startFunctionAnalysis(FuncOp funcOp)
This function is called right before analyzing the given FuncOp.
DenseMap< int64_t, int64_t > IndexMapping
A mapping of indices to indices.
AliasingOpOperandList getAliasingOpOperands(Operation *op, Value value, const AnalysisState &state) const
bool isWritable(Operation *op, Value value, const AnalysisState &state) const
Return true if the given function argument is writable.
FailureOr< BufferLikeType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, const BufferizationState &state, SmallVector< Value > &invocationStack) const
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options, BufferizationState &state) const
Rewrite function bbArgs and return values into buffer form.
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options, BufferizationState &state) const