84 func::FuncDialect::getDialectNamespace());
85 assert(maybeState &&
"FuncAnalysisState does not exist");
92 func::FuncDialect::getDialectNamespace());
99 func::FuncOp funcOp) {
110 func::ReturnOp returnOp;
111 for (
Block &b : funcOp.getBody()) {
112 if (
auto candidateOp = dyn_cast<func::ReturnOp>(b.getTerminator())) {
115 returnOp = candidateOp;
124 static void annotateEquivalentReturnBbArg(
OpOperand &returnVal,
126 const char *kEquivalentArgsAttr =
"__equivalent_func_args__";
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();
141 op->
setAttr(kEquivalentArgsAttr, b.getI64ArrayAttr(equivBbArgs));
146 static LogicalResult aliasingFuncOpBBArgsAnalysis(FuncOp funcOp,
152 assert(returnOp &&
"expected func with single return op");
154 for (
OpOperand &returnVal : returnOp->getOpOperands())
157 if (bbArg.
getType().
isa<RankedTensorType>()) {
163 annotateEquivalentReturnBbArg(returnVal, bbArg);
174 static void annotateFuncArgAccess(func::FuncOp funcOp,
BlockArgument bbArg,
175 bool isRead,
bool isWritten) {
178 if (isRead && isWritten) {
179 accessType = b.getStringAttr(
"read-write");
181 accessType = b.getStringAttr(
"read");
182 }
else if (isWritten) {
183 accessType = b.getStringAttr(
"write");
185 accessType = b.getStringAttr(
"none");
187 funcOp.setArgAttr(bbArg.
getArgNumber(),
"bufferization.access", accessType);
193 static LogicalResult funcOpBbArgReadWriteAnalysis(FuncOp funcOp,
199 if (funcOp.getBody().empty()) {
214 annotateFuncArgAccess(funcOp, bbArg, isRead, isWritten);
229 BufferizationDialect::kBufferLayoutAttrName);
231 BufferizationDialect::kWritableAttrName);
236 SymbolRefAttr sym = callOp.getCallableForCallee().dyn_cast<SymbolRefAttr>();
239 return dyn_cast_or_null<func::FuncOp>(
251 funcOp->walk([&](func::CallOp callOp) {
253 assert(calledFunction &&
"could not retrieved called func::FuncOp");
260 int64_t returnIdx = it.first;
261 int64_t bbargIdx = it.second;
262 if (!state.
isInPlace(callOp->getOpOperand(bbargIdx)))
264 Value returnVal = callOp.getResult(returnIdx);
265 Value argVal = callOp->getOperand(bbargIdx);
288 if (!funcOp.getBody().empty()) {
291 return funcOp->emitError()
292 <<
"cannot bufferize a FuncOp with tensors and " 293 "without a unique ReturnOp";
296 numberCallOpsContainedInFuncOp[funcOp] = 0;
299 if (!isa<func::CallOp>(callOp.getOperation()))
300 return callOp->emitError() <<
"expected a 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]++;
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);
333 BufferizableOpInterface::kInplaceableAttrName,
340 auto bufferizableOp = cast<BufferizableOpInterface>(funcOp.getOperation());
354 if (funcOp.getBody().empty())
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());
365 resultTypes.push_back(operand.get().getType());
369 auto newFuncType = FunctionType::get(
370 funcOp.getContext(), funcOp.getFunctionType().getInputs(), resultTypes);
371 funcOp.setType(newFuncType);
380 "expected that function boundary bufferization is activated");
394 for (func::FuncOp funcOp : orderedFuncOps) {
396 if (funcOp.getBody().empty())
410 if (
failed(aliasingFuncOpBBArgsAnalysis(funcOp, state)) ||
411 failed(funcOpBbArgReadWriteAnalysis(funcOp, state)))
429 assert(
options.bufferizeFunctionBoundaries &&
430 "expected that function boundary bufferization is activated");
443 for (func::FuncOp funcOp : orderedFuncOps) {
449 if (
options.functionBoundaryTypeConversion ==
455 moduleOp.walk([&](func::FuncOp op) {
466 "expected that function boundary bufferization is activated");
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.
void startFunctionAnalysis(FuncOp funcOp)
This function is called right before analyzing the given FuncOp.
Operation is a basic unit of execution within MLIR.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Block represents an ordered list of Operations.
bool wasInterrupted() const
Returns true if the walk was interrupted.
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...
bool areEquivalentBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 bufferize to equivalent buffers.
unsigned getNumOperands()
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.
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.
Block * getOwner() const
Returns the block that owns this argument.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
This class represents an efficient way to signal success or failure.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
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.
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()
IRValueT get() const
Return the current value being used by this operand.
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:
This class represents an argument of a Block.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
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 ...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
static llvm::ManagedStatic< PassManagerOptions > options
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
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.
State for analysis-enabled bufferization.
Operation * getOwner() const
Return the owner of this operand.
DenseMap< FuncOp, IndexMapping > equivalentFuncArgs
A mapping of ReturnOp OpOperand indices to equivalent FuncOp BBArg indices.
This class represents an operand of an operation.
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.
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.
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.
static FuncOp getCalledFunction(CallOpInterface callOp)
Return the FuncOp called by callOp.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
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.
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.