24 for (
Block &b : funcOp.getBody())
25 if (
auto returnOp = dyn_cast<func::ReturnOp>(b.getTerminator()))
26 result.push_back(returnOp);
30 namespace bufferization {
36 auto createdAliasingResults =
41 (void)createdAliasingResults;
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");
56 TensorLikeType type) {
57 if (
auto tensorType = dyn_cast<TensorType>(type)) {
58 return *
options.defaultMemorySpaceFn(tensorType);
70 dyn_cast<TensorLikeType>(funcOp.getFunctionType().getInput(index));
71 assert(type &&
"expected TensorLikeType");
74 if (
auto tensorType = dyn_cast<TensorType>(type)) {
75 BufferLikeType memrefType =
options.functionArgTypeConverterFn(
78 auto layoutAttr = funcOp.getArgAttrOfType<MemRefLayoutAttrInterface>(
79 index, BufferizationDialect::kBufferLayoutAttrName);
83 auto rankedMemrefType = dyn_cast<MemRefType>(memrefType);
84 assert(rankedMemrefType &&
85 "buffer layout not supported on unranked tensors");
87 rankedMemrefType.getShape(), rankedMemrefType.getElementType(),
88 layoutAttr, rankedMemrefType.getMemorySpace()));
91 return options.functionArgTypeConverterFn(type,
nullptr, funcOp,
99 llvm::dyn_cast_if_present<SymbolRefAttr>(callOp.getCallableForCallee());
102 return dyn_cast_or_null<FuncOp>(
111 if (
auto *funcAnalysisState =
122 static const FuncAnalysisState &
124 assert(isa<OneShotAnalysisState>(state) &&
"expected OneShotAnalysisState");
126 .getExtension<FuncAnalysisState>();
127 assert(result &&
"FuncAnalysisState does not exist");
134 if (!isa<OneShotAnalysisState>(state))
137 .getExtension<FuncAnalysisState>();
140 const auto &analyzedFuncOps = funcState->analyzedFuncOps;
141 auto it = analyzedFuncOps.find(funcOp);
142 if (it == analyzedFuncOps.end())
149 static std::optional<int64_t>
151 int64_t returnValIdx) {
152 auto funcOpIt = state.equivalentFuncArgs.find(funcOp);
153 if (funcOpIt == state.equivalentFuncArgs.end())
157 auto retValIt = funcOpIt->getSecond().find(returnValIdx);
158 if (retValIt == funcOpIt->getSecond().end())
162 return retValIt->getSecond();
166 :
public BufferizableOpInterface::ExternalModel<CallOpInterface,
170 func::CallOp callOp = cast<func::CallOp>(op);
172 assert(funcOp &&
"expected CallOp to a FuncOp");
179 return funcState.
readBbArgs.lookup(funcOp).contains(
185 func::CallOp callOp = cast<func::CallOp>(op);
187 assert(funcOp &&
"expected CallOp to a FuncOp");
200 func::CallOp callOp = cast<func::CallOp>(op);
202 assert(funcOp &&
"expected CallOp to a FuncOp");
209 auto aliasingReturnVals =
214 std::optional<int64_t> equivalent = {};
215 if (aliasingReturnVals.size() == 1) {
217 aliasingReturnVals.front());
218 assert((!equivalent.has_value() ||
220 "inconsistent analysis state");
223 for (int64_t resultIdx : aliasingReturnVals)
224 result.
addAlias({callOp->getOpResult(resultIdx),
227 equivalent.has_value()});
231 FailureOr<BufferLikeType>
235 auto callOp = cast<func::CallOp>(op);
241 assert(funcOp &&
"expected CallOp to a FuncOp");
245 FunctionType funcType = funcOp.getFunctionType();
247 funcType.getResult(cast<OpResult>(value).getResultNumber());
248 if (
auto bufferizedType = dyn_cast<BufferLikeType>(resultType))
249 return bufferizedType;
252 auto tensorType = cast<TensorLikeType>(resultType);
253 return cast<BufferLikeType>(
options.functionArgTypeConverterFn(
263 func::CallOp callOp = cast<func::CallOp>(op);
267 for (
Value result : callOp.getResults()) {
268 Type returnType = result.getType();
269 if (!isa<TensorLikeType>(returnType)) {
271 resultTypes.push_back(returnType);
276 FailureOr<BufferLikeType> resultType =
280 resultTypes.push_back(*resultType);
288 assert(funcOp &&
"expected CallOp to a FuncOp");
289 FunctionType funcType = funcOp.getFunctionType();
291 for (
OpOperand &opOperand : callOp->getOpOperands()) {
293 if (!isa<TensorLikeType>(opOperand.get().getType())) {
294 newOperands.push_back(opOperand.get());
299 FailureOr<Value> maybeBuffer =
303 Value buffer = *maybeBuffer;
306 auto bufferType = funcType.getInput(opOperand.getOperandNumber());
307 if (!isa<BufferLikeType>(bufferType)) {
311 FailureOr<BufferLikeType> maybeBufferType =
313 funcOp.getArgument(opOperand.getOperandNumber()),
options,
315 if (
failed(maybeBufferType))
317 bufferType = *maybeBufferType;
326 if (buffer.
getType() != bufferType) {
327 auto memrefDstType = dyn_cast<MemRefType>(bufferType);
328 assert(memrefDstType &&
329 "buffer layout not supported on unranked tensors");
331 rewriter, buffer, memrefDstType,
options);
334 buffer = *replacement;
336 newOperands.push_back(buffer);
341 func::CallOp::create(rewriter, callOp.getLoc(), funcOp.getSymName(),
342 resultTypes, newOperands);
343 newCallOp->
setAttrs(callOp->getAttrs());
353 :
public BufferizableOpInterface::ExternalModel<ReturnOpInterface,
374 auto returnOp = cast<func::ReturnOp>(op);
375 assert(isa<FuncOp>(returnOp->getParentOp()) &&
376 "only support FuncOp parent for ReturnOp");
386 FuncOpInterface, FuncOp> {
391 auto isaTensor = llvm::IsaPred<TensorLikeType>;
394 auto funcOp = cast<FuncOp>(op);
395 bool hasTensorArg = any_of(funcOp.getArgumentTypes(),
isaTensor);
396 bool hasTensorResult = any_of(funcOp.getResultTypes(),
isaTensor);
397 if (hasTensorArg || hasTensorResult)
405 for (
Block &block : funcOp.getBody())
406 if (any_of(block.getArgumentTypes(),
isaTensor))
418 FailureOr<BufferLikeType>
422 auto funcOp = cast<FuncOp>(op);
423 auto bbArg = cast<BlockArgument>(value);
426 if (bbArg.getOwner() == &funcOp.getBody().front())
444 auto funcOp = cast<FuncOp>(op);
445 FunctionType funcType = funcOp.getFunctionType();
450 Type argType = it.value();
451 if (isa<TensorLikeType>(argType)) {
456 argTypes.push_back(argType);
461 for (
Type resultType : funcType.getResults()) {
462 if (
auto tensorType = dyn_cast<TensorLikeType>(resultType)) {
463 BufferLikeType resultType =
options.functionArgTypeConverterFn(
466 retTypes.push_back(resultType);
469 retTypes.push_back(resultType);
476 if (funcOp.isExternal()) {
477 funcOp.setType(newFuncType);
482 for (
Block &block : funcOp.getBody())
489 assert(returnOp->getNumOperands() == retTypes.size() &&
490 "incorrect number of return values");
492 for (
auto [returnVal, bufferizedType] :
493 llvm::zip_equal(returnOp->getOperands(), retTypes)) {
494 auto tensorType = dyn_cast<TensorLikeType>(returnVal.getType());
499 returnValues.push_back(returnVal);
505 Value toBufferOp = bufferization::ToBufferOp::create(
506 rewriter, returnOp.getLoc(), bufferizedType, returnVal);
507 returnValues.push_back(toBufferOp);
510 returnOp.getOperandsMutable().assign(returnValues);
514 funcOp.setType(newFuncType);
521 auto funcOp = cast<FuncOp>(op);
523 assert(bbArg &&
"expected BlockArgument");
533 bbArg.
getArgNumber(), BufferizationDialect::kWritableAttrName))
534 return writable.getValue();
548 func::CallOp::attachInterface<func_ext::CallOpInterface>(*ctx);
549 func::FuncOp::attachInterface<func_ext::FuncOpInterface>(*ctx);
550 func::ReturnOp::attachInterface<func_ext::ReturnOpInterface>(*ctx);
static bool isaTensor(Type t)
static llvm::ManagedStatic< PassManagerOptions > options
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block * getOwner() const
Returns the block that owns this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
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.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
This class represents an operand of an operation.
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Operation is the basic unit of execution within MLIR.
void setAttrs(DictionaryAttr newAttrs)
Set the attributes from a dictionary on this operation.
MLIRContext * getContext()
Return the context this operation is associated with.
result_range getResults()
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
This class represents a collection of SymbolTables.
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...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
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 BufferLikeType getBufferizedFunctionArgType(FuncOp funcOp, int64_t index, const BufferizationOptions &options)
Return the index-th bufferized function argument type.
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 ®istry)
static FuncOp getCalledFunction(CallOpInterface callOp, SymbolTableCollection &symbolTables)
Return the FuncOp called by callOp.
static mlir::Attribute getDefaultMemorySpace(const BufferizationOptions &options, TensorLikeType type)
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.
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)...
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)
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.
static bool supportsUnstructuredControlFlow()
bool hasTensorSemantics(Operation *op) const
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