MLIR  15.0.0git
OneShotModuleBufferize.cpp
Go to the documentation of this file.
1 //===- ModuleBufferization.cpp - Bufferization across Func. Boundaries ----===//
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 //
9 // Module Bufferization is an extension of One-Shot Bufferize that
10 // bufferizes function boundaries. It provides `BufferizableOpInterface`
11 // implementations for FuncOp, CallOp and ReturnOp.
12 //
13 // Module Bufferization is run via `runOneShotModuleBufferize(ModuleOp, ...)`.
14 // This function analyzes the given module and determines the order of analysis
15 // and bufferization: Functions that are called are processed before their
16 // respective callers.
17 //
18 // After analyzing a FuncOp, additional information about its bbArgs is
19 // gathered and stored in `FuncAnalysisState`.
20 //
21 // * `aliasingFuncOpBBArgsAnalysis` determines the equivalent/aliasing bbArgs
22 // for
23 // each tensor return value (if any).
24 // * `funcOpBbArgReadWriteAnalysis` determines whether or not a tensor bbArg is
25 // read/written.
26 //
27 // Module Bufferization implements the following calling convention.
28 //
29 // * In the absence of conflicts within a FuncOp, the FuncOp's bbArgs may always
30 // be written to in-place.
31 // * If a tensor operand of a CallOp is read after the CallOp, the operand of
32 // the CallOp must bufferize out-of-place.
33 //
34 // Example: The tensor.insert op bufferizes in-place because it is allowed to
35 // modify the buffer of `%t1` directly. The CallOp in `caller` must bufferize
36 // out-of-place because `%t0` is modified by the callee but read by the
37 // tensor.extract op. The analysis of CallOps decides whether an OpOperand must
38 // bufferize out-of-place based on results of `funcOpBbArgReadWriteAnalysis`.
39 // ```
40 // func @callee(%t1 : tensor<?xf32>) -> tensor<?xf32> {
41 // %f = ... : f32
42 // %0 = tensor.insert %f into %t1[...] : tensor<?xf32>
43 // return %0 : tensor<?xf32>
44 // }
45 //
46 // func @caller() -> () {
47 // %t0 = ... : tensor<?xf32>
48 // %1 = call @callee(%t0) : (tensor<?xf32>) -> (tensor<?xf32>)
49 // %2 = tensor.extract %1[...] : tensor<?xf32>
50 // }
51 // ```
52 //
53 // Note: If a function is external, `funcOpBbArgReadWriteAnalysis` cannot
54 // analyze the function body. In such a case, the CallOp analysis conservatively
55 // assumes that each tensor OpOperand is both read and written.
56 //
57 // TODO: Add FuncOp attributes so that bbArgs of external FuncOps can be marked
58 // as "not reading" and/or "not writing".
59 
61 
70 #include "mlir/IR/Operation.h"
71 
72 using namespace mlir;
73 using namespace mlir::bufferization;
74 using namespace mlir::bufferization::func_ext;
75 
76 /// A mapping of FuncOps to their callers.
78 
79 /// Get FuncAnalysisState.
80 static const FuncAnalysisState &
83  state.getDialectState<FuncAnalysisState>(
84  func::FuncDialect::getDialectNamespace());
85  assert(maybeState && "FuncAnalysisState does not exist");
86  return **maybeState;
87 }
88 
89 /// Get or create FuncAnalysisState.
91  return state.getOrCreateDialectState<FuncAnalysisState>(
92  func::FuncDialect::getDialectNamespace());
93 }
94 
95 /// Return the state (phase) of analysis of the FuncOp.
96 /// Used for debug modes.
97 LLVM_ATTRIBUTE_UNUSED
99  func::FuncOp funcOp) {
100  const FuncAnalysisState &funcState = getFuncAnalysisState(state);
101  auto it = funcState.analyzedFuncOps.find(funcOp);
102  if (it == funcState.analyzedFuncOps.end())
104  return it->second;
105 }
106 
107 /// Return the unique ReturnOp that terminates `funcOp`.
108 /// Return nullptr if there is no such unique ReturnOp.
109 static func::ReturnOp getAssumedUniqueReturnOp(func::FuncOp funcOp) {
110  func::ReturnOp returnOp;
111  for (Block &b : funcOp.getBody()) {
112  if (auto candidateOp = dyn_cast<func::ReturnOp>(b.getTerminator())) {
113  if (returnOp)
114  return nullptr;
115  returnOp = candidateOp;
116  }
117  }
118  return returnOp;
119 }
120 
121 namespace {
122 
123 /// Annotate IR with the results of the analysis. For testing purposes only.
124 static void annotateEquivalentReturnBbArg(OpOperand &returnVal,
125  BlockArgument bbArg) {
126  const char *kEquivalentArgsAttr = "__equivalent_func_args__";
127  Operation *op = returnVal.getOwner();
128 
129  SmallVector<int64_t> equivBbArgs;
130  if (op->hasAttr(kEquivalentArgsAttr)) {
131  auto attr = op->getAttr(kEquivalentArgsAttr).cast<ArrayAttr>();
132  equivBbArgs = llvm::to_vector<4>(llvm::map_range(attr, [](Attribute a) {
133  return a.cast<IntegerAttr>().getValue().getSExtValue();
134  }));
135  } else {
136  equivBbArgs.append(op->getNumOperands(), -1);
137  }
138  equivBbArgs[returnVal.getOperandNumber()] = bbArg.getArgNumber();
139 
140  OpBuilder b(op->getContext());
141  op->setAttr(kEquivalentArgsAttr, b.getI64ArrayAttr(equivBbArgs));
142 }
143 
144 /// Store function BlockArguments that are equivalent to/aliasing a returned
145 /// value in FuncAnalysisState.
146 static LogicalResult aliasingFuncOpBBArgsAnalysis(FuncOp funcOp,
147  OneShotAnalysisState &state) {
148  FuncAnalysisState &funcState = getFuncAnalysisState(state);
149 
150  // Support only single return-terminated block in the function.
151  func::ReturnOp returnOp = getAssumedUniqueReturnOp(funcOp);
152  assert(returnOp && "expected func with single return op");
153 
154  for (OpOperand &returnVal : returnOp->getOpOperands())
155  if (returnVal.get().getType().isa<RankedTensorType>())
156  for (BlockArgument bbArg : funcOp.getArguments())
157  if (bbArg.getType().isa<RankedTensorType>()) {
158  int64_t returnIdx = returnVal.getOperandNumber();
159  int64_t bbArgIdx = bbArg.getArgNumber();
160  if (state.areEquivalentBufferizedValues(returnVal.get(), bbArg)) {
161  funcState.equivalentFuncArgs[funcOp][returnIdx] = bbArgIdx;
162  if (state.getOptions().testAnalysisOnly)
163  annotateEquivalentReturnBbArg(returnVal, bbArg);
164  }
165  if (state.areAliasingBufferizedValues(returnVal.get(), bbArg)) {
166  funcState.aliasingFuncArgs[funcOp][returnIdx].push_back(bbArgIdx);
167  funcState.aliasingReturnVals[funcOp][bbArgIdx].push_back(returnIdx);
168  }
169  }
170 
171  return success();
172 }
173 
174 static void annotateFuncArgAccess(func::FuncOp funcOp, BlockArgument bbArg,
175  bool isRead, bool isWritten) {
176  OpBuilder b(funcOp.getContext());
177  Attribute accessType;
178  if (isRead && isWritten) {
179  accessType = b.getStringAttr("read-write");
180  } else if (isRead) {
181  accessType = b.getStringAttr("read");
182  } else if (isWritten) {
183  accessType = b.getStringAttr("write");
184  } else {
185  accessType = b.getStringAttr("none");
186  }
187  funcOp.setArgAttr(bbArg.getArgNumber(), "bufferization.access", accessType);
188 }
189 
190 /// Determine which FuncOp bbArgs are read and which are written. When run on a
191 /// function with unknown ops, we conservatively assume that such ops bufferize
192 /// to a read + write.
193 static LogicalResult funcOpBbArgReadWriteAnalysis(FuncOp funcOp,
194  OneShotAnalysisState &state) {
195  FuncAnalysisState &funcState = getFuncAnalysisState(state);
196 
197  // If the function has no body, conservatively assume that all args are
198  // read + written.
199  if (funcOp.getBody().empty()) {
200  for (BlockArgument bbArg : funcOp.getArguments()) {
201  funcState.readBbArgs[funcOp].insert(bbArg.getArgNumber());
202  funcState.writtenBbArgs[funcOp].insert(bbArg.getArgNumber());
203  }
204 
205  return success();
206  }
207 
208  for (BlockArgument bbArg : funcOp.getArguments()) {
209  if (!bbArg.getType().isa<TensorType>())
210  continue;
211  bool isRead = state.isValueRead(bbArg);
212  bool isWritten = state.isValueWritten(bbArg);
213  if (state.getOptions().testAnalysisOnly)
214  annotateFuncArgAccess(funcOp, bbArg, isRead, isWritten);
215  if (isRead)
216  funcState.readBbArgs[funcOp].insert(bbArg.getArgNumber());
217  if (isWritten)
218  funcState.writtenBbArgs[funcOp].insert(bbArg.getArgNumber());
219  }
220 
221  return success();
222 }
223 } // namespace
224 
225 /// Remove bufferization attributes on FuncOp arguments.
227  auto funcOp = cast<func::FuncOp>(bbArg.getOwner()->getParentOp());
228  funcOp.removeArgAttr(bbArg.getArgNumber(),
229  BufferizationDialect::kBufferLayoutAttrName);
230  funcOp.removeArgAttr(bbArg.getArgNumber(),
231  BufferizationDialect::kWritableAttrName);
232 }
233 
234 /// Return the func::FuncOp called by `callOp`.
235 static func::FuncOp getCalledFunction(CallOpInterface callOp) {
236  SymbolRefAttr sym = callOp.getCallableForCallee().dyn_cast<SymbolRefAttr>();
237  if (!sym)
238  return nullptr;
239  return dyn_cast_or_null<func::FuncOp>(
241 }
242 
243 /// Gather equivalence info of CallOps.
244 /// Note: This only adds new equivalence info if the called function was already
245 /// analyzed.
246 // TODO: This does not handle cyclic function call graphs etc.
247 static void equivalenceAnalysis(func::FuncOp funcOp,
248  BufferizationAliasInfo &aliasInfo,
249  OneShotAnalysisState &state) {
250  FuncAnalysisState &funcState = getFuncAnalysisState(state);
251  funcOp->walk([&](func::CallOp callOp) {
252  func::FuncOp calledFunction = getCalledFunction(callOp);
253  assert(calledFunction && "could not retrieved called func::FuncOp");
254 
255  // No equivalence info available for the called function.
256  if (!funcState.equivalentFuncArgs.count(calledFunction))
257  return WalkResult::skip();
258 
259  for (auto it : funcState.equivalentFuncArgs[calledFunction]) {
260  int64_t returnIdx = it.first;
261  int64_t bbargIdx = it.second;
262  if (!state.isInPlace(callOp->getOpOperand(bbargIdx)))
263  continue;
264  Value returnVal = callOp.getResult(returnIdx);
265  Value argVal = callOp->getOperand(bbargIdx);
266  aliasInfo.unionEquivalenceClasses(returnVal, argVal);
267  }
268 
269  return WalkResult::advance();
270  });
271 }
272 
273 /// Store all functions of the `moduleOp` in `orderedFuncOps`, sorted by
274 /// callee-caller order (i.e. callees without callers first).
275 /// Store the map of FuncOp to all its callers in `callerMap`.
276 /// Return `failure()` if a cycle of calls is detected or if we are unable to
277 /// retrieve the called FuncOp from any CallOpInterface.
278 static LogicalResult
279 getFuncOpsOrderedByCalls(ModuleOp moduleOp,
280  SmallVectorImpl<func::FuncOp> &orderedFuncOps,
281  FuncCallerMap &callerMap) {
282  // For each FuncOp, the set of functions called by it (i.e. the union of
283  // symbols of all nested CallOpInterfaceOp).
285  // For each FuncOp, the number of CallOpInterface it contains.
286  DenseMap<func::FuncOp, unsigned> numberCallOpsContainedInFuncOp;
287  WalkResult res = moduleOp.walk([&](func::FuncOp funcOp) -> WalkResult {
288  if (!funcOp.getBody().empty()) {
289  func::ReturnOp returnOp = getAssumedUniqueReturnOp(funcOp);
290  if (!returnOp)
291  return funcOp->emitError()
292  << "cannot bufferize a FuncOp with tensors and "
293  "without a unique ReturnOp";
294  }
295 
296  numberCallOpsContainedInFuncOp[funcOp] = 0;
297  return funcOp.walk([&](CallOpInterface callOp) -> WalkResult {
298  // Only support CallOp for now.
299  if (!isa<func::CallOp>(callOp.getOperation()))
300  return callOp->emitError() << "expected a CallOp";
301  func::FuncOp calledFunction = getCalledFunction(callOp);
302  assert(calledFunction && "could not retrieved called func::FuncOp");
303  callerMap[calledFunction].insert(callOp);
304  if (calledBy[calledFunction].insert(funcOp).second) {
305  numberCallOpsContainedInFuncOp[funcOp]++;
306  }
307  return WalkResult::advance();
308  });
309  });
310  if (res.wasInterrupted())
311  return failure();
312  // Iteratively remove function operation that do not call any of the
313  // functions remaining in the callCounter map and add them to the worklist.
314  while (!numberCallOpsContainedInFuncOp.empty()) {
315  auto it = llvm::find_if(numberCallOpsContainedInFuncOp,
316  [](auto entry) { return entry.getSecond() == 0; });
317  if (it == numberCallOpsContainedInFuncOp.end())
318  return moduleOp.emitOpError(
319  "expected callgraph to be free of circular dependencies.");
320  orderedFuncOps.push_back(it->getFirst());
321  for (auto callee : calledBy[it->getFirst()])
322  numberCallOpsContainedInFuncOp[callee]--;
323  numberCallOpsContainedInFuncOp.erase(it);
324  }
325  return success();
326 }
327 
328 /// Set the attribute that triggers inplace bufferization on a FuncOp argument
329 /// `bbArg`.
330 static void setInPlaceFuncArgument(BlockArgument bbArg, bool inPlace) {
331  auto funcOp = cast<func::FuncOp>(bbArg.getOwner()->getParentOp());
332  funcOp.setArgAttr(bbArg.getArgNumber(),
333  BufferizableOpInterface::kInplaceableAttrName,
334  BoolAttr::get(bbArg.getContext(), inPlace));
335 }
336 
337 /// Annotate the IR with the result of the analysis. For testing/debugging only.
338 static void annotateOpsWithBufferizationMarkers(func::FuncOp funcOp,
339  const AnalysisState &state) {
340  auto bufferizableOp = cast<BufferizableOpInterface>(funcOp.getOperation());
341  for (BlockArgument bbArg : funcOp.getArguments())
342  if (bbArg.getType().isa<TensorType>())
343  setInPlaceFuncArgument(bbArg, bufferizableOp.isWritable(bbArg, state));
344 }
345 
346 /// Fold return values that are memref casts and update function return types.
347 ///
348 /// During FuncOp bufferization, the exact type of the returned memrefs (if any)
349 /// is not known yet. Therefore, the bufferization uses memref types with the
350 /// most generic layout map as function return types. After bufferizing the
351 /// entire function body, a more concise memref type can potentially be used for
352 /// the return type of the function.
353 static void foldMemRefCasts(func::FuncOp funcOp) {
354  if (funcOp.getBody().empty())
355  return;
356 
357  func::ReturnOp returnOp = getAssumedUniqueReturnOp(funcOp);
358  SmallVector<Type> resultTypes;
359 
360  for (OpOperand &operand : returnOp->getOpOperands()) {
361  if (auto castOp = operand.get().getDefiningOp<memref::CastOp>()) {
362  operand.set(castOp.source());
363  resultTypes.push_back(castOp.source().getType());
364  } else {
365  resultTypes.push_back(operand.get().getType());
366  }
367  }
368 
369  auto newFuncType = FunctionType::get(
370  funcOp.getContext(), funcOp.getFunctionType().getInputs(), resultTypes);
371  funcOp.setType(newFuncType);
372 }
373 
376  OneShotAnalysisState &state) {
378  static_cast<const OneShotBufferizationOptions &>(state.getOptions());
379  assert(options.bufferizeFunctionBoundaries &&
380  "expected that function boundary bufferization is activated");
381  FuncAnalysisState &funcState = getFuncAnalysisState(state);
382  BufferizationAliasInfo &aliasInfo = state.getAliasInfo();
383 
384  // A list of functions in the order in which they are analyzed + bufferized.
385  SmallVector<func::FuncOp> orderedFuncOps;
386 
387  // A mapping of FuncOps to their callers.
388  FuncCallerMap callerMap;
389 
390  if (failed(getFuncOpsOrderedByCalls(moduleOp, orderedFuncOps, callerMap)))
391  return failure();
392 
393  // Analyze ops.
394  for (func::FuncOp funcOp : orderedFuncOps) {
395  // No body => no analysis.
396  if (funcOp.getBody().empty())
397  continue;
398 
399  // Now analyzing function.
400  funcState.startFunctionAnalysis(funcOp);
401 
402  // Gather equivalence info for CallOps.
403  equivalenceAnalysis(funcOp, aliasInfo, state);
404 
405  // Analyze funcOp.
406  if (failed(analyzeOp(funcOp, state)))
407  return failure();
408 
409  // Run some extra function analyses.
410  if (failed(aliasingFuncOpBBArgsAnalysis(funcOp, state)) ||
411  failed(funcOpBbArgReadWriteAnalysis(funcOp, state)))
412  return failure();
413 
414  // Mark op as fully analyzed.
416 
417  // Add annotations to function arguments.
418  if (options.testAnalysisOnly)
420  }
421 
422  return success();
423 }
424 
426  ModuleOp moduleOp, const OneShotAnalysisState &analysisState) {
427  auto const &options = static_cast<const OneShotBufferizationOptions &>(
428  analysisState.getOptions());
429  assert(options.bufferizeFunctionBoundaries &&
430  "expected that function boundary bufferization is activated");
431  IRRewriter rewriter(moduleOp.getContext());
432 
433  // A list of functions in the order in which they are analyzed + bufferized.
434  SmallVector<func::FuncOp> orderedFuncOps;
435 
436  // A mapping of FuncOps to their callers.
437  FuncCallerMap callerMap;
438 
439  if (failed(getFuncOpsOrderedByCalls(moduleOp, orderedFuncOps, callerMap)))
440  return failure();
441 
442  // Bufferize functions.
443  for (func::FuncOp funcOp : orderedFuncOps) {
444  // Note: It would be good to apply cleanups here but we cannot as aliasInfo
445  // would be invalidated.
446  if (failed(bufferizeOp(funcOp, options, /*copyBeforeWrite=*/false)))
447  return failure();
448  // Change buffer return types to more precise layout maps.
449  if (options.functionBoundaryTypeConversion ==
451  foldMemRefCasts(funcOp);
452  }
453 
454  // Post-pass cleanup of function argument attributes.
455  moduleOp.walk([&](func::FuncOp op) {
456  for (BlockArgument bbArg : op.getArguments())
458  });
459 
460  return success();
461 }
462 
464  ModuleOp moduleOp, const OneShotBufferizationOptions &options) {
465  assert(options.bufferizeFunctionBoundaries &&
466  "expected that function boundary bufferization is activated");
467  OneShotAnalysisState analysisState(moduleOp, options);
468  if (failed(insertTensorCopies(moduleOp, options)))
469  return failure();
470  if (options.testAnalysisOnly)
471  return success();
472  if (failed(bufferizeModuleOp(moduleOp, analysisState)))
473  return failure();
474  return success();
475 }
TODO: Remove this file when SCCP and integer range analysis have been ported to the new framework...
static void equivalenceAnalysis(func::FuncOp funcOp, BufferizationAliasInfo &aliasInfo, OneShotAnalysisState &state)
Gather equivalence info of CallOps.
LogicalResult bufferizeModuleOp(ModuleOp moduleOp, const OneShotAnalysisState &analysisState)
Bufferize op and its nested ops that implement BufferizableOpInterface.
LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state)
Analyze op and its nested ops.
LogicalResult runOneShotModuleBufferize(ModuleOp moduleOp, const bufferization::OneShotBufferizationOptions &options)
Run One-Shot Module Bufferization on the given module.
U cast() const
Definition: Attributes.h:130
void startFunctionAnalysis(FuncOp funcOp)
This function is called right before analyzing the given FuncOp.
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:30
Block represents an ordered list of Operations.
Definition: Block.h:29
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
const BufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
bool areEquivalentBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 bufferize to equivalent buffers.
unsigned getNumOperands()
Definition: Operation.h:270
bool testAnalysisOnly
If set to true, does not modify the IR apart from adding attributes (for checking the results of the ...
LogicalResult insertTensorCopies(Operation *op, const OneShotBufferizationOptions &options)
DenseMap< FuncOp, IndexToIndexListMapping > aliasingFuncArgs
A mapping of ReturnOp OpOperand indices to aliasing FuncOp BBArg indices.
static const FuncAnalysisState & getFuncAnalysisState(const AnalysisState &state)
Get FuncAnalysisState.
DenseMap< FuncOp, FuncOpAnalysisState > analyzedFuncOps
Keep track of which FuncOps are fully analyzed or currently being analyzed.
void unionEquivalenceClasses(Value v1, Value v2)
Union the equivalence classes of v1 and v2.
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:312
The BufferizationAliasInfo class maintains a list of buffer aliases and equivalence classes to suppor...
static void removeBufferizationAttributes(BlockArgument bbArg)
Remove bufferization attributes on FuncOp arguments.
static void foldMemRefCasts(func::FuncOp funcOp)
Fold return values that are memref casts and update function return types.
static func::ReturnOp getAssumedUniqueReturnOp(FuncOp funcOp)
Return the unique ReturnOp that terminates funcOp.
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:154
Block * getOwner() const
Returns the block that owns this argument.
Definition: Value.h:309
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Definition: Value.cpp:212
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
Definition: Operation.h:392
static FuncOpAnalysisState getFuncOpAnalysisState(const AnalysisState &state, FuncOp funcOp)
Return the state (phase) of analysis of the FuncOp.
LogicalResult analyzeModuleOp(ModuleOp moduleOp, OneShotAnalysisState &state)
Analyze moduleOp and its nested ops.
Attributes are known-constant values of operations.
Definition: Attributes.h:24
Extra analysis state that is required for bufferization of function boundaries.
DenseMap< FuncOp, BbArgIndexSet > writtenBbArgs
A set of all written-to BlockArguments of FuncOps.
static WalkResult advance()
Definition: Visitors.h:51
IRValueT get() const
Return the current value being used by this operand.
Definition: UseDefLists.h:133
bool areAliasingBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 may bufferize to aliasing buffers.
bool bufferizeFunctionBoundaries
Specifies whether function boundaries (ops in the func dialect) should be bufferized or not...
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
This class represents an argument of a Block.
Definition: Value.h:300
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Definition: BuiltinTypes.h:77
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of...
bool isValueWritten(Value value) const
Return true if the buffer of the given tensor value is written to.
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
Definition: PatternMatch.h:584
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
static llvm::ManagedStatic< PassManagerOptions > options
static WalkResult skip()
Definition: Visitors.h:52
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
Definition: Operation.h:402
static LogicalResult getFuncOpsOrderedByCalls(ModuleOp moduleOp, SmallVectorImpl< func::FuncOp > &orderedFuncOps, FuncCallerMap &callerMap)
Store all functions of the moduleOp in orderedFuncOps, sorted by callee-caller order (i...
Type getType() const
Return the type of this value.
Definition: Value.h:118
State for analysis-enabled bufferization.
Operation * getOwner() const
Return the owner of this operand.
Definition: UseDefLists.h:37
DenseMap< FuncOp, IndexMapping > equivalentFuncArgs
A mapping of ReturnOp OpOperand indices to equivalent FuncOp BBArg indices.
This class represents an operand of an operation.
Definition: Value.h:251
bool isValueRead(Value value) const
Return true if the given value is read by an op that bufferizes to a memory read. ...
LogicalResult bufferizeOp(Operation *op, const BufferizationOptions &options, bool copyBeforeWrite=true, const OpFilter *opFilter=nullptr)
Bufferize op and its nested ops that implement BufferizableOpInterface.
Definition: Bufferize.cpp:371
BufferizationAliasInfo & getAliasInfo()
Return a reference to the BufferizationAliasInfo.
DenseMap< FuncOp, BbArgIndexSet > readBbArgs
A set of all read BlockArguments of FuncOps.
static BoolAttr get(MLIRContext *context, bool value)
FuncOpAnalysisState
The state of analysis of a FuncOp.
bool isa() const
Definition: Types.h:246
static void annotateOpsWithBufferizationMarkers(func::FuncOp funcOp, const AnalysisState &state)
Annotate the IR with the result of the analysis. For testing/debugging only.
bool isInPlace(OpOperand &opOperand) const override
Return true if the given OpResult has been decided to bufferize inplace.
This class helps build Operations.
Definition: Builders.h:184
static FuncOp getCalledFunction(CallOpInterface callOp)
Return the FuncOp called by callOp.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Definition: Operation.h:378
DenseMap< FuncOp, IndexToIndexListMapping > aliasingReturnVals
A mapping of FuncOp BBArg indices to aliasing ReturnOp OpOperand indices.
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Definition: Value.h:121
Options for analysis-enabled bufferization.
static void setInPlaceFuncArgument(BlockArgument bbArg, bool inPlace)
Set the attribute that triggers inplace bufferization on a FuncOp argument bbArg. ...
Base class for generic analysis states.