17#include "llvm/ADT/SmallVectorExtras.h"
30 auto srcType = llvm::cast<MemRefType>(value.
getType());
33 if (srcType.getElementType() != destType.getElementType())
35 if (srcType.getRank() != destType.getRank())
41 auto isGuaranteedCastCompatible = [](MemRefType source, MemRefType
target) {
42 int64_t sourceOffset, targetOffset;
44 if (failed(source.getStridesAndOffset(sourceStrides, sourceOffset)) ||
45 failed(
target.getStridesAndOffset(targetStrides, targetOffset)))
48 return ShapedType::isDynamic(a) && ShapedType::isStatic(
b);
50 if (dynamicToStatic(sourceOffset, targetOffset))
52 for (
auto it : zip(sourceStrides, targetStrides))
53 if (dynamicToStatic(std::get<0>(it), std::get<1>(it)))
61 if (memref::CastOp::areCastCompatible(srcType, destType) &&
62 isGuaranteedCastCompatible(srcType, destType)) {
69 for (
int i = 0; i < destType.getRank(); ++i) {
70 if (destType.getShape()[i] != ShapedType::kDynamic)
72 Value size = memref::DimOp::create(
b, loc, value, i);
73 dynamicOperands.push_back(size);
77 b, loc, destType, dynamicOperands,
options.bufferAlignment);
90 auto bufferToTensor = toBuffer.getTensor().getDefiningOp<ToTensorOp>();
94 Type srcType = bufferToTensor.getBuffer().getType();
95 Type destType = toBuffer.getType();
98 if (srcType == destType) {
99 rewriter.
replaceOp(toBuffer, bufferToTensor.getBuffer());
103 if (!llvm::isa<BaseMemRefType>(srcType) ||
104 !llvm::isa<BaseMemRefType>(destType)) {
107 options.castFn(rewriter, bufferToTensor.getBuffer().getLoc(), destType,
108 bufferToTensor.getBuffer());
115 auto rankedSrcType = llvm::dyn_cast<MemRefType>(srcType);
116 auto rankedDestType = llvm::dyn_cast<MemRefType>(destType);
117 auto unrankedSrcType = llvm::dyn_cast<UnrankedMemRefType>(srcType);
120 if (rankedSrcType && rankedDestType) {
122 rewriter, bufferToTensor.getBuffer(), rankedDestType,
options);
132 if (unrankedSrcType && rankedDestType)
137 if (!memref::CastOp::areCastCompatible(srcType, destType))
141 bufferToTensor.getBuffer());
148 auto shapedType = llvm::cast<ShapedType>(shapedValue.
getType());
149 for (
int64_t i = 0; i < shapedType.getRank(); ++i) {
150 if (shapedType.isDynamicDim(i)) {
151 if (llvm::isa<MemRefType>(shapedType)) {
152 dynamicDims.push_back(memref::DimOp::create(
b, loc, shapedValue, i));
154 assert(llvm::isa<RankedTensorType>(shapedType) &&
"expected tensor");
155 dynamicDims.push_back(tensor::DimOp::create(
b, loc, shapedValue, i));
165LogicalResult AllocTensorOp::bufferize(
RewriterBase &rewriter,
167 BufferizationState &state) {
172 if (getOperation()->getUses().empty()) {
173 rewriter.
eraseOp(getOperation());
180 FailureOr<Value> maybeCopyBuffer =
181 getBuffer(rewriter, getCopy(),
options, state);
182 if (failed(maybeCopyBuffer))
184 copyBuffer = *maybeCopyBuffer;
188 auto allocType = bufferization::getBufferType(getResult(),
options, state);
193 assert(dynamicDims.empty() &&
"expected either `copy` or `dynamicDims`");
196 FailureOr<Value> alloc =
197 options.allocationFn(rewriter, loc, llvm::cast<MemRefType>(*allocType),
198 dynamicDims,
options.bufferAlignment);
204 if (
failed(
options.memCpyFn(rewriter, loc, copyBuffer, *alloc)))
209 replaceOpWithBufferizedValues(rewriter, getOperation(), *alloc);
214bool AllocTensorOp::resultBufferizesToMemoryWrite(
OpResult opResult,
217 return static_cast<bool>(getCopy());
220bool AllocTensorOp::bufferizesToMemoryRead(
OpOperand &opOperand,
223 "expected copy operand");
227bool AllocTensorOp::bufferizesToMemoryWrite(
OpOperand &opOperand,
230 "expected copy operand");
234AliasingValueList AllocTensorOp::getAliasingValues(
OpOperand &opOperand,
240FailureOr<BufferLikeType>
242 const BufferizationState &state,
244 assert(value == getResult() &&
"invalid value");
248 if (getMemorySpace().has_value()) {
249 memorySpace = *getMemorySpace();
250 }
else if (getCopy()) {
251 auto copyBufferType =
252 bufferization::detail::asMemRefType(bufferization::getBufferType(
253 getCopy(),
options, state, invocationStack));
254 if (
failed(copyBufferType))
256 memorySpace = copyBufferType->getMemorySpace();
257 }
else if (
auto ms =
options.defaultMemorySpaceFn(
258 cast<TensorLikeType>(
getType()))) {
261 return getOperation()->emitError(
"could not infer memory space");
264 return cast<BufferLikeType>(
265 getMemRefTypeWithStaticIdentityLayout(
getType(), memorySpace));
268LogicalResult AllocTensorOp::verify() {
270 return emitError(
"dynamic sizes not needed when copying a tensor");
275 return emitError(
"expected that `copy` and return type match");
280 RankedTensorType type,
ValueRange dynamicSizes) {
281 build(builder,
result, type, dynamicSizes,
Value(),
287 RankedTensorType type,
ValueRange dynamicSizes,
295 IntegerAttr memorySpace) {
313 using OpRewritePattern<AllocTensorOp>::OpRewritePattern;
315 LogicalResult matchAndRewrite(AllocTensorOp op,
316 PatternRewriter &rewriter)
const override {
319 SmallVector<int64_t> newShape = llvm::to_vector(op.getType().getShape());
320 SmallVector<Value> newDynamicSizes;
321 unsigned int dynValCounter = 0;
322 for (int64_t i = 0; i < op.getType().getRank(); ++i) {
323 if (!op.isDynamicDim(i))
325 Value value = op.getDynamicSizes()[dynValCounter++];
328 int64_t dim = intVal.getSExtValue();
330 newShape[i] = intVal.getSExtValue();
332 newDynamicSizes.push_back(value);
334 newDynamicSizes.push_back(value);
337 RankedTensorType newType = RankedTensorType::get(
338 newShape, op.getType().getElementType(), op.getType().getEncoding());
339 if (newType == op.getType())
341 auto newOp = AllocTensorOp::create(rewriter, op.getLoc(), newType,
342 newDynamicSizes, Value());
349 using OpRewritePattern<tensor::DimOp>::OpRewritePattern;
351 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
352 PatternRewriter &rewriter)
const override {
353 std::optional<int64_t> maybeConstantIndex = dimOp.getConstantIndex();
354 auto allocTensorOp = dimOp.getSource().getDefiningOp<AllocTensorOp>();
355 if (!allocTensorOp || !maybeConstantIndex)
357 if (*maybeConstantIndex < 0 ||
358 *maybeConstantIndex >= allocTensorOp.getType().getRank())
360 if (!allocTensorOp.getType().isDynamicDim(*maybeConstantIndex))
363 dimOp, allocTensorOp.getDynamicSize(rewriter, *maybeConstantIndex));
371 results.
add<FoldDimOfAllocTensorOp, ReplaceStaticShapeDims>(ctx);
374LogicalResult AllocTensorOp::reifyResultShapes(
377 llvm::map_to_vector<4>(llvm::seq<int64_t>(0,
getType().getRank()),
379 if (isDynamicDim(dim))
383 reifiedReturnShapes.emplace_back(std::move(shapes));
394 if (copyKeyword.succeeded())
400 if (sizeHintKeyword.succeeded())
414 if (copyKeyword.succeeded())
417 if (sizeHintKeyword.succeeded())
420 result.addAttribute(AllocTensorOp::getOperandSegmentSizeAttr(),
422 {static_cast<int32_t>(dynamicSizesOperands.size()),
423 static_cast<int32_t>(copyKeyword.succeeded()),
424 static_cast<int32_t>(sizeHintKeyword.succeeded())}));
431 p <<
" copy(" << getCopy() <<
")";
433 p <<
" size_hint=" << getSizeHint();
435 AllocTensorOp::getOperandSegmentSizeAttr()});
437 auto type = getResult().getType();
438 if (
auto validType = llvm::dyn_cast<::mlir::TensorType>(type))
445 assert(isDynamicDim(idx) &&
"expected dynamic dim");
447 return tensor::DimOp::create(
b, getLoc(), getCopy(), idx);
448 return getOperand(getIndexOfDynamicSize(idx));
464 using OpRewritePattern<CloneOp>::OpRewritePattern;
466 LogicalResult matchAndRewrite(CloneOp cloneOp,
467 PatternRewriter &rewriter)
const override {
468 if (cloneOp.use_empty()) {
473 Value source = cloneOp.getInput();
474 if (source.
getType() != cloneOp.getType() &&
475 !memref::CastOp::areCastCompatible({source.getType()},
476 {cloneOp.getType()}))
481 Value canonicalSource = source;
482 while (
auto iface = dyn_cast_or_null<ViewLikeOpInterface>(
484 if (canonicalSource != iface.getViewDest()) {
487 canonicalSource = iface.getViewSource();
490 std::optional<Operation *> maybeCloneDeallocOp =
493 if (!maybeCloneDeallocOp.has_value())
495 std::optional<Operation *> maybeSourceDeallocOp =
497 if (!maybeSourceDeallocOp.has_value())
499 Operation *cloneDeallocOp = *maybeCloneDeallocOp;
500 Operation *sourceDeallocOp = *maybeSourceDeallocOp;
504 if (cloneDeallocOp && sourceDeallocOp &&
508 Block *currentBlock = cloneOp->getBlock();
509 Operation *redundantDealloc =
nullptr;
510 if (cloneDeallocOp && cloneDeallocOp->
getBlock() == currentBlock) {
511 redundantDealloc = cloneDeallocOp;
512 }
else if (sourceDeallocOp && sourceDeallocOp->
getBlock() == currentBlock) {
513 redundantDealloc = sourceDeallocOp;
516 if (!redundantDealloc)
524 for (Operation *pos = cloneOp->getNextNode(); pos != redundantDealloc;
525 pos = pos->getNextNode()) {
529 auto effectInterface = dyn_cast<MemoryEffectOpInterface>(pos);
530 if (!effectInterface)
532 if (effectInterface.hasEffect<MemoryEffects::Free>())
536 if (source.
getType() != cloneOp.getType())
537 source = memref::CastOp::create(rewriter, cloneOp.getLoc(),
538 cloneOp.getType(), source);
540 rewriter.
eraseOp(redundantDealloc);
549 results.
add<SimplifyClones>(context);
556LogicalResult DeallocTensorOp::bufferize(
RewriterBase &rewriter,
558 BufferizationState &state) {
559 FailureOr<Value> buffer = getBuffer(rewriter, getTensor(),
options, state);
562 memref::DeallocOp::create(rewriter, getLoc(), *buffer);
563 rewriter.
eraseOp(getOperation());
571bool MaterializeInDestinationOp::bufferizesToMemoryRead(
573 return opOperand == getSourceMutable();
576bool MaterializeInDestinationOp::bufferizesToMemoryWrite(
578 if (opOperand == getDestMutable()) {
579 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
585bool MaterializeInDestinationOp::mustBufferizeInPlace(
594MaterializeInDestinationOp::getAliasingValues(
OpOperand &opOperand,
596 if (opOperand == getDestMutable()) {
597 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
598 return {{getOperation()->getResult(0), BufferRelation::Equivalent}};
604MaterializeInDestinationOp::bufferize(
RewriterBase &rewriter,
606 BufferizationState &state) {
607 bool tensorDest = isa<TensorType>(getDest().
getType());
610 FailureOr<Value> maybeBuffer =
611 getBuffer(rewriter, getDest(),
options, state);
614 buffer = *maybeBuffer;
616 assert(isa<BaseMemRefType>(getDest().
getType()) &&
"expected memref type");
619 auto srcBuffer = getBuffer(rewriter, getSource(),
options, state);
622 if (
failed(
options.memCpyFn(rewriter, getLoc(), *srcBuffer, buffer)))
624 replaceOpWithBufferizedValues(rewriter, getOperation(),
629bool MaterializeInDestinationOp::bufferizesToElementwiseAccess(
636LogicalResult MaterializeInDestinationOp::reifyResultShapes(
638 if (getOperation()->getNumResults() == 1) {
639 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
640 reifiedReturnShapes.resize(1,
642 reifiedReturnShapes[0] =
648Value MaterializeInDestinationOp::buildSubsetExtraction(
OpBuilder &builder,
650 if (isa<TensorType>(getDest().
getType())) {
663 assert(isa<BaseMemRefType>(getDest().
getType()) &&
"expected memref type");
664 assert(getRestrict() &&
665 "expected that ops with memrefs dest have 'restrict'");
667 return ToTensorOp::create(
670 true, getWritable());
673bool MaterializeInDestinationOp::isEquivalentSubset(
675 return equivalenceFn(getDest(), candidate);
679MaterializeInDestinationOp::getValuesNeededToBuildSubsetExtraction() {
683OpOperand &MaterializeInDestinationOp::getSourceOperand() {
684 return getOperation()->getOpOperand(0) ;
687bool MaterializeInDestinationOp::operatesOnEquivalentSubset(
688 SubsetOpInterface subsetOp,
693bool MaterializeInDestinationOp::operatesOnDisjointSubset(
694 SubsetOpInterface subsetOp,
699LogicalResult MaterializeInDestinationOp::verify() {
700 if (!isa<TensorType, BaseMemRefType>(getDest().
getType()))
701 return emitOpError(
"'dest' must be a tensor or a memref");
702 if (
auto destType = dyn_cast<TensorType>(getDest().
getType())) {
703 if (getOperation()->getNumResults() != 1)
704 return emitOpError(
"tensor 'dest' implies exactly one tensor result");
705 if (destType != getResult().
getType())
706 return emitOpError(
"result and 'dest' types must match");
708 if (isa<BaseMemRefType>(getDest().
getType()) &&
709 getOperation()->getNumResults() != 0)
710 return emitOpError(
"memref 'dest' implies zero results");
711 if (getRestrict() && !isa<BaseMemRefType>(getDest().
getType()))
712 return emitOpError(
"'restrict' is valid only for memref destinations");
713 if (getWritable() != isa<BaseMemRefType>(getDest().
getType()))
714 return emitOpError(
"'writable' must be specified if and only if the "
715 "destination is of memref type");
717 ShapedType destType = cast<ShapedType>(getDest().
getType());
718 if (srcType.
hasRank() != destType.hasRank())
719 return emitOpError(
"source/destination shapes are incompatible");
724 for (
auto [src, dest] :
725 llvm::zip(srcType.
getShape(), destType.getShape())) {
726 if (src == ShapedType::kDynamic || dest == ShapedType::kDynamic) {
732 return emitOpError(
"source/destination shapes are incompatible");
738void MaterializeInDestinationOp::build(
OpBuilder &builder,
741 auto destTensorType = dyn_cast<TensorType>(dest.
getType());
742 build(builder, state, destTensorType ? destTensorType :
Type(),
746bool MaterializeInDestinationOp::isWritable(
Value value,
748 return isa<TensorType>(getDest().
getType()) ?
true : getWritable();
752 return getDestMutable();
755void MaterializeInDestinationOp::getEffects(
758 if (isa<BaseMemRefType>(getDest().
getType()))
768 return getWritable();
772 if (
auto toBuffer = getBuffer().getDefiningOp<ToBufferOp>())
775 if (toBuffer->getBlock() == this->getOperation()->getBlock() &&
776 toBuffer->getNextNode() == this->getOperation())
777 return toBuffer.getTensor();
783 using OpRewritePattern<tensor::DimOp>::OpRewritePattern;
785 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
786 PatternRewriter &rewriter)
const override {
787 auto memrefToTensorOp = dimOp.getSource().getDefiningOp<ToTensorOp>();
788 if (!memrefToTensorOp)
792 dimOp, memrefToTensorOp.getBuffer(), dimOp.getIndex());
800 results.
add<DimOfToTensorFolder>(context);
808 if (
auto memrefToTensor = getTensor().getDefiningOp<ToTensorOp>())
809 if (memrefToTensor.getBuffer().getType() ==
getType())
810 return memrefToTensor.getBuffer();
818 using OpRewritePattern<ToBufferOp>::OpRewritePattern;
820 LogicalResult matchAndRewrite(ToBufferOp toBuffer,
821 PatternRewriter &rewriter)
const final {
822 auto tensorCastOperand =
823 toBuffer.getOperand().getDefiningOp<tensor::CastOp>();
824 if (!tensorCastOperand)
826 auto srcTensorType = llvm::dyn_cast<RankedTensorType>(
827 tensorCastOperand.getOperand().getType());
830 auto currentOutputMemRefType =
831 dyn_cast<BaseMemRefType>(toBuffer.getResult().getType());
832 if (!currentOutputMemRefType)
835 auto memrefType = currentOutputMemRefType.cloneWith(
836 srcTensorType.getShape(), srcTensorType.getElementType());
837 Value memref = ToBufferOp::create(rewriter, toBuffer.getLoc(), memrefType,
838 tensorCastOperand.getOperand(),
839 toBuffer.getReadOnly());
849 using OpRewritePattern<ToBufferOp>::OpRewritePattern;
851 LogicalResult matchAndRewrite(ToBufferOp toBuffer,
852 PatternRewriter &rewriter)
const final {
862 using OpRewritePattern<memref::LoadOp>::OpRewritePattern;
864 LogicalResult matchAndRewrite(memref::LoadOp
load,
865 PatternRewriter &rewriter)
const override {
866 auto toBuffer =
load.getMemref().getDefiningOp<ToBufferOp>();
867 if (!toBuffer || !toBuffer.getReadOnly())
878 using OpRewritePattern<memref::DimOp>::OpRewritePattern;
880 LogicalResult matchAndRewrite(memref::DimOp dimOp,
881 PatternRewriter &rewriter)
const override {
882 auto castOp = dimOp.getSource().getDefiningOp<ToBufferOp>();
885 Value newSource = castOp.getOperand();
896 results.
add<DimOfCastOp, LoadOfToBuffer, ToBufferOfCast,
897 ToBufferToTensorFolding>(context);
900LogicalResult ToBufferOp::bufferize(
RewriterBase &rewriter,
902 BufferizationState &state) {
910std::optional<Operation *> CloneOp::buildDealloc(
OpBuilder &builder,
912 return memref::DeallocOp::create(builder, alloc.
getLoc(), alloc)
916std::optional<Value> CloneOp::buildClone(
OpBuilder &builder,
Value alloc) {
917 return CloneOp::create(builder, alloc.
getLoc(), alloc).getResult();
924LogicalResult DeallocOp::inferReturnTypes(
925 MLIRContext *context, std::optional<::mlir::Location> location,
928 DeallocOpAdaptor adaptor(operands, attributes, properties, regions);
930 IntegerType::get(context, 1));
934LogicalResult DeallocOp::verify() {
935 if (getMemrefs().size() != getConditions().size())
937 "must have the same number of conditions as memrefs to deallocate");
938 if (getRetained().size() != getUpdatedConditions().size())
939 return emitOpError(
"must have the same number of updated conditions "
940 "(results) as retained operands");
948 if (deallocOp.getMemrefs() == memrefs &&
949 deallocOp.getConditions() == conditions)
953 deallocOp.getMemrefsMutable().assign(memrefs);
954 deallocOp.getConditionsMutable().assign(conditions);
974struct DeallocRemoveDuplicateDeallocMemrefs
976 using OpRewritePattern<DeallocOp>::OpRewritePattern;
978 LogicalResult matchAndRewrite(DeallocOp deallocOp,
979 PatternRewriter &rewriter)
const override {
982 SmallVector<Value> newMemrefs, newConditions;
983 for (
auto [i, memref, cond] :
984 llvm::enumerate(deallocOp.getMemrefs(), deallocOp.getConditions())) {
985 if (memrefToCondition.count(memref)) {
988 Value &newCond = newConditions[memrefToCondition[memref]];
991 arith::OrIOp::create(rewriter, deallocOp.getLoc(), newCond, cond);
993 memrefToCondition.insert({memref, newConditions.size()});
994 newMemrefs.push_back(memref);
995 newConditions.push_back(cond);
1016struct DeallocRemoveDuplicateRetainedMemrefs
1018 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1020 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1021 PatternRewriter &rewriter)
const override {
1024 SmallVector<Value> newRetained;
1025 SmallVector<unsigned> resultReplacementIdx;
1027 for (
auto retained : deallocOp.getRetained()) {
1028 if (seen.count(retained)) {
1029 resultReplacementIdx.push_back(seen[retained]);
1034 newRetained.push_back(retained);
1035 resultReplacementIdx.push_back(i++);
1040 if (newRetained.size() == deallocOp.getRetained().size())
1046 DeallocOp::create(rewriter, deallocOp.getLoc(), deallocOp.getMemrefs(),
1047 deallocOp.getConditions(), newRetained);
1048 SmallVector<Value> replacements(
1049 llvm::map_range(resultReplacementIdx, [&](
unsigned idx) {
1050 return newDeallocOp.getUpdatedConditions()[idx];
1052 rewriter.
replaceOp(deallocOp, replacements);
1063 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1065 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1066 PatternRewriter &rewriter)
const override {
1067 if (deallocOp.getMemrefs().empty()) {
1068 Value constFalse = arith::ConstantOp::create(rewriter, deallocOp.getLoc(),
1071 deallocOp, SmallVector<Value>(deallocOp.getUpdatedConditions().size(),
1092 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1094 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1095 PatternRewriter &rewriter)
const override {
1096 SmallVector<Value> newMemrefs, newConditions;
1097 for (
auto [memref, cond] :
1098 llvm::zip(deallocOp.getMemrefs(), deallocOp.getConditions())) {
1100 newMemrefs.push_back(memref);
1101 newConditions.push_back(cond);
1129 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1131 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1132 PatternRewriter &rewriter)
const override {
1133 SmallVector<Value> newMemrefs(
1134 llvm::map_range(deallocOp.getMemrefs(), [&](Value memref) {
1135 auto extractStridedOp =
1136 memref.getDefiningOp<memref::ExtractStridedMetadataOp>();
1137 if (!extractStridedOp)
1139 Value allocMemref = extractStridedOp.getOperand();
1140 auto allocOp = allocMemref.getDefiningOp<MemoryEffectOpInterface>();
1143 if (allocOp.getEffectOnValue<MemoryEffects::Allocate>(allocMemref))
1149 deallocOp.getConditions(), rewriter);
1167struct RemoveAllocDeallocPairWhenNoOtherUsers
1169 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1171 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1172 PatternRewriter &rewriter)
const override {
1173 SmallVector<Value> newMemrefs, newConditions;
1174 SmallVector<Operation *> toDelete;
1175 for (
auto [memref, cond] :
1176 llvm::zip(deallocOp.getMemrefs(), deallocOp.getConditions())) {
1177 if (
auto allocOp = memref.getDefiningOp<MemoryEffectOpInterface>()) {
1181 if (allocOp.getEffectOnValue<MemoryEffects::Allocate>(memref) &&
1183 memref.hasOneUse()) {
1184 toDelete.push_back(allocOp);
1189 newMemrefs.push_back(memref);
1190 newConditions.push_back(cond);
1197 for (Operation *op : toDelete)
1213 patterns.
add<DeallocRemoveDuplicateDeallocMemrefs,
1214 DeallocRemoveDuplicateRetainedMemrefs, EraseEmptyDealloc,
1215 EraseAlwaysFalseDealloc, SkipExtractMetadataOfAlloc,
1216 RemoveAllocDeallocPairWhenNoOtherUsers>(context);
1223#define GET_OP_CLASSES
1224#include "mlir/Dialect/Bufferization/IR/BufferizationOps.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static SmallVector< Value > getDynamicSize(Value memref, func::FuncOp funcOp)
Return the dynamic shapes of the memref based on the defining op.
static LogicalResult updateDeallocIfChanged(DeallocOp deallocOp, ValueRange memrefs, ValueRange conditions, PatternRewriter &rewriter)
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
true
Given two iterators into the same block, return "true" if a is before `b.
*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 llvm::ManagedStatic< PassManagerOptions > options
template bool mlir::hasSingleEffect< MemoryEffects::Allocate >(Operation *)
static void getDynamicSizes(RankedTensorType tp, ValueRange sizes, SmallVectorImpl< Value > &dynSizes)
Collects the dynamic dimension sizes for tp with the assumption that sizes are the dimension sizes fo...
Base class for generic analysis states.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseCustomTypeWithFallback(Type &result, function_ref< ParseResult(Type &result)> parseType)=0
Parse a custom type with the provided callback, unless the next token is #, in which case the generic...
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
void printStrippedAttrOrType(AttrOrType attrOrType)
Print the provided attribute in the context of an operation custom printer/parser: this will invoke d...
Attributes are known-constant values of operations.
IntegerAttr getIndexAttr(int64_t value)
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
BoolAttr getBoolAttr(bool value)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class provides a mutable adaptor for a range of operands.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
This class represents a single result from folding an operation.
This class represents an operand of an operation.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the Operation.
This is a value defined by a result of an operation.
Block * getBlock()
Returns the operation block that contains this operation.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This class provides an abstraction over the different types of ranges over Regions.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
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...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class represents a specific instance of an effect.
static DerivedEffect * get()
static DefaultResource * get()
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
ArrayRef< int64_t > getShape() const
Returns the shape of this tensor type.
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
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.
void populateDeallocOpCanonicalizationPatterns(RewritePatternSet &patterns, MLIRContext *context)
Add the canonicalization patterns for bufferization.dealloc to the given pattern set to make them ava...
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.
LogicalResult foldToBufferToTensorPair(RewriterBase &rewriter, ToBufferOp toBuffer, const BufferizationOptions &options)
Try to fold to_buffer(to_tensor(x)).
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...
Type getTensorTypeFromMemRefType(Type type)
Return an unranked/ranked tensor type for the given unranked/ranked memref type.
std::optional< Operation * > findDealloc(Value allocValue)
Finds a single dealloc operation for the given allocated value.
LogicalResult foldMemRefCast(Operation *op, Value inner=nullptr)
This is a common utility used for patterns of the form "someop(memref.cast) -> someop".
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given tensor value.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
LogicalResult verifyDynamicDimensionCount(Operation *op, ShapedType type, ValueRange dynamicSizes)
Verify that the number of dynamic size operands matches the number of dynamic dimensions in the shape...
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
LogicalResult verifyRanksMatch(Operation *op, ShapedType lhs, ShapedType rhs, StringRef lhsName, StringRef rhsName)
Verify that two shaped types have matching ranks.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref
This is the representation of an operand reference.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.