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 assert(memref::CastOp::areCastCompatible(srcType, destType) &&
138 "expected that types are cast compatible");
140 bufferToTensor.getBuffer());
147 auto shapedType = llvm::cast<ShapedType>(shapedValue.
getType());
148 for (
int64_t i = 0; i < shapedType.getRank(); ++i) {
149 if (shapedType.isDynamicDim(i)) {
150 if (llvm::isa<MemRefType>(shapedType)) {
151 dynamicDims.push_back(memref::DimOp::create(
b, loc, shapedValue, i));
153 assert(llvm::isa<RankedTensorType>(shapedType) &&
"expected tensor");
154 dynamicDims.push_back(tensor::DimOp::create(
b, loc, shapedValue, i));
164LogicalResult AllocTensorOp::bufferize(
RewriterBase &rewriter,
166 BufferizationState &state) {
171 if (getOperation()->getUses().empty()) {
172 rewriter.
eraseOp(getOperation());
179 FailureOr<Value> maybeCopyBuffer =
180 getBuffer(rewriter, getCopy(),
options, state);
181 if (failed(maybeCopyBuffer))
183 copyBuffer = *maybeCopyBuffer;
187 auto allocType = bufferization::getBufferType(getResult(),
options, state);
192 assert(dynamicDims.empty() &&
"expected either `copy` or `dynamicDims`");
195 FailureOr<Value> alloc =
196 options.allocationFn(rewriter, loc, llvm::cast<MemRefType>(*allocType),
197 dynamicDims,
options.bufferAlignment);
203 if (
failed(
options.memCpyFn(rewriter, loc, copyBuffer, *alloc)))
208 replaceOpWithBufferizedValues(rewriter, getOperation(), *alloc);
213bool AllocTensorOp::resultBufferizesToMemoryWrite(
OpResult opResult,
216 return static_cast<bool>(getCopy());
219bool AllocTensorOp::bufferizesToMemoryRead(
OpOperand &opOperand,
222 "expected copy operand");
226bool AllocTensorOp::bufferizesToMemoryWrite(
OpOperand &opOperand,
229 "expected copy operand");
233AliasingValueList AllocTensorOp::getAliasingValues(
OpOperand &opOperand,
239FailureOr<BufferLikeType>
241 const BufferizationState &state,
243 assert(value == getResult() &&
"invalid value");
247 if (getMemorySpace().has_value()) {
248 memorySpace = *getMemorySpace();
249 }
else if (getCopy()) {
250 auto copyBufferType =
251 bufferization::detail::asMemRefType(bufferization::getBufferType(
252 getCopy(),
options, state, invocationStack));
253 if (
failed(copyBufferType))
255 memorySpace = copyBufferType->getMemorySpace();
256 }
else if (
auto ms =
options.defaultMemorySpaceFn(
257 cast<TensorLikeType>(
getType()))) {
260 return getOperation()->emitError(
"could not infer memory space");
263 return cast<BufferLikeType>(
264 getMemRefTypeWithStaticIdentityLayout(
getType(), memorySpace));
267LogicalResult AllocTensorOp::verify() {
269 return emitError(
"dynamic sizes not needed when copying a tensor");
274 return emitError(
"expected that `copy` and return type match");
279 RankedTensorType type,
ValueRange dynamicSizes) {
280 build(builder,
result, type, dynamicSizes,
Value(),
286 RankedTensorType type,
ValueRange dynamicSizes,
294 IntegerAttr memorySpace) {
312 using OpRewritePattern<AllocTensorOp>::OpRewritePattern;
314 LogicalResult matchAndRewrite(AllocTensorOp op,
315 PatternRewriter &rewriter)
const override {
318 SmallVector<int64_t> newShape = llvm::to_vector(op.getType().getShape());
319 SmallVector<Value> newDynamicSizes;
320 unsigned int dynValCounter = 0;
321 for (int64_t i = 0; i < op.getType().getRank(); ++i) {
322 if (!op.isDynamicDim(i))
324 Value value = op.getDynamicSizes()[dynValCounter++];
327 int64_t dim = intVal.getSExtValue();
329 newShape[i] = intVal.getSExtValue();
331 newDynamicSizes.push_back(value);
333 newDynamicSizes.push_back(value);
336 RankedTensorType newType = RankedTensorType::get(
337 newShape, op.getType().getElementType(), op.getType().getEncoding());
338 if (newType == op.getType())
340 auto newOp = AllocTensorOp::create(rewriter, op.getLoc(), newType,
341 newDynamicSizes, Value());
348 using OpRewritePattern<tensor::DimOp>::OpRewritePattern;
350 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
351 PatternRewriter &rewriter)
const override {
352 std::optional<int64_t> maybeConstantIndex = dimOp.getConstantIndex();
353 auto allocTensorOp = dimOp.getSource().getDefiningOp<AllocTensorOp>();
354 if (!allocTensorOp || !maybeConstantIndex)
356 if (*maybeConstantIndex < 0 ||
357 *maybeConstantIndex >= allocTensorOp.getType().getRank())
359 if (!allocTensorOp.getType().isDynamicDim(*maybeConstantIndex))
362 dimOp, allocTensorOp.getDynamicSize(rewriter, *maybeConstantIndex));
370 results.
add<FoldDimOfAllocTensorOp, ReplaceStaticShapeDims>(ctx);
373LogicalResult AllocTensorOp::reifyResultShapes(
376 llvm::map_to_vector<4>(llvm::seq<int64_t>(0,
getType().getRank()),
378 if (isDynamicDim(dim))
382 reifiedReturnShapes.emplace_back(std::move(shapes));
393 if (copyKeyword.succeeded())
399 if (sizeHintKeyword.succeeded())
413 if (copyKeyword.succeeded())
416 if (sizeHintKeyword.succeeded())
419 result.addAttribute(AllocTensorOp::getOperandSegmentSizeAttr(),
421 {static_cast<int32_t>(dynamicSizesOperands.size()),
422 static_cast<int32_t>(copyKeyword.succeeded()),
423 static_cast<int32_t>(sizeHintKeyword.succeeded())}));
430 p <<
" copy(" << getCopy() <<
")";
432 p <<
" size_hint=" << getSizeHint();
434 AllocTensorOp::getOperandSegmentSizeAttr()});
436 auto type = getResult().getType();
437 if (
auto validType = llvm::dyn_cast<::mlir::TensorType>(type))
444 assert(isDynamicDim(idx) &&
"expected dynamic dim");
446 return tensor::DimOp::create(
b, getLoc(), getCopy(), idx);
447 return getOperand(getIndexOfDynamicSize(idx));
463 using OpRewritePattern<CloneOp>::OpRewritePattern;
465 LogicalResult matchAndRewrite(CloneOp cloneOp,
466 PatternRewriter &rewriter)
const override {
467 if (cloneOp.use_empty()) {
472 Value source = cloneOp.getInput();
473 if (source.
getType() != cloneOp.getType() &&
474 !memref::CastOp::areCastCompatible({source.getType()},
475 {cloneOp.getType()}))
480 Value canonicalSource = source;
481 while (
auto iface = dyn_cast_or_null<ViewLikeOpInterface>(
483 if (canonicalSource != iface.getViewDest()) {
486 canonicalSource = iface.getViewSource();
489 std::optional<Operation *> maybeCloneDeallocOp =
492 if (!maybeCloneDeallocOp.has_value())
494 std::optional<Operation *> maybeSourceDeallocOp =
496 if (!maybeSourceDeallocOp.has_value())
498 Operation *cloneDeallocOp = *maybeCloneDeallocOp;
499 Operation *sourceDeallocOp = *maybeSourceDeallocOp;
503 if (cloneDeallocOp && sourceDeallocOp &&
507 Block *currentBlock = cloneOp->getBlock();
508 Operation *redundantDealloc =
nullptr;
509 if (cloneDeallocOp && cloneDeallocOp->
getBlock() == currentBlock) {
510 redundantDealloc = cloneDeallocOp;
511 }
else if (sourceDeallocOp && sourceDeallocOp->
getBlock() == currentBlock) {
512 redundantDealloc = sourceDeallocOp;
515 if (!redundantDealloc)
523 for (Operation *pos = cloneOp->getNextNode(); pos != redundantDealloc;
524 pos = pos->getNextNode()) {
528 auto effectInterface = dyn_cast<MemoryEffectOpInterface>(pos);
529 if (!effectInterface)
531 if (effectInterface.hasEffect<MemoryEffects::Free>())
535 if (source.
getType() != cloneOp.getType())
536 source = memref::CastOp::create(rewriter, cloneOp.getLoc(),
537 cloneOp.getType(), source);
539 rewriter.
eraseOp(redundantDealloc);
548 results.
add<SimplifyClones>(context);
555LogicalResult DeallocTensorOp::bufferize(
RewriterBase &rewriter,
557 BufferizationState &state) {
558 FailureOr<Value> buffer = getBuffer(rewriter, getTensor(),
options, state);
561 memref::DeallocOp::create(rewriter, getLoc(), *buffer);
562 rewriter.
eraseOp(getOperation());
570bool MaterializeInDestinationOp::bufferizesToMemoryRead(
572 return opOperand == getSourceMutable();
575bool MaterializeInDestinationOp::bufferizesToMemoryWrite(
577 if (opOperand == getDestMutable()) {
578 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
584bool MaterializeInDestinationOp::mustBufferizeInPlace(
593MaterializeInDestinationOp::getAliasingValues(
OpOperand &opOperand,
595 if (opOperand == getDestMutable()) {
596 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
597 return {{getOperation()->getResult(0), BufferRelation::Equivalent}};
603MaterializeInDestinationOp::bufferize(
RewriterBase &rewriter,
605 BufferizationState &state) {
606 bool tensorDest = isa<TensorType>(getDest().
getType());
609 FailureOr<Value> maybeBuffer =
610 getBuffer(rewriter, getDest(),
options, state);
613 buffer = *maybeBuffer;
615 assert(isa<BaseMemRefType>(getDest().
getType()) &&
"expected memref type");
618 auto srcBuffer = getBuffer(rewriter, getSource(),
options, state);
621 if (
failed(
options.memCpyFn(rewriter, getLoc(), *srcBuffer, buffer)))
623 replaceOpWithBufferizedValues(rewriter, getOperation(),
628bool MaterializeInDestinationOp::bufferizesToElementwiseAccess(
635LogicalResult MaterializeInDestinationOp::reifyResultShapes(
637 if (getOperation()->getNumResults() == 1) {
638 assert(isa<TensorType>(getDest().
getType()) &&
"expected tensor type");
639 reifiedReturnShapes.resize(1,
641 reifiedReturnShapes[0] =
647Value MaterializeInDestinationOp::buildSubsetExtraction(
OpBuilder &builder,
649 if (isa<TensorType>(getDest().
getType())) {
662 assert(isa<BaseMemRefType>(getDest().
getType()) &&
"expected memref type");
663 assert(getRestrict() &&
664 "expected that ops with memrefs dest have 'restrict'");
666 return ToTensorOp::create(
669 true, getWritable());
672bool MaterializeInDestinationOp::isEquivalentSubset(
674 return equivalenceFn(getDest(), candidate);
678MaterializeInDestinationOp::getValuesNeededToBuildSubsetExtraction() {
682OpOperand &MaterializeInDestinationOp::getSourceOperand() {
683 return getOperation()->getOpOperand(0) ;
686bool MaterializeInDestinationOp::operatesOnEquivalentSubset(
687 SubsetOpInterface subsetOp,
692bool MaterializeInDestinationOp::operatesOnDisjointSubset(
693 SubsetOpInterface subsetOp,
698LogicalResult MaterializeInDestinationOp::verify() {
699 if (!isa<TensorType, BaseMemRefType>(getDest().
getType()))
700 return emitOpError(
"'dest' must be a tensor or a memref");
701 if (
auto destType = dyn_cast<TensorType>(getDest().
getType())) {
702 if (getOperation()->getNumResults() != 1)
703 return emitOpError(
"tensor 'dest' implies exactly one tensor result");
704 if (destType != getResult().
getType())
705 return emitOpError(
"result and 'dest' types must match");
707 if (isa<BaseMemRefType>(getDest().
getType()) &&
708 getOperation()->getNumResults() != 0)
709 return emitOpError(
"memref 'dest' implies zero results");
710 if (getRestrict() && !isa<BaseMemRefType>(getDest().
getType()))
711 return emitOpError(
"'restrict' is valid only for memref destinations");
712 if (getWritable() != isa<BaseMemRefType>(getDest().
getType()))
713 return emitOpError(
"'writable' must be specified if and only if the "
714 "destination is of memref type");
716 ShapedType destType = cast<ShapedType>(getDest().
getType());
717 if (srcType.
hasRank() != destType.hasRank())
718 return emitOpError(
"source/destination shapes are incompatible");
723 for (
auto [src, dest] :
724 llvm::zip(srcType.
getShape(), destType.getShape())) {
725 if (src == ShapedType::kDynamic || dest == ShapedType::kDynamic) {
731 return emitOpError(
"source/destination shapes are incompatible");
737void MaterializeInDestinationOp::build(
OpBuilder &builder,
740 auto destTensorType = dyn_cast<TensorType>(dest.
getType());
741 build(builder, state, destTensorType ? destTensorType :
Type(),
745bool MaterializeInDestinationOp::isWritable(
Value value,
747 return isa<TensorType>(getDest().
getType()) ?
true : getWritable();
751 return getDestMutable();
754void MaterializeInDestinationOp::getEffects(
757 if (isa<BaseMemRefType>(getDest().
getType()))
767 return getWritable();
771 if (
auto toBuffer = getBuffer().getDefiningOp<ToBufferOp>())
774 if (toBuffer->getBlock() == this->getOperation()->getBlock() &&
775 toBuffer->getNextNode() == this->getOperation())
776 return toBuffer.getTensor();
782 using OpRewritePattern<tensor::DimOp>::OpRewritePattern;
784 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
785 PatternRewriter &rewriter)
const override {
786 auto memrefToTensorOp = dimOp.getSource().getDefiningOp<ToTensorOp>();
787 if (!memrefToTensorOp)
791 dimOp, memrefToTensorOp.getBuffer(), dimOp.getIndex());
799 results.
add<DimOfToTensorFolder>(context);
807 if (
auto memrefToTensor = getTensor().getDefiningOp<ToTensorOp>())
808 if (memrefToTensor.getBuffer().getType() ==
getType())
809 return memrefToTensor.getBuffer();
817 using OpRewritePattern<ToBufferOp>::OpRewritePattern;
819 LogicalResult matchAndRewrite(ToBufferOp toBuffer,
820 PatternRewriter &rewriter)
const final {
821 auto tensorCastOperand =
822 toBuffer.getOperand().getDefiningOp<tensor::CastOp>();
823 if (!tensorCastOperand)
825 auto srcTensorType = llvm::dyn_cast<RankedTensorType>(
826 tensorCastOperand.getOperand().getType());
829 auto currentOutputMemRefType =
830 dyn_cast<BaseMemRefType>(toBuffer.getResult().getType());
831 if (!currentOutputMemRefType)
834 auto memrefType = currentOutputMemRefType.cloneWith(
835 srcTensorType.getShape(), srcTensorType.getElementType());
836 Value memref = ToBufferOp::create(rewriter, toBuffer.getLoc(), memrefType,
837 tensorCastOperand.getOperand(),
838 toBuffer.getReadOnly());
848 using OpRewritePattern<ToBufferOp>::OpRewritePattern;
850 LogicalResult matchAndRewrite(ToBufferOp toBuffer,
851 PatternRewriter &rewriter)
const final {
861 using OpRewritePattern<memref::LoadOp>::OpRewritePattern;
863 LogicalResult matchAndRewrite(memref::LoadOp
load,
864 PatternRewriter &rewriter)
const override {
865 auto toBuffer =
load.getMemref().getDefiningOp<ToBufferOp>();
866 if (!toBuffer || !toBuffer.getReadOnly())
877 using OpRewritePattern<memref::DimOp>::OpRewritePattern;
879 LogicalResult matchAndRewrite(memref::DimOp dimOp,
880 PatternRewriter &rewriter)
const override {
881 auto castOp = dimOp.getSource().getDefiningOp<ToBufferOp>();
884 Value newSource = castOp.getOperand();
895 results.
add<DimOfCastOp, LoadOfToBuffer, ToBufferOfCast,
896 ToBufferToTensorFolding>(context);
899LogicalResult ToBufferOp::bufferize(
RewriterBase &rewriter,
901 BufferizationState &state) {
909std::optional<Operation *> CloneOp::buildDealloc(
OpBuilder &builder,
911 return memref::DeallocOp::create(builder, alloc.
getLoc(), alloc)
915std::optional<Value> CloneOp::buildClone(
OpBuilder &builder,
Value alloc) {
916 return CloneOp::create(builder, alloc.
getLoc(), alloc).getResult();
923LogicalResult DeallocOp::inferReturnTypes(
924 MLIRContext *context, std::optional<::mlir::Location> location,
927 DeallocOpAdaptor adaptor(operands, attributes, properties, regions);
929 IntegerType::get(context, 1));
933LogicalResult DeallocOp::verify() {
934 if (getMemrefs().size() != getConditions().size())
936 "must have the same number of conditions as memrefs to deallocate");
937 if (getRetained().size() != getUpdatedConditions().size())
938 return emitOpError(
"must have the same number of updated conditions "
939 "(results) as retained operands");
947 if (deallocOp.getMemrefs() == memrefs &&
948 deallocOp.getConditions() == conditions)
952 deallocOp.getMemrefsMutable().assign(memrefs);
953 deallocOp.getConditionsMutable().assign(conditions);
973struct DeallocRemoveDuplicateDeallocMemrefs
975 using OpRewritePattern<DeallocOp>::OpRewritePattern;
977 LogicalResult matchAndRewrite(DeallocOp deallocOp,
978 PatternRewriter &rewriter)
const override {
981 SmallVector<Value> newMemrefs, newConditions;
982 for (
auto [i, memref, cond] :
983 llvm::enumerate(deallocOp.getMemrefs(), deallocOp.getConditions())) {
984 if (memrefToCondition.count(memref)) {
987 Value &newCond = newConditions[memrefToCondition[memref]];
990 arith::OrIOp::create(rewriter, deallocOp.getLoc(), newCond, cond);
992 memrefToCondition.insert({memref, newConditions.size()});
993 newMemrefs.push_back(memref);
994 newConditions.push_back(cond);
1015struct DeallocRemoveDuplicateRetainedMemrefs
1017 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1019 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1020 PatternRewriter &rewriter)
const override {
1023 SmallVector<Value> newRetained;
1024 SmallVector<unsigned> resultReplacementIdx;
1026 for (
auto retained : deallocOp.getRetained()) {
1027 if (seen.count(retained)) {
1028 resultReplacementIdx.push_back(seen[retained]);
1033 newRetained.push_back(retained);
1034 resultReplacementIdx.push_back(i++);
1039 if (newRetained.size() == deallocOp.getRetained().size())
1045 DeallocOp::create(rewriter, deallocOp.getLoc(), deallocOp.getMemrefs(),
1046 deallocOp.getConditions(), newRetained);
1047 SmallVector<Value> replacements(
1048 llvm::map_range(resultReplacementIdx, [&](
unsigned idx) {
1049 return newDeallocOp.getUpdatedConditions()[idx];
1051 rewriter.
replaceOp(deallocOp, replacements);
1062 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1064 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1065 PatternRewriter &rewriter)
const override {
1066 if (deallocOp.getMemrefs().empty()) {
1067 Value constFalse = arith::ConstantOp::create(rewriter, deallocOp.getLoc(),
1070 deallocOp, SmallVector<Value>(deallocOp.getUpdatedConditions().size(),
1091 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1093 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1094 PatternRewriter &rewriter)
const override {
1095 SmallVector<Value> newMemrefs, newConditions;
1096 for (
auto [memref, cond] :
1097 llvm::zip(deallocOp.getMemrefs(), deallocOp.getConditions())) {
1099 newMemrefs.push_back(memref);
1100 newConditions.push_back(cond);
1128 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1130 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1131 PatternRewriter &rewriter)
const override {
1132 SmallVector<Value> newMemrefs(
1133 llvm::map_range(deallocOp.getMemrefs(), [&](Value memref) {
1134 auto extractStridedOp =
1135 memref.getDefiningOp<memref::ExtractStridedMetadataOp>();
1136 if (!extractStridedOp)
1138 Value allocMemref = extractStridedOp.getOperand();
1139 auto allocOp = allocMemref.getDefiningOp<MemoryEffectOpInterface>();
1142 if (allocOp.getEffectOnValue<MemoryEffects::Allocate>(allocMemref))
1148 deallocOp.getConditions(), rewriter);
1166struct RemoveAllocDeallocPairWhenNoOtherUsers
1168 using OpRewritePattern<DeallocOp>::OpRewritePattern;
1170 LogicalResult matchAndRewrite(DeallocOp deallocOp,
1171 PatternRewriter &rewriter)
const override {
1172 SmallVector<Value> newMemrefs, newConditions;
1173 SmallVector<Operation *> toDelete;
1174 for (
auto [memref, cond] :
1175 llvm::zip(deallocOp.getMemrefs(), deallocOp.getConditions())) {
1176 if (
auto allocOp = memref.getDefiningOp<MemoryEffectOpInterface>()) {
1180 if (allocOp.getEffectOnValue<MemoryEffects::Allocate>(memref) &&
1182 memref.hasOneUse()) {
1183 toDelete.push_back(allocOp);
1188 newMemrefs.push_back(memref);
1189 newConditions.push_back(cond);
1196 for (Operation *op : toDelete)
1212 patterns.
add<DeallocRemoveDuplicateDeallocMemrefs,
1213 DeallocRemoveDuplicateRetainedMemrefs, EraseEmptyDealloc,
1214 EraseAlwaysFalseDealloc, SkipExtractMetadataOfAlloc,
1215 RemoveAllocDeallocPairWhenNoOtherUsers>(context);
1222#define GET_OP_CLASSES
1223#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.