MLIR  18.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 
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.defaultMemorySpace, 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 
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.
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 a CastOp.
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.
268  if (buffer.getType() != memRefType) {
269  assert(
270  memref::CastOp::areCastCompatible(buffer.getType(), memRefType) &&
271  "CallOp::bufferize: cast incompatible");
272  Value castBuffer = rewriter.create<memref::CastOp>(callOp.getLoc(),
273  memRefType, buffer);
274  buffer = castBuffer;
275  }
276  newOperands.push_back(buffer);
277  }
278 
279  // 3. Create the new CallOp.
280  Operation *newCallOp = rewriter.create<func::CallOp>(
281  callOp.getLoc(), funcOp.getSymName(), resultTypes, newOperands);
282  newCallOp->setAttrs(callOp->getAttrs());
283 
284  // 4. Replace the old op with the new op.
285  replaceOpWithBufferizedValues(rewriter, callOp, newCallOp->getResults());
286 
287  return success();
288  }
289 };
290 
292  : public BufferizableOpInterface::ExternalModel<ReturnOpInterface,
293  func::ReturnOp> {
295  const AnalysisState &state) const {
296  return true;
297  }
298 
300  const AnalysisState &state) const {
301  return false;
302  }
303 
305  const AnalysisState &state) const {
306  return {};
307  }
308 
310  const BufferizationOptions &options) const {
311 #ifndef NDEBUG
312  auto returnOp = cast<func::ReturnOp>(op);
313  assert(isa<FuncOp>(returnOp->getParentOp()) &&
314  "only support FuncOp parent for ReturnOp");
315 #endif // NDEBUG
316 
317  // ReturnOps are bufferized as part of FuncOps.
318  return success();
319  }
320 };
321 
324  FuncOpInterface, FuncOp> {
325 
326  static bool supportsUnstructuredControlFlow() { return true; }
327 
330  const AnalysisState &state) const {
331  return getAliasingBranchOpOperands(op, cast<BlockArgument>(value), state);
332  }
333 
336  SmallVector<Value> &invocationStack) const {
337  auto funcOp = cast<FuncOp>(op);
338  auto bbArg = cast<BlockArgument>(value);
339 
340  // Function arguments are special.
341  if (bbArg.getOwner() == &funcOp.getBody().front())
342  return getBufferizedFunctionArgType(funcOp, bbArg.getArgNumber(),
343  options);
344 
346  getBufferType(op, value, options, invocationStack);
347  }
348 
350  const AnalysisState &state) const {
351  auto funcOp = cast<func::FuncOp>(op);
352  // TODO: func.func with multiple returns are not supported.
353  if (!getAssumedUniqueReturnOp(funcOp) && !funcOp.isExternal())
354  return op->emitOpError("op without unique func.return is not supported");
355  return success();
356  }
357 
358  /// Rewrite function bbArgs and return values into buffer form. This function
359  /// bufferizes the function signature and the ReturnOp. When the entire
360  /// function body has been bufferized, function return types can be switched
361  /// to more concise memref types as part of `foldMemRefCasts`.
362  ///
363  /// All function bbArgs are writable unless they are explicitly marked as
364  /// read-only. Callers must insert copies when needed.
366  const BufferizationOptions &options) const {
367  auto funcOp = cast<FuncOp>(op);
368  FunctionType funcType = funcOp.getFunctionType();
369 
370  // Construct the bufferized function type.
371  SmallVector<Type> argTypes;
372  for (const auto &it : llvm::enumerate(funcType.getInputs())) {
373  Type argType = it.value();
374  if (dyn_cast<TensorType>(argType)) {
375  argTypes.push_back(
376  getBufferizedFunctionArgType(funcOp, it.index(), options));
377  continue;
378  }
379  argTypes.push_back(argType);
380  }
381 
382  // Bodiless functions are assumed opaque and we cannot know the
383  // bufferization contract they want to enforce. As a consequence, only
384  // support functions that don't return any tensors atm.
385  if (funcOp.isExternal()) {
386  SmallVector<Type> retTypes;
387  for (Type resultType : funcType.getResults()) {
388  if (isa<TensorType>(resultType))
389  return funcOp->emitError() << "cannot bufferize bodiless function "
390  << "that returns a tensor";
391  retTypes.push_back(resultType);
392  }
393  funcOp.setType(FunctionType::get(op->getContext(), argTypes, retTypes));
394  return success();
395  }
396 
397  // TODO: Support functions with multiple returns.
398  func::ReturnOp returnOp = getAssumedUniqueReturnOp(funcOp);
399  assert(returnOp && "expected func with single return op");
400  Location loc = returnOp.getLoc();
401 
402  // 1. Bufferize every block.
403  for (Block &block : funcOp.getBody())
404  if (failed(bufferization::bufferizeBlockSignature(&block, rewriter,
405  options)))
406  return failure();
407 
408  // 2. For each result, keep track of which inplace argument it reuses.
409  SmallVector<Value> returnValues;
410  for (OpOperand &returnOperand : returnOp->getOpOperands()) {
411  Value returnVal = returnOperand.get();
412  auto tensorType = dyn_cast<TensorType>(returnVal.getType());
413  rewriter.setInsertionPoint(returnOp);
414 
415  // If not a tensor type just forward it.
416  if (!tensorType) {
417  returnValues.push_back(returnVal);
418  continue;
419  }
420 
421  // Note: If `inferFunctionResultLayout = true`, cast are later folded
422  // away.
423  BaseMemRefType resultType = options.functionArgTypeConverterFn(
424  tensorType, *options.defaultMemorySpace, funcOp, options);
425  Value toMemrefOp = rewriter.create<bufferization::ToMemrefOp>(
426  loc, resultType, returnVal);
427  returnValues.push_back(toMemrefOp);
428  }
429 
430  // 3. Rewrite the terminator without the in-place bufferizable values.
431  returnOp.getOperandsMutable().assign(returnValues);
432 
433  // 4. Rewrite the FuncOp type to buffer form.
434  funcOp.setType(FunctionType::get(op->getContext(), argTypes,
435  ValueRange(returnValues).getTypes()));
436 
437  return success();
438  }
439 
440  /// Return `true` if the given function argument is writable.
441  bool isWritable(Operation *op, Value value,
442  const AnalysisState &state) const {
443  auto funcOp = cast<FuncOp>(op);
444  BlockArgument bbArg = dyn_cast<BlockArgument>(value);
445  assert(bbArg && "expected BlockArgument");
446 
447  // Non-entry block arguments are always writable. (They may alias with
448  // values that are not writable, which will turn them into read-only.)
449  if (bbArg.getOwner() != &funcOp.getBody().front())
450  return true;
451 
452  // "bufferization.writable" overrides other writability decisions. This is
453  // currently used for testing only.
454  if (BoolAttr writable = funcOp.getArgAttrOfType<BoolAttr>(
455  bbArg.getArgNumber(), BufferizationDialect::kWritableAttrName))
456  return writable.getValue();
457 
458  // All function arguments are writable by default.
459  return true;
460  }
461 };
462 
463 } // namespace func_ext
464 } // namespace bufferization
465 } // namespace mlir
466 
469  registry.addExtension(+[](MLIRContext *ctx, func::FuncDialect *dialect) {
470  func::CallOp::attachInterface<func_ext::CallOpInterface>(*ctx);
471  func::FuncOp::attachInterface<func_ext::FuncOpInterface>(*ctx);
472  func::ReturnOp::attachInterface<func_ext::ReturnOpInterface>(*ctx);
473  });
474 }
static llvm::ManagedStatic< PassManagerOptions > options
This class provides a shared interface for ranked and unranked memref types.
Definition: BuiltinTypes.h:138
This class represents an argument of a Block.
Definition: Value.h:315
Block * getOwner() const
Returns the block that owns this argument.
Definition: Value.h:324
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:327
Block represents an ordered list of Operations.
Definition: Block.h:30
Operation & front()
Definition: Block.h:146
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.
void addExtension(std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
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:383
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:446
This class represents an operand of an operation.
Definition: Value.h:263
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:304
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:399
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:378
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:125
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.
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:567
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:285
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
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.
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
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