21 #include "llvm/ADT/ScopeExit.h"
22 #include "llvm/Support/Debug.h"
29 namespace bufferization {
31 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.cpp.inc"
38 #define DEBUG_TYPE "bufferizable-op-interface"
39 #define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
40 #define LDBG(X) LLVM_DEBUG(DBGS() << (X))
43 using namespace bufferization;
48 if (
auto bufferizableOp =
options.dynCastBufferizableOp(op))
58 if (
auto iter = enclosingRepetitiveRegionCache.find_as(op);
59 iter != enclosingRepetitiveRegionCache.end())
61 return enclosingRepetitiveRegionCache[op] =
67 if (
auto iter = enclosingRepetitiveRegionCache.find_as(value);
68 iter != enclosingRepetitiveRegionCache.end())
76 visitedRegions.push_back(region);
81 enclosingRepetitiveRegionCache[value] = region;
82 for (
Region *r : visitedRegions)
83 enclosingRepetitiveRegionCache[r] = region;
89 if (
auto iter = enclosingRepetitiveRegionCache.find_as(block);
90 iter != enclosingRepetitiveRegionCache.end())
104 enclosingRepetitiveRegionCache[block] = region;
105 for (
Region *r : visitedRegions)
106 enclosingRepetitiveRegionCache[r] = region;
112 auto key = std::make_pair(op0, op1);
113 if (
auto iter = insideMutuallyExclusiveRegionsCache.find(key);
114 iter != insideMutuallyExclusiveRegionsCache.end())
118 insideMutuallyExclusiveRegionsCache[key] = result;
119 insideMutuallyExclusiveRegionsCache[std::make_pair(op1, op0)] = result;
124 enclosingRepetitiveRegionCache.clear();
125 insideMutuallyExclusiveRegionsCache.clear();
146 if (bufferizableOp &&
149 "expected that all parallel regions are also repetitive regions");
158 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
159 return opResult.getDefiningOp();
160 return llvm::cast<BlockArgument>(value).getOwner()->
getParentOp();
171 if (llvm::isa<RankedTensorType>(shapedValue.
getType())) {
172 tensor = shapedValue;
173 }
else if (llvm::isa<MemRefType>(shapedValue.
getType())) {
174 tensor = b.
create<ToTensorOp>(
177 }
else if (llvm::isa<UnrankedTensorType>(shapedValue.
getType()) ||
178 llvm::isa<UnrankedMemRefType>(shapedValue.
getType())) {
180 ->
emitError(
"copying of unranked tensors is not implemented");
182 llvm_unreachable(
"expected RankedTensorType or MemRefType");
184 RankedTensorType tensorType = llvm::cast<RankedTensorType>(tensor.
getType());
189 bool reifiedShapes =
false;
190 if (llvm::isa<RankedTensorType>(shapedValue.
getType()) &&
191 llvm::isa<OpResult>(shapedValue)) {
195 reifiedShapes =
true;
197 resultDims[llvm::cast<OpResult>(shapedValue).getResultNumber()];
198 for (
const auto &dim :
enumerate(tensorType.getShape()))
199 if (ShapedType::isDynamic(dim.value()))
200 dynamicSizes.push_back(cast<Value>(shape[dim.index()]));
210 auto allocTensorOp = b.
create<AllocTensorOp>(loc, tensorType, dynamicSizes,
216 auto copyBufferType =
218 if (failed(copyBufferType))
220 std::optional<Attribute> memorySpace = copyBufferType->getMemorySpace();
222 memorySpace =
options.defaultMemorySpaceFn(tensorType);
223 if (memorySpace.has_value())
224 allocTensorOp.setMemorySpaceAttr(memorySpace.value());
225 return allocTensorOp.getResult();
228 LogicalResult BufferizableOpInterface::resolveTensorOpOperandConflicts(
240 Type operandType = opOperand.get().getType();
241 if (!llvm::isa<TensorType>(operandType))
243 if (analysisState.isInPlace(opOperand))
245 if (llvm::isa<UnrankedTensorType>(operandType))
246 return op->
emitError(
"copying of unranked tensors is not implemented");
249 analysisState.getAliasingValues(opOperand);
251 isa<OpResult>(aliasingValues.
getAliases()[0].value) &&
252 !analysisState.bufferizesToMemoryWrite(opOperand) &&
254 .getAliasingOpOperands(aliasingValues.
getAliases()[0].value)
255 .getNumAliases() == 1 &&
256 !isa<UnrankedTensorType>(
257 aliasingValues.
getAliases()[0].value.getType())) {
265 outOfPlaceValues.push_back(value);
266 if (!analysisState.canOmitTensorCopy(opOperand))
267 copiedOpValues.insert(value);
270 outOfPlaceOpOperands.push_back(&opOperand);
271 if (!analysisState.canOmitTensorCopy(opOperand))
272 copiedOpOperands.insert(&opOperand);
278 for (
OpOperand *opOperand : outOfPlaceOpOperands) {
280 rewriter, op->
getLoc(), opOperand->get(), analysisState.getOptions(),
281 bufferizationState, copiedOpOperands.contains(opOperand));
289 for (
Value value : outOfPlaceValues) {
291 rewriter, op->
getLoc(), value, analysisState.getOptions(),
292 bufferizationState, copiedOpValues.count(value));
299 if (use->getOwner() ==
copy->getDefiningOp())
303 if (isa<tensor::DimOp>(use->getOwner()))
318 bool isAllowed = !hasAllowRule();
319 for (
const Entry &entry : entries) {
320 bool filterResult = entry.fn(op);
321 switch (entry.type) {
323 isAllowed |= filterResult;
359 : functionArgTypeConverterFn(defaultFunctionArgTypeConverter),
360 unknownTypeConverterFn(defaultUnknownTypeConverter) {}
365 bool isFuncBoundaryOp = isa_and_nonnull<func::FuncDialect>(op->
getDialect());
372 BufferizableOpInterface
376 auto bufferizableOp = dyn_cast<BufferizableOpInterface>(op);
379 return bufferizableOp;
382 BufferizableOpInterface
388 LayoutMapOption layoutMapOption) {
392 if (layoutMapOption == LayoutMapOption::IdentityLayoutMap)
399 layoutMapOption == LayoutMapOption::InferLayoutMap;
407 if (
auto bbArg = llvm::dyn_cast<BlockArgument>(value)) {
418 if (
auto bufferizableOp =
getOptions().dynCastBufferizableOp(op))
419 return bufferizableOp.getAliasingOpOperands(value, *
this);
428 if (
auto bufferizableOp =
430 return bufferizableOp.getAliasingValues(opOperand, *
this);
439 if (
auto bufferizableOp =
441 return bufferizableOp.bufferizesToMemoryRead(opOperand, *
this);
451 if (
auto bufferizableOp =
453 return bufferizableOp.bufferizesToMemoryWrite(opOperand, *
this);
463 if (
auto bufferizableOp =
465 return bufferizableOp.bufferizesToAliasOnly(opOperand, *
this);
473 auto opResult = llvm::dyn_cast<OpResult>(value);
479 return bufferizableOp.resultBufferizesToMemoryWrite(opResult, *
this);
486 assert(llvm::isa<TensorType>(value.
getType()) &&
"expected TensorType");
490 workingSet.push_back(&use);
492 while (!workingSet.empty()) {
493 OpOperand *uMaybeReading = workingSet.pop_back_val();
494 if (!visited.insert(uMaybeReading).second)
500 for (
OpOperand &use : alias.value.getUses())
501 workingSet.push_back(&use);
520 workingSet.insert(opOperand->
get());
522 if (visitedOpOperands)
523 visitedOpOperands->insert(opOperand);
525 while (!workingSet.empty()) {
526 Value value = workingSet.pop_back_val();
528 if (!
config.revisitAlreadyVisitedValues && visited.contains(value)) {
530 if (
config.alwaysIncludeLeaves)
531 result.insert(value);
534 visited.insert(value);
536 if (condition(value)) {
537 result.insert(value);
544 if (
config.alwaysIncludeLeaves)
545 result.insert(value);
553 if (
config.alwaysIncludeLeaves)
554 result.insert(value);
559 if (
config.followEquivalentOnly &&
563 if (
config.alwaysIncludeLeaves)
564 result.insert(value);
571 if (
config.alwaysIncludeLeaves)
572 result.insert(value);
576 if (
config.followSameTypeOrCastsOnly &&
577 a.opOperand->get().getType() != value.
getType() &&
581 if (
config.alwaysIncludeLeaves)
582 result.insert(value);
586 workingSet.insert(a.opOperand->get());
587 if (visitedOpOperands)
588 visitedOpOperands->insert(a.opOperand);
599 config.alwaysIncludeLeaves =
false;
628 llvm::none_of(aliases,
638 if (isa<ToBufferOp>(opOperand.
getOwner()))
666 auto rankedTensorType = llvm::dyn_cast<RankedTensorType>(tensor.
getType());
667 assert((!rankedTensorType || llvm::cast<MemRefType>(memrefType).getRank() ==
668 rankedTensorType.getRank()) &&
669 "to_buffer would be invalid: mismatching ranks");
677 auto tensorType = llvm::dyn_cast<TensorLikeType>(value.
getType());
678 assert(tensorType &&
"unexpected non-tensor type");
682 if (
auto toTensorOp = value.
getDefiningOp<bufferization::ToTensorOp>())
683 return toTensorOp.getBuffer();
689 if (failed(bufferType))
693 .
create<bufferization::ToBufferOp>(value.
getLoc(), *bufferType, value)
698 FailureOr<BufferLikeType>
706 FailureOr<BufferLikeType>
710 assert(llvm::isa<TensorLikeType>(value.
getType()) &&
711 "unexpected non-tensor type");
712 invocationStack.push_back(value);
714 llvm::make_scope_exit([&]() { invocationStack.pop_back(); });
718 auto bufferizableOp =
options.dynCastBufferizableOp(op);
720 return bufferizableOp.getBufferType(value,
options, state, invocationStack);
723 return cast<TensorLikeType>(value.
getType()).getBufferType(
options, [&]() {
724 return op->emitError();
729 if (
auto bufferizableOp = dyn_cast<BufferizableOpInterface>(op))
730 return bufferizableOp.hasTensorSemantics();
738 "expected one value per OpResult");
744 Value replacement = values[opResult.getResultNumber()];
745 if (llvm::isa<TensorLikeType>(opResult.getType())) {
748 assert(llvm::isa<BufferLikeType>(replacement.
getType()) &&
749 "tensor op result should be replaced with a buffer value");
754 replacement = rewriter.
create<bufferization::ToTensorOp>(
755 replacement.
getLoc(), opResult.getType(), replacement);
757 replacements.push_back(replacement);
777 .
create<memref::AllocOp>(loc, type, dynShape,
780 return b.
create<memref::AllocOp>(loc, type, dynShape).getResult();
787 return (*
memCpyFn)(b, loc, from, to);
789 b.
create<memref::CopyOp>(loc, from, to);
799 MemRefLayoutAttrInterface layout,
802 if (
auto unrankedTensorType =
803 llvm::dyn_cast<UnrankedTensorType>(tensorType)) {
804 assert(!layout &&
"UnrankedTensorType cannot have a layout map");
810 auto rankedTensorType = llvm::cast<RankedTensorType>(tensorType);
813 rankedTensorType.getElementType(), layout,
817 return options.unknownTypeConverterFn(tensorType, memorySpace,
options);
824 if (
auto unrankedTensorType =
825 llvm::dyn_cast<UnrankedTensorType>(tensorType)) {
831 auto rankedTensorType = llvm::cast<RankedTensorType>(tensorType);
832 int64_t dynamicOffset = ShapedType::kDynamic;
834 ShapedType::kDynamic);
836 dynamicOffset, dynamicStrides);
838 rankedTensorType.getElementType(), stridedLayout,
848 if (
auto unrankedTensorType =
849 llvm::dyn_cast<UnrankedTensorType>(tensorType)) {
855 auto rankedTensorType = llvm::cast<RankedTensorType>(tensorType);
856 MemRefLayoutAttrInterface layout = {};
858 rankedTensorType.getElementType(), layout,
868 auto bufferizableOp = cast<BufferizableOpInterface>(opResult.
getDefiningOp());
870 bufferizableOp.getAliasingOpOperands(opResult, state);
880 return state.bufferizesToMemoryWrite(*alias.
opOperand);
913 auto isMemoryWriteInsideOp = [&](
Value v) {
917 return state.bufferizesToMemoryWrite(v);
920 config.alwaysIncludeLeaves =
false;
923 .findValueInReverseUseDefChain(alias.
opOperand,
924 isMemoryWriteInsideOp,
config)
938 if (!llvm::isa<TensorType>(opOperand.
get().
getType()))
941 for (
const auto &it : aliasingValues)
942 if (it.value == value)
943 result.emplace_back(&opOperand, it.relation, it.isDefinite);
952 assert(llvm::isa<TensorType>(value.
getType()) &&
"expected tensor type");
953 auto tensorType = cast<TensorType>(value.
getType());
956 if (llvm::isa<BlockArgument>(value))
961 auto opResult = llvm::cast<OpResult>(value);
968 Value equivalentOperand = aliases.
getAliases().front().opOperand->get();
970 bufferizationState, invocationStack));
977 if (!memSpace.has_value())
978 return op->
emitError(
"could not infer memory space");
984 BufferizableOpInterface bufferizableOp,
unsigned index) {
985 assert(index < bufferizableOp->getNumRegions() &&
"invalid region index");
986 auto regionInterface =
987 dyn_cast<RegionBranchOpInterface>(bufferizableOp.getOperation());
988 if (!regionInterface)
990 return regionInterface.isRepetitiveRegion(index);
997 if (
auto bbArg = dyn_cast<BlockArgument>(value))
998 if (bbArg.getOwner() != &bbArg.getOwner()->getParent()->getBlocks().front())
1006 if (isa<TensorType>(operand.get().getType()))
1019 if (llvm::isa<TensorType>(result.getType()))
1022 if (!region.getBlocks().empty())
1023 for (
BlockArgument bbArg : region.getBlocks().front().getArguments())
1024 if (isa<TensorType>(bbArg.getType()))
1030 auto isaTensor = [](
Type t) {
return isa<TensorLikeType>(t); };
1032 return any_of(r.getBlocks(), [&](Block &b) {
1033 return any_of(b.getArguments(), [&](BlockArgument bbArg) {
1034 return isaTensor(bbArg.getType());
1038 if (hasTensorBlockArgument)
1046 FailureOr<BaseMemRefType>
1048 if (failed(bufferType))
1050 return cast<BaseMemRefType>(*bufferType);
1056 return mlir::succeeded(
1057 cast<TensorLikeType>(tensor.
getType())
1058 .verifyCompatibleBufferType(cast<BufferLikeType>(buffer.
getType()),
1059 [&]() { return op.emitError(); }));
static void setInsertionPointAfter(OpBuilder &b, Value value)
static bool isRepetitiveRegion(Region *region, const BufferizationOptions &options)
static void ensureToBufferOpIsValid(Value tensor, Type memrefType)
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static bool isaTensor(Type t)
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME)
Base class for generic analysis states.
Attributes are known-constant values of operations.
This class provides a shared interface for ranked and unranked memref types.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
IntegerAttr getI64IntegerAttr(int64_t value)
IRValueT get() const
Return the current value being used by this operand.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
operand_type_range getOperandTypes()
MutableArrayRef< OpOperand > getOpOperands()
result_type_range getResultTypes()
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
result_range getOpResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Operation * getParentOp()
Return the parent operation this region is attached to.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
This class represents a collection of SymbolTables.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
This class provides an efficient unique identifier for a specific C++ type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
This class provides an abstraction over the different types of ranges over Values.
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.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
size_t getNumAliases() const
ArrayRef< T > getAliases() const
AnalysisState provides a variety of helper functions for dealing with tensor values.
bool isValueRead(Value value) const
Return true if the given value is read by an op that bufferizes to a memory read.
AliasingValueList getAliasingValues(OpOperand &opOperand) const
Determine which Value will alias with opOperand if the op is bufferized in place.
SetVector< Value > findValueInReverseUseDefChain(OpOperand *opOperand, llvm::function_ref< bool(Value)> condition, TraversalConfig config=TraversalConfig(), llvm::DenseSet< OpOperand * > *visitedOpOperands=nullptr) const
Starting from opOperand, follow the use-def chain in reverse, always selecting the aliasing OpOperand...
virtual bool areAliasingBufferizedValues(Value v1, Value v2) const
Return true if v1 and v2 may bufferize to aliasing buffers.
virtual bool hasUndefinedContents(OpOperand *opOperand) const
Return true if the given tensor has undefined contents.
bool insideMutuallyExclusiveRegions(Operation *op0, Operation *op1)
Checks whether op0 and op1 are inside mutually exclusive regions.
bool canOmitTensorCopy(OpOperand &opOperand) const
Return true if a copy can always be avoided when allocating a new tensor for the given OpOperand.
bool bufferizesToMemoryWrite(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory write.
virtual bool isInPlace(OpOperand &opOperand) const
Return true if the given OpResult has been decided to bufferize inplace.
SetVector< Value > findDefinitions(OpOperand *opOperand) const
Find the values that may define the contents of the given value at runtime.
bool bufferizesToAliasOnly(OpOperand &opOperand) const
Return true if opOperand does neither read nor write but bufferizes to an alias.
AliasingOpOperandList getAliasingOpOperands(Value value) const
Determine which OpOperand* will alias with value if the op is bufferized in place.
AnalysisState(const BufferizationOptions &options)
Region * getEnclosingRepetitiveRegion(Operation *op, const BufferizationOptions &options)
Return the closest enclosing repetitive region around the given op.
const BufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
bool bufferizesToMemoryRead(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory read.
virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const
Return true if v1 and v2 bufferize to equivalent buffers.
virtual void resetCache()
BufferizationState provides information about the state of the IR during the bufferization process.
SymbolTableCollection & getSymbolTables()
Get a reference to the collection of cached symbol tables.
bool isOpAllowed(Operation *op) const
Return whether the op is allowed or not.
Operation * getOwner() const
Return the owner of this operand.
FailureOr< BaseMemRefType > defaultGetBufferType(Value value, const BufferizationOptions &options, const BufferizationState &state, SmallVector< Value > &invocationStack)
This is the default implementation of BufferizableOpInterface::getBufferType.
AliasingOpOperandList defaultGetAliasingOpOperands(Value value, const AnalysisState &state)
This is the default implementation of BufferizableOpInterface::getAliasingOpOperands.
bool defaultResultBufferizesToMemoryWrite(OpResult opResult, const AnalysisState &state)
This is the default implementation of BufferizableOpInterface::resultBufferizesToMemoryWrite.
AliasingValueList unknownGetAliasingValues(OpOperand &opOperand)
This is the default implementation of getAliasingValues in case the owner op does not implement the B...
bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp, unsigned index)
This is the default implementation of BufferizableOpInterface::isRepetitiveRegion.
FailureOr< BaseMemRefType > asMemRefType(FailureOr< BufferLikeType > bufferType)
This is a helper function used when buffer type is guaranteed to be memref.
AliasingOpOperandList unknownGetAliasingOpOperands(Value value)
This is the default implementation of getAliasingOpOperands in case the defining op does not implemen...
bool defaultHasTensorSemantics(Operation *op)
This is the default implementation of BufferizableOpInterface::hasTensorSemantics.
bool typesMatchAfterBufferization(Operation &op, Value tensor, Value buffer)
This function is a free-standing helper that relies on bufferization::TensorLikeTypeInterface to veri...
BaseMemRefType getMemRefType(TensorType tensorType, const BufferizationOptions &options, MemRefLayoutAttrInterface layout={}, Attribute memorySpace=nullptr)
Return a MemRefType to which the TensorType can be bufferized.
void replaceOpWithBufferizedValues(RewriterBase &rewriter, Operation *op, ValueRange values)
Replace an op with replacement values.
BaseMemRefType getMemRefTypeWithStaticIdentityLayout(TensorType tensorType, Attribute memorySpace=nullptr)
Return a MemRef type with a static identity layout (i.e., no layout map).
Operation * getOwnerOfValue(Value value)
Return the owner of the given value.
Region * getParallelRegion(Region *region, const BufferizationOptions &options)
If region is a parallel region, return region.
FailureOr< Value > getBuffer(RewriterBase &rewriter, Value value, const BufferizationOptions &options, const BufferizationState &state)
Lookup the buffer for the given value.
Region * getNextEnclosingRepetitiveRegion(Region *region, const BufferizationOptions &options)
Assuming that the given region is repetitive, find the next enclosing repetitive region.
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.
AliasList< AliasingOpOperand > AliasingOpOperandList
A list of possible aliasing OpOperands.
FailureOr< Value > allocateTensorForShapedValue(OpBuilder &b, Location loc, Value shapedValue, const BufferizationOptions &options, const BufferizationState &state, bool copy=true)
Create an AllocTensorOp for the given shaped value (memref or tensor).
BaseMemRefType getMemRefTypeWithFullyDynamicLayout(TensorType tensorType, Attribute memorySpace=nullptr)
Return a MemRef type with fully dynamic layout.
void populateDynamicDimSizes(OpBuilder &b, Location loc, Value shapedValue, SmallVector< Value > &dynamicDims)
Populate dynamicDims with tensor::DimOp / memref::DimOp results for all dynamic dimensions of the giv...
bool hasTensorSemantics(Operation *op)
Return "true" if the given op has tensor semantics and should be bufferized.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Type getTensorTypeFromMemRefType(Type type)
Return an unranked/ranked tensor type for the given unranked/ranked memref type.
Include the generated interface declarations.
LogicalResult reifyResultShapes(OpBuilder &b, Operation *op, ReifiedRankedShapedTypeDims &reifiedReturnShapes)
Reify the shape of the result of an operation (typically in terms of the shape of its operands).
const FrozenRewritePatternSet GreedyRewriteConfig config
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
A maybe aliasing OpOperand.
Options for BufferizableOpInterface-based bufferization.
std::function< void(AnalysisState &)> AnalysisStateInitFn
Initializer function for analysis state.
void setFunctionBoundaryTypeConversion(LayoutMapOption layoutMapOption)
This function controls buffer types on function signatures.
BufferizableOpInterface dynCastBufferizableOp(Operation *op) const
Try to cast the given op to BufferizableOpInterface if the op is allow listed.
bool inferFunctionResultLayout
If true, function result types are inferred from the body of the function.
unsigned int bufferAlignment
Buffer alignment for new memory allocations.
FunctionArgTypeConverterFn functionArgTypeConverterFn
Type converter from tensors to memrefs.
std::optional< AllocationFn > allocationFn
Helper functions for allocation and memory copying.
OpFilter opFilter
A filter that specifies which ops should be bufferized and which ops should be ignored.
bool isOpAllowed(Operation *op) const
Return true if the given op should be bufferized.
std::optional< MemCpyFn > memCpyFn
bool bufferizeFunctionBoundaries
Specifies whether function boundaries (ops in the func dialect) should be bufferized or not.
FailureOr< Value > createAlloc(OpBuilder &b, Location loc, MemRefType type, ValueRange dynShape) const
Create a memref allocation with the given type and dynamic extents.
LogicalResult createMemCpy(OpBuilder &b, Location loc, Value from, Value to) const
Creates a memcpy between two given buffers.
SmallVector< AnalysisStateInitFn > stateInitializers
Initializer functions for analysis state.
Traversal parameters for findValueInReverseUseDefChain.