MLIR  20.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 
17 #include "mlir/IR/Dialect.h"
18 #include "mlir/IR/Operation.h"
19 #include <optional>
20 
21 namespace mlir {
22 namespace bufferization {
23 namespace func_ext {
24 
25 void FuncAnalysisState::startFunctionAnalysis(FunctionOpInterface funcOp) {
27  auto createdEquiv = equivalentFuncArgs.try_emplace(funcOp, IndexMapping());
28  auto createdAliasingResults =
29  aliasingReturnVals.try_emplace(funcOp, IndexToIndexListMapping());
30  auto createdRead = readBbArgs.try_emplace(funcOp, BbArgIndexSet());
31  auto createdWritten = writtenBbArgs.try_emplace(funcOp, BbArgIndexSet());
32  (void)createdEquiv;
33  (void)createdAliasingResults;
34  (void)createdRead;
35  (void)createdWritten;
36 #ifndef NDEBUG
37  assert(createdEquiv.second && "equivalence info exists already");
38  assert(createdAliasingResults.second && "aliasing info exists already");
39  assert(createdRead.second && "bbarg access info exists already");
40  assert(createdWritten.second && "bbarg access info exists already");
41 #endif // NDEBUG
42 }
43 
44 /// Return the unique ReturnOp that terminates `funcOp`.
45 /// Return nullptr if there is no such unique ReturnOp.
46 static func::ReturnOp getAssumedUniqueReturnOp(FuncOp funcOp) {
47  func::ReturnOp returnOp;
48  for (Block &b : funcOp.getBody()) {
49  if (auto candidateOp = dyn_cast<func::ReturnOp>(b.getTerminator())) {
50  if (returnOp)
51  return nullptr;
52  returnOp = candidateOp;
53  }
54  }
55  return returnOp;
56 }
57 
58 /// Return the index-th bufferized function argument type. This assumes that the
59 /// specified argument is a tensor. If the tensor is ranked, a layout map may be
60 /// specified by the user (as per `options.functionArgTypeConverterFn`).
61 static BaseMemRefType
62 getBufferizedFunctionArgType(FuncOp funcOp, int64_t index,
64  auto tensorType =
65  dyn_cast<TensorType>(funcOp.getFunctionType().getInput(index));
66  assert(tensorType && "expected TensorType");
67 
68  BaseMemRefType memrefType = options.functionArgTypeConverterFn(
69  tensorType, *options.defaultMemorySpaceFn(tensorType), funcOp, options);
70 
71  auto layoutAttr = funcOp.getArgAttrOfType<AffineMapAttr>(
72  index, BufferizationDialect::kBufferLayoutAttrName);
73  if (!layoutAttr)
74  return memrefType;
75 
76  auto rankedMemrefType = dyn_cast<MemRefType>(memrefType);
77  assert(rankedMemrefType && "buffer layout not supported on unranked tensors");
78  return MemRefType::get(
79  rankedMemrefType.getShape(), rankedMemrefType.getElementType(),
80  layoutAttr.getValue(), rankedMemrefType.getMemorySpace());
81 }
82 
83 /// Return the FuncOp called by `callOp`.
84 static FuncOp getCalledFunction(CallOpInterface callOp) {
85  SymbolRefAttr sym = llvm::dyn_cast_if_present<SymbolRefAttr>(callOp.getCallableForCallee());
86  if (!sym)
87  return nullptr;
88  return dyn_cast_or_null<FuncOp>(
90 }
91 
92 /// Get FuncAnalysisState.
93 static const FuncAnalysisState &
95  assert(isa<OneShotAnalysisState>(state) && "expected OneShotAnalysisState");
96  auto *result = static_cast<const OneShotAnalysisState &>(state)
97  .getExtension<FuncAnalysisState>();
98  assert(result && "FuncAnalysisState does not exist");
99  return *result;
100 }
101 
102 /// Return the state (phase) of analysis of the FuncOp.
104  FuncOp funcOp) {
105  if (!isa<OneShotAnalysisState>(state))
107  auto *funcState = static_cast<const OneShotAnalysisState &>(state)
108  .getExtension<FuncAnalysisState>();
109  if (!funcState)
111  const auto &analyzedFuncOps = funcState->analyzedFuncOps;
112  auto it = analyzedFuncOps.find(funcOp);
113  if (it == analyzedFuncOps.end())
115  return it->second;
116 }
117 
118 /// Return the index of the bbArg in the given FuncOp that is equivalent to the
119 /// specified return value (if any).
120 static std::optional<int64_t>
121 getEquivalentFuncArgIdx(FuncOp funcOp, const FuncAnalysisState &state,
122  int64_t returnValIdx) {
123  auto funcOpIt = state.equivalentFuncArgs.find(funcOp);
124  if (funcOpIt == state.equivalentFuncArgs.end())
125  // No equivalence info stores for funcOp.
126  return std::nullopt;
127 
128  auto retValIt = funcOpIt->getSecond().find(returnValIdx);
129  if (retValIt == funcOpIt->getSecond().end())
130  // Return value has no equivalent bbArg.
131  return std::nullopt;
132 
133  return retValIt->getSecond();
134 }
135 
137  : public BufferizableOpInterface::ExternalModel<CallOpInterface,
138  func::CallOp> {
140  const AnalysisState &state) const {
141  func::CallOp callOp = cast<func::CallOp>(op);
142  FuncOp funcOp = getCalledFunction(callOp);
143  assert(funcOp && "expected CallOp to a FuncOp");
144 
146  // FuncOp not analyzed yet. Assume that OpOperand is read.
147  return true;
148 
149  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
150  return funcState.readBbArgs.lookup(funcOp).contains(
151  opOperand.getOperandNumber());
152  }
153 
155  const AnalysisState &state) const {
156  func::CallOp callOp = cast<func::CallOp>(op);
157  FuncOp funcOp = getCalledFunction(callOp);
158  assert(funcOp && "expected CallOp to a FuncOp");
159 
161  // FuncOp not analyzed yet. Assume that OpOperand is written.
162  return true;
163 
164  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
165  return funcState.writtenBbArgs.lookup(funcOp).contains(
166  opOperand.getOperandNumber());
167  }
168 
170  const AnalysisState &state) const {
171  func::CallOp callOp = cast<func::CallOp>(op);
172  FuncOp funcOp = getCalledFunction(callOp);
173  assert(funcOp && "expected CallOp to a FuncOp");
175  // FuncOp not analyzed yet. Any OpResult may be aliasing.
176  return detail::unknownGetAliasingValues(opOperand);
177 
178  // Get aliasing results from state.
179  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
180  auto aliasingReturnVals =
181  funcState.aliasingReturnVals.lookup(funcOp).lookup(
182  opOperand.getOperandNumber());
183 
184  // Check if the aliasing OpResult is equivalent to the OpOperand.
185  std::optional<int64_t> equivalent = {};
186  if (aliasingReturnVals.size() == 1) {
187  equivalent = getEquivalentFuncArgIdx(funcOp, funcState,
188  aliasingReturnVals.front());
189  assert((!equivalent.has_value() ||
190  *equivalent == opOperand.getOperandNumber()) &&
191  "inconsistent analysis state");
192  }
193  AliasingValueList result;
194  for (int64_t resultIdx : aliasingReturnVals)
195  result.addAlias({callOp->getOpResult(resultIdx),
196  equivalent.has_value() ? BufferRelation::Equivalent
198  /*isDefinite=*/equivalent.has_value()});
199  return result;
200  }
201 
202  FailureOr<BaseMemRefType>
204  SmallVector<Value> &invocationStack) const {
205  auto callOp = cast<func::CallOp>(op);
206  FuncOp funcOp = getCalledFunction(callOp);
207  assert(funcOp && "expected CallOp to a FuncOp");
208 
209  // The callee was already bufferized, so we can directly take the type from
210  // its signature.
211  FunctionType funcType = funcOp.getFunctionType();
212  return cast<BaseMemRefType>(
213  funcType.getResult(cast<OpResult>(value).getResultNumber()));
214  }
215 
216  /// All function arguments are writable. It is the responsibility of the
217  /// CallOp to insert buffer copies where necessary.
218  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
219  const BufferizationOptions &options) const {
220  func::CallOp callOp = cast<func::CallOp>(op);
221 
222  // 1. Compute the result types of the new CallOp.
223  SmallVector<Type> resultTypes;
224  for (Value result : callOp.getResults()) {
225  Type returnType = result.getType();
226  if (!isa<TensorType>(returnType)) {
227  // Non-tensor values are returned.
228  resultTypes.push_back(returnType);
229  continue;
230  }
231 
232  // Returning a memref.
233  FailureOr<BaseMemRefType> resultType =
235  if (failed(resultType))
236  return failure();
237  resultTypes.push_back(*resultType);
238  }
239 
240  // 2. Rewrite tensor operands as memrefs based on type of the already
241  // bufferized callee.
242  SmallVector<Value> newOperands;
243  FuncOp funcOp = getCalledFunction(callOp);
244  assert(funcOp && "expected CallOp to a FuncOp");
245  FunctionType funcType = funcOp.getFunctionType();
246 
247  for (OpOperand &opOperand : callOp->getOpOperands()) {
248  // Non-tensor operands are just copied.
249  if (!isa<TensorType>(opOperand.get().getType())) {
250  newOperands.push_back(opOperand.get());
251  continue;
252  }
253 
254  // Retrieve buffers for tensor operands.
255  FailureOr<Value> maybeBuffer =
256  getBuffer(rewriter, opOperand.get(), options);
257  if (failed(maybeBuffer))
258  return failure();
259  Value buffer = *maybeBuffer;
260 
261  // Caller / callee type mismatch is handled with castOrReallocMemRefValue.
262  auto memRefType = funcType.getInput(opOperand.getOperandNumber());
263  // Since we don't yet have a clear layout story, to_memref may
264  // conservatively turn tensors into more dynamic memref than necessary.
265  // If the memref type of the callee fails, introduce an extra memref.cast
266  // that will either canonicalize away or fail compilation until we can do
267  // something better. Insert a reallocation + copy if it cannot be
268  // statically guaranteed that a direct cast would be valid.
269  if (buffer.getType() != memRefType) {
270  auto memrefDstType = dyn_cast<MemRefType>(memRefType);
271  assert(memrefDstType &&
272  "buffer layout not supported on unranked tensors");
273  FailureOr<Value> replacement = bufferization::castOrReallocMemRefValue(
274  rewriter, buffer, memrefDstType, options);
275  if (failed(replacement))
276  return failure();
277  buffer = *replacement;
278  }
279  newOperands.push_back(buffer);
280  }
281 
282  // 3. Create the new CallOp.
283  Operation *newCallOp = rewriter.create<func::CallOp>(
284  callOp.getLoc(), funcOp.getSymName(), resultTypes, newOperands);
285  newCallOp->setAttrs(callOp->getAttrs());
286 
287  // 4. Replace the old op with the new op.
288  replaceOpWithBufferizedValues(rewriter, callOp, newCallOp->getResults());
289 
290  return success();
291  }
292 };
293 
295  : public BufferizableOpInterface::ExternalModel<ReturnOpInterface,
296  func::ReturnOp> {
298  const AnalysisState &state) const {
299  return true;
300  }
301 
303  const AnalysisState &state) const {
304  return false;
305  }
306 
308  const AnalysisState &state) const {
309  return {};
310  }
311 
312  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
313  const BufferizationOptions &options) const {
314 #ifndef NDEBUG
315  auto returnOp = cast<func::ReturnOp>(op);
316  assert(isa<FuncOp>(returnOp->getParentOp()) &&
317  "only support FuncOp parent for ReturnOp");
318 #endif // NDEBUG
319 
320  // ReturnOps are bufferized as part of FuncOps.
321  return success();
322  }
323 };
324 
327  FuncOpInterface, FuncOp> {
328 
329  static bool supportsUnstructuredControlFlow() { return true; }
330 
331  bool hasTensorSemantics(Operation *op) const {
332  auto isaTensor = llvm::IsaPred<TensorType>;
333 
334  // A function has tensor semantics if it has tensor arguments/results.
335  auto funcOp = cast<FuncOp>(op);
336  bool hasTensorArg = any_of(funcOp.getArgumentTypes(), isaTensor);
337  bool hasTensorResult = any_of(funcOp.getResultTypes(), isaTensor);
338  if (hasTensorArg || hasTensorResult)
339  return true;
340 
341  // It also has tensor semantics if it has tensor block arguments.
342  // TODO: Decouple bufferization of unstructured control flow from
343  // BufferizableOpInterface implementations. We should only care about
344  // region entry block arguments here (which are already covered by the
345  // argument types of the function).
346  for (Block &block : funcOp.getBody())
347  if (any_of(block.getArgumentTypes(), isaTensor))
348  return true;
349 
350  return false;
351  }
352 
355  const AnalysisState &state) const {
356  return getAliasingBranchOpOperands(op, cast<BlockArgument>(value), state);
357  }
358 
359  FailureOr<BaseMemRefType>
361  SmallVector<Value> &invocationStack) const {
362  auto funcOp = cast<FuncOp>(op);
363  auto bbArg = cast<BlockArgument>(value);
364 
365  // Function arguments are special.
366  if (bbArg.getOwner() == &funcOp.getBody().front())
367  return getBufferizedFunctionArgType(funcOp, bbArg.getArgNumber(),
368  options);
369 
371  getBufferType(op, value, options, invocationStack);
372  }
373 
374  LogicalResult verifyAnalysis(Operation *op,
375  const AnalysisState &state) const {
376  auto funcOp = cast<func::FuncOp>(op);
377  // TODO: func.func with multiple returns are not supported.
378  if (!getAssumedUniqueReturnOp(funcOp) && !funcOp.isExternal())
379  return op->emitOpError("op without unique func.return is not supported");
380  return success();
381  }
382 
383  /// Rewrite function bbArgs and return values into buffer form. This function
384  /// bufferizes the function signature and the ReturnOp. When the entire
385  /// function body has been bufferized, function return types can be switched
386  /// to more concise memref types as part of `foldMemRefCasts`.
387  ///
388  /// All function bbArgs are writable unless they are explicitly marked as
389  /// read-only. Callers must insert copies when needed.
390  LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
391  const BufferizationOptions &options) const {
392  auto funcOp = cast<FuncOp>(op);
393  FunctionType funcType = funcOp.getFunctionType();
394 
395  // Construct the bufferized function type.
396  SmallVector<Type> argTypes;
397  for (const auto &it : llvm::enumerate(funcType.getInputs())) {
398  Type argType = it.value();
399  if (dyn_cast<TensorType>(argType)) {
400  argTypes.push_back(
401  getBufferizedFunctionArgType(funcOp, it.index(), options));
402  continue;
403  }
404  argTypes.push_back(argType);
405  }
406 
407  // Bodiless functions are assumed opaque and we cannot know the
408  // bufferization contract they want to enforce. As a consequence, only
409  // support functions that don't return any tensors atm.
410  if (funcOp.isExternal()) {
411  SmallVector<Type> retTypes;
412  for (Type resultType : funcType.getResults()) {
413  if (isa<TensorType>(resultType))
414  return funcOp->emitError() << "cannot bufferize bodiless function "
415  << "that returns a tensor";
416  retTypes.push_back(resultType);
417  }
418  funcOp.setType(FunctionType::get(op->getContext(), argTypes, retTypes));
419  return success();
420  }
421 
422  // TODO: Support functions with multiple returns.
423  func::ReturnOp returnOp = getAssumedUniqueReturnOp(funcOp);
424  assert(returnOp && "expected func with single return op");
425  Location loc = returnOp.getLoc();
426 
427  // 1. Bufferize every block.
428  for (Block &block : funcOp.getBody())
429  if (failed(bufferization::bufferizeBlockSignature(&block, rewriter,
430  options)))
431  return failure();
432 
433  // 2. For each result, keep track of which inplace argument it reuses.
434  SmallVector<Value> returnValues;
435  for (OpOperand &returnOperand : returnOp->getOpOperands()) {
436  Value returnVal = returnOperand.get();
437  auto tensorType = dyn_cast<TensorType>(returnVal.getType());
438  rewriter.setInsertionPoint(returnOp);
439 
440  // If not a tensor type just forward it.
441  if (!tensorType) {
442  returnValues.push_back(returnVal);
443  continue;
444  }
445 
446  // Note: If `inferFunctionResultLayout = true`, cast are later folded
447  // away.
448  BaseMemRefType resultType = options.functionArgTypeConverterFn(
449  tensorType, *options.defaultMemorySpaceFn(tensorType), funcOp,
450  options);
451  Value toMemrefOp = rewriter.create<bufferization::ToMemrefOp>(
452  loc, resultType, returnVal);
453  returnValues.push_back(toMemrefOp);
454  }
455 
456  // 3. Rewrite the terminator without the in-place bufferizable values.
457  returnOp.getOperandsMutable().assign(returnValues);
458 
459  // 4. Rewrite the FuncOp type to buffer form.
460  funcOp.setType(FunctionType::get(op->getContext(), argTypes,
461  ValueRange(returnValues).getTypes()));
462 
463  return success();
464  }
465 
466  /// Return `true` if the given function argument is writable.
467  bool isWritable(Operation *op, Value value,
468  const AnalysisState &state) const {
469  auto funcOp = cast<FuncOp>(op);
470  BlockArgument bbArg = dyn_cast<BlockArgument>(value);
471  assert(bbArg && "expected BlockArgument");
472 
473  // Non-entry block arguments are always writable. (They may alias with
474  // values that are not writable, which will turn them into read-only.)
475  if (bbArg.getOwner() != &funcOp.getBody().front())
476  return true;
477 
478  // "bufferization.writable" overrides other writability decisions. This is
479  // currently used for testing only.
480  if (BoolAttr writable = funcOp.getArgAttrOfType<BoolAttr>(
481  bbArg.getArgNumber(), BufferizationDialect::kWritableAttrName))
482  return writable.getValue();
483 
484  // All function arguments are writable by default.
485  return true;
486  }
487 };
488 
489 } // namespace func_ext
490 } // namespace bufferization
491 } // namespace mlir
492 
495  registry.addExtension(+[](MLIRContext *ctx, func::FuncDialect *dialect) {
496  func::CallOp::attachInterface<func_ext::CallOpInterface>(*ctx);
497  func::FuncOp::attachInterface<func_ext::FuncOpInterface>(*ctx);
498  func::ReturnOp::attachInterface<func_ext::ReturnOpInterface>(*ctx);
499  });
500 }
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:149
This class represents an argument of a Block.
Definition: Value.h:319
Block * getOwner() const
Returns the block that owns this argument.
Definition: Value.h:328
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:331
Block represents an ordered list of Operations.
Definition: Block.h:31
Operation & front()
Definition: Block.h:151
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.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:66
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition: Builders.h:406
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:488
This class represents an operand of an operation.
Definition: Value.h:267
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Definition: Value.cpp:216
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:305
result_range getResults()
Definition: Operation.h:410
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:400
static 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 provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
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:129
AnalysisState provides a variety of helper functions for dealing with tensor values.
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 FuncOpAnalysisState getFuncOpAnalysisState(const AnalysisState &state, FuncOp funcOp)
Return the state (phase) of analysis of the FuncOp.
static func::ReturnOp getAssumedUniqueReturnOp(FuncOp funcOp)
Return the unique ReturnOp that terminates funcOp.
static const FuncAnalysisState & getFuncAnalysisState(const AnalysisState &state)
Get FuncAnalysisState.
static FuncOp getCalledFunction(CallOpInterface callOp)
Return the FuncOp called by callOp.
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.
LogicalResult bufferizeBlockSignature(Block *block, RewriterBase &rewriter, const BufferizationOptions &options)
Bufferize the signature of block and its callers (i.e., ops that have the given block as a successor)...
Definition: Bufferize.cpp:537
FailureOr< BaseMemRefType > getBufferType(Value value, const BufferizationOptions &options)
Return the buffer type for a given Value (tensor) after bufferization without bufferizing any IR.
FailureOr< Value > getBuffer(RewriterBase &rewriter, Value value, const BufferizationOptions &options)
Lookup the buffer for the given value.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
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...
FailureOr< BaseMemRefType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, SmallVector< Value > &invocationStack) const
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...
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand, const AnalysisState &state) const
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options) const
All function arguments are writable.
FailureOr< BaseMemRefType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, SmallVector< Value > &invocationStack) const
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.
void startFunctionAnalysis(FunctionOpInterface funcOp)
This function is called right before analyzing the given FuncOp.
DenseMap< FunctionOpInterface, IndexToIndexListMapping > aliasingReturnVals
A mapping of FuncOp BBArg indices to aliasing ReturnOp OpOperand indices.
DenseMap< FunctionOpInterface, FuncOpAnalysisState > analyzedFuncOps
Keep track of which FuncOps are fully analyzed or currently being analyzed.
DenseMap< int64_t, SmallVector< int64_t > > IndexToIndexListMapping
A mapping of indices to a list of indices.
DenseMap< FunctionOpInterface, IndexMapping > equivalentFuncArgs
A mapping of ReturnOp OpOperand indices to equivalent FuncOp BBArg indices.
DenseMap< FunctionOpInterface, BbArgIndexSet > writtenBbArgs
A set of all written-to BlockArguments of FuncOps.
DenseMap< FunctionOpInterface, BbArgIndexSet > readBbArgs
A set of all read BlockArguments of FuncOps.
DenseSet< int64_t > BbArgIndexSet
A set of block argument indices.
DenseMap< int64_t, int64_t > IndexMapping
A mapping of indices to indices.
AliasingOpOperandList getAliasingOpOperands(Operation *op, Value value, const AnalysisState &state) const
LogicalResult verifyAnalysis(Operation *op, const AnalysisState &state) const
FailureOr< BaseMemRefType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, SmallVector< Value > &invocationStack) const
bool isWritable(Operation *op, Value value, const AnalysisState &state) const
Return true if the given function argument is writable.
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options) 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
LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options) const
bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand, const AnalysisState &state) const