20#include "llvm/ADT/ScopeExit.h"
21#include "llvm/ADT/SmallVectorExtras.h"
30#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.cpp.inc"
37#define DEBUG_TYPE "bufferizable-op-interface"
45 if (
auto bufferizableOp =
options.dynCastBufferizableOp(op))
51Region *AnalysisState::getEnclosingRepetitiveRegion(
55 if (
auto iter = enclosingRepetitiveRegionCache.find_as(op);
56 iter != enclosingRepetitiveRegionCache.end())
58 return enclosingRepetitiveRegionCache[op] =
62Region *AnalysisState::getEnclosingRepetitiveRegion(
64 if (
auto iter = enclosingRepetitiveRegionCache.find_as(value);
65 iter != enclosingRepetitiveRegionCache.end())
71 SmallVector<Region *> visitedRegions;
73 visitedRegions.push_back(region);
78 enclosingRepetitiveRegionCache[value] = region;
79 for (Region *r : visitedRegions)
80 enclosingRepetitiveRegionCache[r] = region;
84Region *AnalysisState::getEnclosingRepetitiveRegion(
86 if (
auto iter = enclosingRepetitiveRegionCache.find_as(block);
87 iter != enclosingRepetitiveRegionCache.end())
91 Operation *op =
nullptr;
94 SmallVector<Region *> visitedRegions;
101 enclosingRepetitiveRegionCache[block] = region;
102 for (Region *r : visitedRegions)
103 enclosingRepetitiveRegionCache[r] = region;
107bool AnalysisState::insideMutuallyExclusiveRegions(
Operation *op0,
109 auto key = std::make_pair(op0, op1);
110 if (
auto iter = insideMutuallyExclusiveRegionsCache.find(key);
111 iter != insideMutuallyExclusiveRegionsCache.end())
115 insideMutuallyExclusiveRegionsCache[key] =
result;
116 insideMutuallyExclusiveRegionsCache[std::make_pair(op1, op0)] =
result;
120void AnalysisState::resetCache() {
121 enclosingRepetitiveRegionCache.clear();
122 insideMutuallyExclusiveRegionsCache.clear();
133Region *bufferization::getNextEnclosingRepetitiveRegion(
144 const BufferizationOptions &
options) {
147 if (bufferizableOp &&
150 "expected that all parallel regions are also repetitive regions");
159 if (
auto opResult = llvm::dyn_cast<OpResult>(value))
160 return opResult.getDefiningOp();
161 return llvm::cast<BlockArgument>(value).getOwner()->
getParentOp();
169FailureOr<Value> bufferization::allocateTensorForShapedValue(
171 const BufferizationOptions &
options,
const BufferizationState &state,
174 if (llvm::isa<RankedTensorType>(shapedValue.
getType())) {
176 }
else if (llvm::isa<MemRefType>(shapedValue.
getType())) {
177 tensor = ToTensorOp::create(
180 }
else if (llvm::isa<UnrankedTensorType>(shapedValue.
getType()) ||
181 llvm::isa<UnrankedMemRefType>(shapedValue.
getType())) {
183 ->
emitError(
"copying of unranked tensors is not implemented");
185 llvm_unreachable(
"expected RankedTensorType or MemRefType");
187 RankedTensorType tensorType = llvm::cast<RankedTensorType>(
tensor.getType());
192 bool reifiedShapes =
false;
193 if (llvm::isa<RankedTensorType>(shapedValue.
getType()) &&
194 llvm::isa<OpResult>(shapedValue)) {
198 reifiedShapes =
true;
200 resultDims[llvm::cast<OpResult>(shapedValue).getResultNumber()];
201 for (
const auto &dim :
enumerate(tensorType.getShape())) {
202 if (ShapedType::isDynamic(dim.value())) {
203 dynamicSizes.push_back(
216 auto allocTensorOp = AllocTensorOp::create(
b, loc, tensorType, dynamicSizes,
221 return allocTensorOp.getResult();
222 auto copyBufferType =
224 if (
failed(copyBufferType))
226 std::optional<Attribute> memorySpace = copyBufferType->getMemorySpace();
229 options.defaultMemorySpaceFn(cast<TensorLikeType>(tensorType));
230 if (memorySpace.has_value())
231 allocTensorOp.setMemorySpaceAttr(memorySpace.value());
232 return allocTensorOp.getResult();
237LogicalResult BufferizableOpInterface::resolveTensorOpOperandConflicts(
239 const BufferizationState &bufferizationState) {
249 Type operandType = opOperand.get().getType();
250 if (!llvm::isa<TensorType>(operandType))
252 if (analysisState.isInPlace(opOperand))
254 if (llvm::isa<UnrankedTensorType>(operandType))
255 return op->
emitError(
"copying of unranked tensors is not implemented");
257 AliasingValueList aliasingValues =
258 analysisState.getAliasingValues(opOperand);
259 if (aliasingValues.getNumAliases() == 1 &&
260 isa<OpResult>(aliasingValues.getAliases()[0].value) &&
261 !analysisState.bufferizesToMemoryWrite(opOperand) &&
263 .getAliasingOpOperands(aliasingValues.getAliases()[0].value)
264 .getNumAliases() == 1 &&
265 !isa<UnrankedTensorType>(
266 aliasingValues.getAliases()[0].value.getType())) {
273 Value value = aliasingValues.getAliases()[0].value;
274 outOfPlaceValues.push_back(value);
275 if (!analysisState.canOmitTensorCopy(opOperand))
276 copiedOpValues.insert(value);
279 outOfPlaceOpOperands.push_back(&opOperand);
280 if (!analysisState.canOmitTensorCopy(opOperand))
281 copiedOpOperands.insert(&opOperand);
287 for (
OpOperand *opOperand : outOfPlaceOpOperands) {
288 FailureOr<Value>
copy = allocateTensorForShapedValue(
289 rewriter, op->
getLoc(), opOperand->get(), analysisState.getOptions(),
290 bufferizationState, copiedOpOperands.contains(opOperand));
298 for (
Value value : outOfPlaceValues) {
299 FailureOr<Value>
copy = allocateTensorForShapedValue(
300 rewriter, op->
getLoc(), value, analysisState.getOptions(),
301 bufferizationState, copiedOpValues.count(value));
308 if (use->getOwner() ==
copy->getDefiningOp())
312 if (isa<tensor::DimOp>(use->getOwner()))
325bool OpFilter::isOpAllowed(
Operation *op)
const {
327 bool isAllowed = !hasAllowRule();
328 for (
const Entry &entry : entries) {
329 bool filterResult = entry.fn(op);
330 switch (entry.type) {
332 isAllowed |= filterResult;
352defaultFunctionArgTypeConverter(TensorLikeType type,
Attribute memorySpace,
354 const BufferizationOptions &
options) {
355 if (
auto tensorType = mlir::dyn_cast<TensorType>(type)) {
356 return cast<BufferLikeType>(
357 getMemRefTypeWithFullyDynamicLayout(tensorType, memorySpace));
361 return options.unknownTypeConverterFn(type, memorySpace,
options);
365defaultUnknownTypeConverter(TensorLikeType tensorType,
Attribute memorySpace,
366 const BufferizationOptions &
options) {
367 return cast<BufferLikeType>(getMemRefTypeWithFullyDynamicLayout(
368 cast<TensorType>(tensorType), memorySpace));
374BufferizationOptions::BufferizationOptions()
375 : functionArgTypeConverterFn(defaultFunctionArgTypeConverter),
376 unknownTypeConverterFn(defaultUnknownTypeConverter) {}
378bool BufferizationOptions::isOpAllowed(
Operation *op)
const {
381 bool isFuncBoundaryOp = isa_and_nonnull<func::FuncDialect>(op->
getDialect());
382 if (!bufferizeFunctionBoundaries && isFuncBoundaryOp)
385 return opFilter.isOpAllowed(op);
388BufferizableOpInterface
389BufferizationOptions::dynCastBufferizableOp(
Operation *op)
const {
390 if (!isOpAllowed(op))
392 auto bufferizableOp = dyn_cast<BufferizableOpInterface>(op);
395 return bufferizableOp;
398BufferizableOpInterface
399BufferizationOptions::dynCastBufferizableOp(
Value value)
const {
403void BufferizationOptions::setFunctionBoundaryTypeConversion(
404 LayoutMapOption layoutMapOption) {
405 functionArgTypeConverterFn = [=](TensorLikeType type, Attribute memorySpace,
407 const BufferizationOptions &
options) {
408 if (
auto tensorType = mlir::dyn_cast<TensorType>(type)) {
409 if (layoutMapOption == LayoutMapOption::IdentityLayoutMap)
410 return cast<BufferLikeType>(
411 bufferization::getMemRefTypeWithStaticIdentityLayout(tensorType,
413 return cast<BufferLikeType>(
414 bufferization::getMemRefTypeWithFullyDynamicLayout(tensorType,
419 return options.unknownTypeConverterFn(type, memorySpace,
options);
421 inferFunctionResultLayout =
422 layoutMapOption == LayoutMapOption::InferLayoutMap;
430 if (
auto bbArg = llvm::dyn_cast<BlockArgument>(value)) {
431 b.setInsertionPointToStart(bbArg.getOwner());
439AliasingOpOperandList AnalysisState::getAliasingOpOperands(
Value value)
const {
441 if (
auto bufferizableOp = getOptions().dynCastBufferizableOp(op))
442 return bufferizableOp.getAliasingOpOperands(value, *
this);
445 return detail::unknownGetAliasingOpOperands(value);
450AliasingValueList AnalysisState::getAliasingValues(
OpOperand &opOperand)
const {
451 if (
auto bufferizableOp =
452 getOptions().dynCastBufferizableOp(opOperand.
getOwner()))
453 return bufferizableOp.getAliasingValues(opOperand, *
this);
456 return detail::unknownGetAliasingValues(opOperand);
461bool AnalysisState::bufferizesToMemoryRead(
OpOperand &opOperand)
const {
462 if (
auto bufferizableOp =
463 getOptions().dynCastBufferizableOp(opOperand.
getOwner()))
464 return bufferizableOp.bufferizesToMemoryRead(opOperand, *
this);
473bool AnalysisState::bufferizesToMemoryWrite(
OpOperand &opOperand)
const {
474 if (
auto bufferizableOp =
475 getOptions().dynCastBufferizableOp(opOperand.
getOwner()))
476 return bufferizableOp.bufferizesToMemoryWrite(opOperand, *
this);
485bool AnalysisState::bufferizesToAliasOnly(
OpOperand &opOperand)
const {
486 if (
auto bufferizableOp =
487 getOptions().dynCastBufferizableOp(opOperand.
getOwner()))
488 return bufferizableOp.bufferizesToAliasOnly(opOperand, *
this);
495bool AnalysisState::bufferizesToMemoryWrite(
Value value)
const {
496 auto opResult = llvm::dyn_cast<OpResult>(value);
499 auto bufferizableOp = getOptions().dynCastBufferizableOp(value);
502 return bufferizableOp.resultBufferizesToMemoryWrite(opResult, *
this);
508bool AnalysisState::isValueRead(
Value value)
const {
509 assert(llvm::isa<TensorLikeType>(value.
getType()) &&
510 "expected TensorLikeType");
511 SmallVector<OpOperand *> workingSet;
513 for (OpOperand &use : value.
getUses())
514 workingSet.push_back(&use);
516 while (!workingSet.empty()) {
517 OpOperand *uMaybeReading = workingSet.pop_back_val();
518 if (!visited.insert(uMaybeReading).second)
522 if (bufferizesToAliasOnly(*uMaybeReading))
523 for (AliasingValue alias : getAliasingValues(*uMaybeReading))
524 for (OpOperand &use : alias.value.getUses())
525 workingSet.push_back(&use);
526 if (bufferizesToMemoryRead(*uMaybeReading))
538llvm::SetVector<Value> AnalysisState::findValueInReverseUseDefChain(
540 TraversalConfig config,
541 llvm::DenseSet<OpOperand *> *visitedOpOperands)
const {
542 llvm::DenseSet<Value> visited;
543 llvm::SetVector<Value>
result, workingSet;
544 workingSet.insert(opOperand->
get());
546 if (visitedOpOperands)
547 visitedOpOperands->insert(opOperand);
549 while (!workingSet.empty()) {
550 Value value = workingSet.pop_back_val();
552 if (!config.revisitAlreadyVisitedValues && visited.contains(value)) {
554 if (config.alwaysIncludeLeaves)
558 visited.insert(value);
560 if (condition(value)) {
565 if (!config.followUnknownOps && !
options.dynCastBufferizableOp(value)) {
568 if (config.alwaysIncludeLeaves)
573 AliasingOpOperandList aliases = getAliasingOpOperands(value);
574 if (aliases.getNumAliases() == 0) {
577 if (config.alwaysIncludeLeaves)
582 for (AliasingOpOperand a : aliases) {
583 if (config.followEquivalentOnly &&
584 a.relation != BufferRelation::Equivalent) {
587 if (config.alwaysIncludeLeaves)
592 if (config.followInPlaceOnly && !isInPlace(*a.opOperand)) {
595 if (config.alwaysIncludeLeaves)
600 if (config.followSameTypeOrCastsOnly &&
601 a.opOperand->get().getType() != value.
getType() &&
605 if (config.alwaysIncludeLeaves)
610 workingSet.insert(a.opOperand->get());
611 if (visitedOpOperands)
612 visitedOpOperands->insert(a.opOperand);
620llvm::SetVector<Value>
621AnalysisState::findDefinitions(
OpOperand *opOperand)
const {
622 TraversalConfig config;
623 config.alwaysIncludeLeaves =
false;
624 return findValueInReverseUseDefChain(
625 opOperand, [&](Value v) {
return this->bufferizesToMemoryWrite(v); },
634 for (
const BufferizationOptions::AnalysisStateInitFn &fn :
639bool AnalysisState::canOmitTensorCopy(
OpOperand &opOperand)
const {
641 if (hasUndefinedContents(&opOperand))
646 if (bufferizesToMemoryWrite(opOperand) && !bufferizesToMemoryRead(opOperand))
650 AliasingValueList aliases = getAliasingValues(opOperand);
651 if (!bufferizesToMemoryRead(opOperand) &&
652 llvm::none_of(aliases,
653 [&](AliasingValue a) {
return isValueRead(a.value); }))
660bool AnalysisState::isInPlace(
OpOperand &opOperand)
const {
662 if (isa<ToBufferOp>(opOperand.
getOwner()))
667 return !bufferizesToMemoryWrite(opOperand);
670bool AnalysisState::areEquivalentBufferizedValues(
Value v1,
Value v2)
const {
676bool AnalysisState::areAliasingBufferizedValues(
Value v1,
Value v2)
const {
682bool AnalysisState::hasUndefinedContents(
OpOperand *opOperand)
const {
688 const BufferizationOptions &
options,
689 const BufferizationState &state) {
691 auto tensorType = llvm::dyn_cast<TensorLikeType>(value.
getType());
692 assert(tensorType &&
"unexpected non-tensor type");
696 if (
auto toTensorOp = value.
getDefiningOp<bufferization::ToTensorOp>())
697 return toTensorOp.getBuffer();
706 return bufferization::ToBufferOp::create(rewriter, value.
getLoc(),
712FailureOr<BufferLikeType>
713bufferization::getBufferType(
Value value,
const BufferizationOptions &
options,
714 const BufferizationState &state) {
720FailureOr<BufferLikeType>
721bufferization::getBufferType(
Value value,
const BufferizationOptions &
options,
722 const BufferizationState &state,
724 assert(llvm::isa<TensorLikeType>(value.
getType()) &&
725 "unexpected non-tensor type");
726 invocationStack.push_back(value);
727 llvm::scope_exit popFromStack([&]() { invocationStack.pop_back(); });
731 auto bufferizableOp =
options.dynCastBufferizableOp(op);
733 return bufferizableOp.getBufferType(value,
options, state, invocationStack);
737 options.defaultMemorySpaceFn(cast<TensorLikeType>(value.
getType()));
738 if (!memSpace.has_value())
739 return op->emitError(
"could not infer memory space");
741 return options.unknownTypeConverterFn(cast<TensorLikeType>(value.
getType()),
745bool bufferization::hasTensorSemantics(
Operation *op) {
746 if (
auto bufferizableOp = dyn_cast<BufferizableOpInterface>(op))
747 return bufferizableOp.hasTensorSemantics();
748 return detail::defaultHasTensorSemantics(op);
751void bufferization::replaceOpWithBufferizedValues(
RewriterBase &rewriter,
755 "expected one value per OpResult");
762 if (llvm::isa<TensorLikeType>(opResult.getType())) {
765 assert(llvm::isa<BufferLikeType>(
replacement.getType()) &&
766 "tensor op result should be replaced with a buffer value");
789 return (*allocationFn)(
b, loc, type, dynShape, bufferAlignment);
792 if (bufferAlignment != 0)
793 return memref::AllocOp::create(
b, loc, type, dynShape,
794 b.getI64IntegerAttr(bufferAlignment))
796 return memref::AllocOp::create(
b, loc, type, dynShape).getResult();
803 return (*memCpyFn)(
b, loc, from, to);
805 memref::CopyOp::create(
b, loc, from, to);
814bufferization::getMemRefTypeWithFullyDynamicLayout(
TensorType tensorType,
817 if (
auto unrankedTensorType =
818 llvm::dyn_cast<UnrankedTensorType>(tensorType)) {
819 return UnrankedMemRefType::get(unrankedTensorType.getElementType(),
824 auto rankedTensorType = llvm::cast<RankedTensorType>(tensorType);
825 int64_t dynamicOffset = ShapedType::kDynamic;
827 ShapedType::kDynamic);
828 auto stridedLayout = StridedLayoutAttr::get(tensorType.
getContext(),
829 dynamicOffset, dynamicStrides);
830 return MemRefType::get(rankedTensorType.getShape(),
831 rankedTensorType.getElementType(), stridedLayout,
838bufferization::getMemRefTypeWithStaticIdentityLayout(
TensorType tensorType,
841 if (
auto unrankedTensorType =
842 llvm::dyn_cast<UnrankedTensorType>(tensorType)) {
843 return UnrankedMemRefType::get(unrankedTensorType.getElementType(),
848 auto rankedTensorType = llvm::cast<RankedTensorType>(tensorType);
849 MemRefLayoutAttrInterface layout = {};
850 return MemRefType::get(rankedTensorType.getShape(),
851 rankedTensorType.getElementType(), layout,
859bool bufferization::detail::defaultResultBufferizesToMemoryWrite(
861 auto bufferizableOp = cast<BufferizableOpInterface>(opResult.
getDefiningOp());
862 AliasingOpOperandList opOperands =
863 bufferizableOp.getAliasingOpOperands(opResult, state);
867 if (opOperands.getAliases().empty())
872 if (llvm::any_of(opOperands, [&](AliasingOpOperand alias) {
873 return state.bufferizesToMemoryWrite(*alias.opOperand);
906 auto isMemoryWriteInsideOp = [&](
Value v) {
910 return state.bufferizesToMemoryWrite(v);
912 TraversalConfig config;
913 config.alwaysIncludeLeaves =
false;
914 for (AliasingOpOperand alias : opOperands) {
916 .findValueInReverseUseDefChain(alias.opOperand,
917 isMemoryWriteInsideOp, config)
926AliasingOpOperandList bufferization::detail::defaultGetAliasingOpOperands(
931 if (!llvm::isa<TensorLikeType>(opOperand.
get().
getType()))
933 AliasingValueList aliasingValues = state.getAliasingValues(opOperand);
934 for (
const auto &it : aliasingValues)
935 if (it.value == value)
936 result.emplace_back(&opOperand, it.relation, it.isDefinite);
938 return AliasingOpOperandList(std::move(
result));
941FailureOr<BufferLikeType> bufferization::detail::defaultGetBufferType(
943 const BufferizationState &bufferizationState,
945 assert(llvm::isa<TensorType>(value.
getType()) &&
"expected tensor type");
946 auto tensorType = cast<TensorType>(value.
getType());
952 <<
"cannot bufferize value of type " << tensorType
953 <<
": element type " << elementType
954 <<
" is not a valid memref element type";
957 if (llvm::isa<BlockArgument>(value)) {
958 return options.unknownTypeConverterFn(cast<TensorLikeType>(tensorType),
964 auto opResult = llvm::cast<OpResult>(value);
966 AliasingOpOperandList aliases = analysisState.getAliasingOpOperands(opResult);
967 if (aliases.getNumAliases() > 0 &&
968 aliases.getAliases()[0].relation == BufferRelation::Equivalent) {
971 Value equivalentOperand = aliases.getAliases().front().opOperand->get();
979 options.defaultMemorySpaceFn(cast<TensorLikeType>(tensorType));
980 if (!memSpace.has_value())
981 return op->
emitError(
"could not infer memory space");
983 return options.unknownTypeConverterFn(cast<TensorLikeType>(tensorType),
987bool bufferization::detail::defaultIsRepetitiveRegion(
988 BufferizableOpInterface bufferizableOp,
unsigned index) {
989 assert(index < bufferizableOp->getNumRegions() &&
"invalid region index");
990 auto regionInterface =
991 dyn_cast<RegionBranchOpInterface>(bufferizableOp.getOperation());
992 if (!regionInterface)
994 return regionInterface.isRepetitiveRegion(
index);
998bufferization::detail::unknownGetAliasingOpOperands(
Value value) {
1001 if (
auto bbArg = dyn_cast<BlockArgument>(value))
1002 if (bbArg.getOwner() != &bbArg.getOwner()->getParent()->getBlocks().front())
1008 AliasingOpOperandList r;
1010 if (isa<TensorLikeType>(operand.get().getType()))
1011 r.addAlias({&operand, BufferRelation::Unknown,
false});
1016bufferization::detail::unknownGetAliasingValues(
OpOperand &opOperand) {
1021 AliasingValueList r;
1023 if (llvm::isa<TensorLikeType>(
result.getType()))
1024 r.addAlias({
result, BufferRelation::Unknown,
false});
1028 if (isa<TensorLikeType>(bbArg.getType()))
1029 r.addAlias({bbArg, BufferRelation::Unknown,
false});
1033bool bufferization::detail::defaultHasTensorSemantics(
Operation *op) {
1034 auto isaTensor = [](
Type t) {
return isa<TensorLikeType>(t); };
1036 return any_of(r.getBlocks(), [&](Block &b) {
1037 return any_of(b.getArguments(), [&](BlockArgument bbArg) {
1038 return isaTensor(bbArg.getType());
1042 if (hasTensorBlockArgument)
1050FailureOr<BaseMemRefType>
1051bufferization::detail::asMemRefType(FailureOr<BufferLikeType> bufferType) {
1054 return cast<BaseMemRefType>(*bufferType);
1057bool bufferization::detail::typesMatchAfterBufferization(
Operation &op,
1060 return mlir::succeeded(
1061 cast<TensorLikeType>(
tensor.getType())
1062 .verifyCompatibleBufferType(cast<BufferLikeType>(buffer.
getType()),
1063 [&]() { return op.emitError(); }));
static void setInsertionPointAfter(OpBuilder &b, Value value)
static bool isRepetitiveRegion(Region *region, const BufferizationOptions &options)
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
*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
static RankedTensorType getBufferType(const SparseTensorType &stt, bool needTmpCOO)
#define MLIR_DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME)
static Operation * getOwnerOfValue(Value value)
Base class for generic analysis states.
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
Attributes are known-constant values of operations.
This class provides a shared interface for ranked and unranked memref types.
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a memref.
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.
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 setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
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...
Block * getBlock()
Returns the operation block that contains 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...
MutableArrayRef< OpOperand > getOpOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
operand_type_range getOperandTypes()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
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.
BlockListType & getBlocks()
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...
Type getElementType() const
Returns the element type of this tensor type.
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.
Operation * getOwner() const
Return the owner of this operand.
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...
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).
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Region * getEnclosingRepetitiveRegion(Operation *op)
Return the first enclosing region of the given op that may be executed repetitively as per RegionBran...
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...