24 for (
Block &
b : funcOp.getBody())
25 if (
auto returnOp = dyn_cast<func::ReturnOp>(
b.getTerminator()))
26 result.push_back(returnOp);
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 (isa<TensorType>(type)) {
58 return *
options.defaultMemorySpaceFn(type);
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");
86 return cast<BufferLikeType>(MemRefType::get(
87 rankedMemrefType.getShape(), rankedMemrefType.getElementType(),
88 layoutAttr, rankedMemrefType.getMemorySpace()));
91 return options.functionArgTypeConverterFn(type,
nullptr, funcOp,
98 return dyn_cast_or_null<FuncOp>(callOp.resolveCallableInTable(&symbolTables));
104 if (isa<OneShotAnalysisState>(state)) {
105 auto &oneShotAnalysisState =
107 if (
auto *funcAnalysisState =
119static const FuncAnalysisState &
121 assert(isa<OneShotAnalysisState>(state) &&
"expected OneShotAnalysisState");
123 .getExtension<FuncAnalysisState>();
124 assert(
result &&
"FuncAnalysisState does not exist");
131 if (!isa<OneShotAnalysisState>(state))
134 .getExtension<FuncAnalysisState>();
137 const auto &analyzedFuncOps = funcState->analyzedFuncOps;
138 auto it = analyzedFuncOps.find(funcOp);
139 if (it == analyzedFuncOps.end())
146static std::optional<int64_t>
154 auto retValIt = funcOpIt->getSecond().find(returnValIdx);
155 if (retValIt == funcOpIt->getSecond().end())
159 return retValIt->getSecond();
163 :
public BufferizableOpInterface::ExternalModel<CallOpInterface,
167 func::CallOp callOp = cast<func::CallOp>(op);
169 assert(funcOp &&
"expected CallOp to a FuncOp");
176 return funcState.
readBbArgs.lookup(funcOp).contains(
182 func::CallOp callOp = cast<func::CallOp>(op);
184 assert(funcOp &&
"expected CallOp to a FuncOp");
197 func::CallOp callOp = cast<func::CallOp>(op);
199 assert(funcOp &&
"expected CallOp to a FuncOp");
202 return detail::unknownGetAliasingValues(opOperand);
206 auto aliasingReturnVals =
211 std::optional<int64_t> equivalent = {};
212 if (aliasingReturnVals.size() == 1) {
214 aliasingReturnVals.front());
215 assert((!equivalent.has_value() ||
217 "inconsistent analysis state");
220 for (
int64_t resultIdx : aliasingReturnVals)
221 result.addAlias({callOp->getOpResult(resultIdx),
222 equivalent.has_value() ? BufferRelation::Equivalent
223 : BufferRelation::Unknown,
224 equivalent.has_value()});
228 FailureOr<BufferLikeType>
230 const BufferizationState &state,
232 auto callOp = cast<func::CallOp>(op);
236 assert(funcOp &&
"expected CallOp to a FuncOp");
240 FunctionType funcType = funcOp.getFunctionType();
242 funcType.getResult(cast<OpResult>(value).getResultNumber());
243 if (
auto bufferizedType = dyn_cast<BufferLikeType>(resultType))
244 return bufferizedType;
247 auto tensorType = cast<TensorLikeType>(resultType);
248 return cast<BufferLikeType>(
options.functionArgTypeConverterFn(
257 BufferizationState &state)
const {
258 func::CallOp callOp = cast<func::CallOp>(op);
264 if (!isa<TensorLikeType>(returnType)) {
266 resultTypes.push_back(returnType);
271 FailureOr<BufferLikeType> resultType =
273 if (failed(resultType))
275 resultTypes.push_back(*resultType);
283 assert(funcOp &&
"expected CallOp to a FuncOp");
284 FunctionType funcType = funcOp.getFunctionType();
286 for (
OpOperand &opOperand : callOp->getOpOperands()) {
288 if (!isa<TensorLikeType>(opOperand.get().getType())) {
289 newOperands.push_back(opOperand.get());
294 FailureOr<Value> maybeBuffer =
295 getBuffer(rewriter, opOperand.get(),
options, state);
296 if (failed(maybeBuffer))
298 Value buffer = *maybeBuffer;
301 auto bufferType = funcType.getInput(opOperand.getOperandNumber());
302 if (!isa<BufferLikeType>(bufferType)) {
306 FailureOr<BufferLikeType> maybeBufferType =
307 bufferization::getBufferType(
308 funcOp.getArgument(opOperand.getOperandNumber()),
options,
310 if (failed(maybeBufferType))
312 bufferType = *maybeBufferType;
321 if (buffer.
getType() != bufferType) {
322 auto memrefDstType = dyn_cast<MemRefType>(bufferType);
323 assert(memrefDstType &&
324 "buffer layout not supported on unranked tensors");
332 newOperands.push_back(buffer);
336 func::CallOp newCallOp =
337 func::CallOp::create(rewriter, callOp.getLoc(), resultTypes,
338 newOperands, callOp.getProperties(),
339 callOp->getDiscardableAttrDictionary().getValue());
342 replaceOpWithBufferizedValues(rewriter, callOp, newCallOp->getResults());
349 :
public BufferizableOpInterface::ExternalModel<ReturnOpInterface,
368 BufferizationState &state)
const {
370 auto returnOp = cast<func::ReturnOp>(op);
371 assert(isa<FuncOp>(returnOp->getParentOp()) &&
372 "only support FuncOp parent for ReturnOp");
382 FuncOpInterface, FuncOp> {
387 auto isaTensor = llvm::IsaPred<TensorLikeType>;
390 auto funcOp = cast<FuncOp>(op);
391 bool hasTensorArg = any_of(funcOp.getArgumentTypes(),
isaTensor);
392 bool hasTensorResult = any_of(funcOp.getResultTypes(),
isaTensor);
393 if (hasTensorArg || hasTensorResult)
401 for (
Block &block : funcOp.getBody())
402 if (any_of(block.getArgumentTypes(),
isaTensor))
408 AliasingOpOperandList
414 FailureOr<BufferLikeType>
416 const BufferizationState &state,
418 auto funcOp = cast<FuncOp>(op);
419 auto bbArg = cast<BlockArgument>(value);
422 if (bbArg.getOwner() == &funcOp.getBody().front())
439 BufferizationState &state)
const {
440 auto funcOp = cast<FuncOp>(op);
441 FunctionType funcType = funcOp.getFunctionType();
445 for (
const auto &it : llvm::enumerate(funcType.getInputs())) {
446 Type argType = it.value();
447 if (isa<TensorLikeType>(argType)) {
452 argTypes.push_back(argType);
457 for (
Type resultType : funcType.getResults()) {
458 if (
auto tensorType = dyn_cast<TensorLikeType>(resultType)) {
459 BufferLikeType resultType =
options.functionArgTypeConverterFn(
462 retTypes.push_back(resultType);
465 retTypes.push_back(resultType);
469 auto newFuncType = FunctionType::get(op->
getContext(), argTypes, retTypes);
472 if (funcOp.isExternal()) {
473 funcOp.setType(newFuncType);
478 for (
Block &block : funcOp.getBody())
485 assert(returnOp->getNumOperands() == retTypes.size() &&
486 "incorrect number of return values");
488 for (
auto [returnVal, bufferizedType] :
489 llvm::zip_equal(returnOp->getOperands(), retTypes)) {
490 auto tensorType = dyn_cast<TensorLikeType>(returnVal.getType());
495 returnValues.push_back(returnVal);
501 Value toBufferOp = bufferization::ToBufferOp::create(
502 rewriter, returnOp.getLoc(), bufferizedType, returnVal);
503 returnValues.push_back(toBufferOp);
506 returnOp.getOperandsMutable().assign(returnValues);
510 funcOp.setType(newFuncType);
517 auto funcOp = cast<FuncOp>(op);
519 assert(bbArg &&
"expected BlockArgument");
529 bbArg.
getArgNumber(), BufferizationDialect::kWritableAttrName))
530 return writable.getValue();
544 func::CallOp::attachInterface<func_ext::CallOpInterface>(*ctx);
545 func::FuncOp::attachInterface<func_ext::FuncOpInterface>(*ctx);
546 func::ReturnOp::attachInterface<func_ext::ReturnOpInterface>(*ctx);
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static bool isaTensor(Type t)
static llvm::ManagedStatic< PassManagerOptions > options
Base class for generic analysis states.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
unsigned getArgNumber() const
Returns the number of this argument.
Block * getOwner() const
Returns the block that owns 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() const
Return which operand this is in the OpOperand list of the Operation.
Operation is the basic unit of execution within MLIR.
MLIRContext * getContext()
Return the context this operation is associated with.
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.
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.
State for analysis-enabled bufferization.
static BufferLikeType getBufferizedFunctionArgType(FuncOp funcOp, int64_t index, const BufferizationOptions &options)
Return the index-th bufferized function argument type.
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 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...
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.
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)...
Include the generated interface declarations.
A template that provides a default implementation of getAliasingOpOperands for ops that support unstr...
AliasingOpOperandList getAliasingBranchOpOperands(Operation *op, BlockArgument bbArg, const AnalysisState &state) const
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< int64_t, SmallVector< int64_t > > IndexToIndexListMapping
A mapping of indices to a list of indices.
DenseMap< FuncOp, IndexToIndexListMapping > aliasingReturnVals
A mapping of FuncOp BBArg indices to aliasing ReturnOp OpOperand 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.
FailureOr< BufferLikeType > getBufferType(Operation *op, Value value, const BufferizationOptions &options, const BufferizationState &state, SmallVector< Value > &invocationStack) const
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
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