34 :
public BufferizableOpInterface::ExternalModel<CastOpInterface,
36 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
37 const AnalysisState &state)
const {
41 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
42 const AnalysisState &state)
const {
46 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
47 const AnalysisState &state)
const {
48 return {{op->
getResult(0), BufferRelation::Equivalent}};
51 FailureOr<BufferLikeType>
53 const BufferizationState &state,
54 SmallVector<Value> &invocationStack)
const {
55 auto castOp = cast<tensor::CastOp>(op);
56 auto maybeSrcBufferType =
57 bufferization::detail::asMemRefType(bufferization::getBufferType(
58 castOp.getSource(),
options, state, invocationStack));
59 if (
failed(maybeSrcBufferType))
61 Attribute memorySpace = maybeSrcBufferType->getMemorySpace();
67 if (isa<UnrankedTensorType>(castOp.getSource().getType())) {
70 return cast<BufferLikeType>(
71 getMemRefTypeWithFullyDynamicLayout(castOp.getType(), memorySpace));
75 if (isa<UnrankedTensorType>(castOp.getType())) {
76 return cast<BufferLikeType>(
77 getMemRefTypeWithFullyDynamicLayout(castOp.getType(), memorySpace));
82 auto rankedResultType = cast<RankedTensorType>(castOp.getType());
83 return cast<BufferLikeType>(MemRefType::get(
84 rankedResultType.getShape(), rankedResultType.getElementType(),
85 llvm::cast<MemRefType>(*maybeSrcBufferType).getLayout(), memorySpace));
88 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
89 const BufferizationOptions &
options,
90 BufferizationState &state)
const {
91 auto castOp = cast<tensor::CastOp>(op);
94 FailureOr<Value> resultBuffer =
95 getBuffer(rewriter, castOp.getSource(),
options, state);
100 auto resultMemRefType =
101 bufferization::getBufferType(castOp.getResult(),
options, state);
102 if (
failed(resultMemRefType))
104 if (resultBuffer->getType() == *resultMemRefType) {
106 replaceOpWithBufferizedValues(rewriter, op, *resultBuffer);
111 assert(memref::CastOp::areCastCompatible(resultBuffer->getType(),
112 *resultMemRefType) &&
113 "CallOp::bufferize: cast incompatible");
114 replaceOpWithNewBufferizedOp<memref::CastOp>(
115 rewriter, op, *resultMemRefType, *resultBuffer);
122struct CollapseShapeOpInterface
123 :
public BufferizableOpInterface::ExternalModel<CollapseShapeOpInterface,
124 tensor::CollapseShapeOp> {
125 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
126 const AnalysisState &state)
const {
134 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
135 const AnalysisState &state)
const {
139 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
140 const AnalysisState &state)
const {
142 return {{op->
getOpResult(0), BufferRelation::Equivalent}};
145 FailureOr<BufferLikeType>
147 const BufferizationState &state,
148 SmallVector<Value> &invocationStack)
const {
149 auto collapseShapeOp = cast<tensor::CollapseShapeOp>(op);
150 auto maybeSrcBufferType = bufferization::getBufferType(
151 collapseShapeOp.getSrc(),
options, state, invocationStack);
152 if (
failed(maybeSrcBufferType))
154 auto srcBufferType = llvm::cast<MemRefType>(*maybeSrcBufferType);
155 bool canBeCollapsed = memref::CollapseShapeOp::isGuaranteedCollapsible(
156 srcBufferType, collapseShapeOp.getReassociationIndices());
158 if (!canBeCollapsed) {
160 RankedTensorType tensorResultType = collapseShapeOp.getResultType();
161 return cast<BufferLikeType>(
162 bufferization::getMemRefTypeWithStaticIdentityLayout(
163 tensorResultType, srcBufferType.getMemorySpace()));
166 return cast<BufferLikeType>(memref::CollapseShapeOp::computeCollapsedType(
167 srcBufferType, collapseShapeOp.getReassociationIndices()));
170 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
171 const BufferizationOptions &
options,
172 BufferizationState &state)
const {
173 auto collapseShapeOp = cast<tensor::CollapseShapeOp>(op);
174 RankedTensorType tensorResultType = collapseShapeOp.getResultType();
175 FailureOr<Value> maybeBuffer =
176 getBuffer(rewriter, collapseShapeOp.getSrc(),
options, state);
179 Value buffer = *maybeBuffer;
180 auto bufferType = cast<MemRefType>(buffer.
getType());
182 if (tensorResultType.getRank() == 0) {
184 MemRefType resultType;
186 if (bufferType.getLayout().isIdentity()) {
188 MemRefLayoutAttrInterface layout;
189 resultType = MemRefType::get({}, tensorResultType.getElementType(),
190 layout, bufferType.getMemorySpace());
194 SmallVector<int64_t> strides;
196 if (
failed(bufferType.getStridesAndOffset(strides, offset)))
198 resultType = MemRefType::get(
199 {}, tensorResultType.getElementType(),
200 StridedLayoutAttr::get(op->
getContext(), offset, {}),
201 bufferType.getMemorySpace());
204 replaceOpWithNewBufferizedOp<memref::CollapseShapeOp>(
205 rewriter, op, resultType, buffer, collapseShapeOp.getReassociation());
212 bool canBeCollapsed = memref::CollapseShapeOp::isGuaranteedCollapsible(
213 bufferType, collapseShapeOp.getReassociationIndices());
214 if (!canBeCollapsed) {
216 AnalysisState analysisState(
options);
217 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
218 rewriter, op->
getLoc(), collapseShapeOp.getSrc(),
options, state);
222 MemRefType::get(collapseShapeOp.getSrcType().getShape(),
223 collapseShapeOp.getSrcType().getElementType(),
224 AffineMap(), bufferType.getMemorySpace());
225 buffer = bufferization::ToBufferOp::create(rewriter, op->
getLoc(),
226 memrefType, *tensorAlloc);
230 replaceOpWithNewBufferizedOp<memref::CollapseShapeOp>(
231 rewriter, op, buffer, collapseShapeOp.getReassociationIndices());
238 :
public BufferizableOpInterface::ExternalModel<DimOpInterface,
240 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
241 const AnalysisState &state)
const {
246 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
247 const AnalysisState &state)
const {
251 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
252 const AnalysisState &state)
const {
256 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
257 const BufferizationOptions &
options,
258 BufferizationState &state)
const {
259 auto dimOp = cast<tensor::DimOp>(op);
260 FailureOr<Value> v = getBuffer(rewriter, dimOp.getSource(),
options, state);
263 replaceOpWithNewBufferizedOp<memref::DimOp>(rewriter, op, *v,
270struct EmptyOpInterface
271 :
public BufferizableOpInterface::ExternalModel<EmptyOpInterface,
273 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
275 bool resultBufferizesToMemoryWrite(Operation *op, OpResult opResult,
276 const AnalysisState &state)
const {
281 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
282 const BufferizationOptions &
options,
283 BufferizationState &state)
const {
284 auto emptyOp = cast<tensor::EmptyOp>(op);
293 FailureOr<Value> allocTensor = allocateTensorForShapedValue(
304struct ExpandShapeOpInterface
305 :
public BufferizableOpInterface::ExternalModel<ExpandShapeOpInterface,
306 tensor::ExpandShapeOp> {
307 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
308 const AnalysisState &state)
const {
314 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
315 const AnalysisState &state)
const {
319 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
320 const AnalysisState &state)
const {
321 return {{op->
getOpResult(0), BufferRelation::Equivalent}};
324 FailureOr<BufferLikeType>
326 const BufferizationState &state,
327 SmallVector<Value> &invocationStack)
const {
328 auto expandShapeOp = cast<tensor::ExpandShapeOp>(op);
329 auto maybeSrcBufferType = bufferization::getBufferType(
330 expandShapeOp.getSrc(),
options, state, invocationStack);
331 if (
failed(maybeSrcBufferType))
333 auto srcBufferType = llvm::cast<MemRefType>(*maybeSrcBufferType);
334 auto maybeResultType = memref::ExpandShapeOp::computeExpandedType(
335 srcBufferType, expandShapeOp.getResultType().getShape(),
336 expandShapeOp.getReassociationIndices());
337 if (
failed(maybeResultType))
339 return cast<BufferLikeType>(*maybeResultType);
342 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
343 const BufferizationOptions &
options,
344 BufferizationState &state)
const {
345 auto expandShapeOp = cast<tensor::ExpandShapeOp>(op);
346 FailureOr<BufferLikeType> maybeResultType =
347 bufferization::getBufferType(expandShapeOp.getResult(),
options, state);
348 if (
failed(maybeResultType))
350 FailureOr<Value> buffer =
351 getBuffer(rewriter, expandShapeOp.getSrc(),
options, state);
355 auto memrefExpandShape = memref::ExpandShapeOp::create(
356 rewriter, op->
getLoc(), *maybeResultType, *buffer,
357 expandShapeOp.getReassociationIndices(),
358 expandShapeOp.getMixedOutputShape());
359 replaceOpWithBufferizedValues(rewriter, op,
360 memrefExpandShape->getResults());
366struct ExtractSliceOpInterface
367 :
public BufferizableOpInterface::ExternalModel<ExtractSliceOpInterface,
368 tensor::ExtractSliceOp> {
369 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
370 const AnalysisState &state)
const {
374 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
375 const AnalysisState &state)
const {
379 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
380 const AnalysisState &state)
const {
381 return {{op->
getOpResult(0), BufferRelation::Unknown}};
384 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
385 const BufferizationOptions &
options,
386 BufferizationState &state)
const {
387 auto extractSliceOp = cast<tensor::ExtractSliceOp>(op);
388 SmallVector<OpFoldResult> mixedOffsets = extractSliceOp.getMixedOffsets();
389 SmallVector<OpFoldResult> mixedSizes = extractSliceOp.getMixedSizes();
390 SmallVector<OpFoldResult> mixedStrides = extractSliceOp.getMixedStrides();
391 Location loc = extractSliceOp.getLoc();
394 FailureOr<Value> srcMemref =
395 getBuffer(rewriter, extractSliceOp.getSource(),
options, state);
400 auto resultMemrefType = bufferization::getBufferType(
401 extractSliceOp.getResult(),
options, state);
402 if (
failed(resultMemrefType))
404 Value subView = memref::SubViewOp::create(
405 rewriter, loc, llvm::cast<MemRefType>(*resultMemrefType), *srcMemref,
406 mixedOffsets, mixedSizes, mixedStrides);
408 replaceOpWithBufferizedValues(rewriter, op, subView);
412 FailureOr<BufferLikeType>
414 const BufferizationState &state,
415 SmallVector<Value> &invocationStack)
const {
416 auto extractSliceOp = cast<tensor::ExtractSliceOp>(op);
417 assert(value == extractSliceOp.getResult() &&
"invalid value");
418 auto srcMemrefType = bufferization::getBufferType(
419 extractSliceOp.getSource(),
options, state, invocationStack);
420 if (
failed(srcMemrefType))
422 SmallVector<OpFoldResult> mixedOffsets = extractSliceOp.getMixedOffsets();
423 SmallVector<OpFoldResult> mixedSizes = extractSliceOp.getMixedSizes();
424 SmallVector<OpFoldResult> mixedStrides = extractSliceOp.getMixedStrides();
425 return cast<BufferLikeType>(memref::SubViewOp::inferRankReducedResultType(
426 extractSliceOp.getType().getShape(),
427 llvm::cast<MemRefType>(*srcMemrefType), mixedOffsets, mixedSizes,
433struct ExtractOpInterface
434 :
public BufferizableOpInterface::ExternalModel<ExtractOpInterface,
436 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
437 const AnalysisState &state)
const {
441 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
442 const AnalysisState &state)
const {
446 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
447 const AnalysisState &state)
const {
451 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
452 const BufferizationOptions &
options,
453 BufferizationState &state)
const {
454 auto extractOp = cast<tensor::ExtractOp>(op);
455 FailureOr<Value> srcMemref =
456 getBuffer(rewriter, extractOp.getTensor(),
options, state);
459 replaceOpWithNewBufferizedOp<memref::LoadOp>(rewriter, op, *srcMemref,
460 extractOp.getIndices());
467static void createStores(RewriterBase &rewriter, Location loc,
int dim,
468 Value buffer, ArrayRef<int64_t> shape,
469 ArrayRef<Value> constants,
470 OperandRange::iterator &elementIt,
471 SmallVectorImpl<Value> &
indices) {
472 if (dim ==
static_cast<int>(shape.size()) - 1) {
473 for (
int i = 0; i < shape.back(); ++i) {
475 memref::StoreOp::create(rewriter, loc, *elementIt, buffer,
indices);
480 for (
int i = 0; i < shape[dim]; ++i) {
482 createStores(rewriter, loc, dim + 1, buffer, shape, constants, elementIt,
488struct FromElementsOpInterface
489 :
public BufferizableOpInterface::ExternalModel<FromElementsOpInterface,
490 tensor::FromElementsOp> {
492 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
494 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
495 const BufferizationOptions &
options,
496 BufferizationState &state)
const {
497 auto fromElementsOp = cast<tensor::FromElementsOp>(op);
498 auto tensorType = cast<RankedTensorType>(fromElementsOp.getType());
501 Location loc = op->
getLoc();
502 auto shape = tensorType.getShape();
504 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
505 rewriter, loc, fromElementsOp.getResult(),
options, state,
509 FailureOr<BufferLikeType> memrefType =
510 bufferization::getBufferType(*tensorAlloc,
options, state);
513 Value buffer = bufferization::ToBufferOp::create(rewriter, op->
getLoc(),
514 *memrefType, *tensorAlloc);
517 if (fromElementsOp.getElements().empty()) {
518 replaceOpWithBufferizedValues(rewriter, op, buffer);
524 memref::StoreOp::create(rewriter, loc,
525 fromElementsOp.getElements().front(), buffer);
526 replaceOpWithBufferizedValues(rewriter, op, buffer);
531 auto maxDim = *llvm::max_element(shape);
532 SmallVector<Value, 2> constants;
533 constants.reserve(maxDim);
534 for (
int i = 0; i < maxDim; ++i)
538 auto elementIt = fromElementsOp.getElements().begin();
539 SmallVector<Value, 2>
indices(tensorType.getRank(), constants[0]);
540 createStores(rewriter, loc, 0, buffer, shape, constants, elementIt,
543 replaceOpWithBufferizedValues(rewriter, op, buffer);
570static Value lowerGenerateLikeOpBody(RewriterBase &rewriter, Location loc,
571 Value tensorDestination,
573 Region &generateBody) {
574 assert(generateBody.
hasOneBlock() &&
"expected body with single block");
575 auto tensorType = cast<RankedTensorType>(tensorDestination.
getType());
580 OpBuilder::InsertionGuard g(rewriter);
582 linalg::MapOp::create(rewriter, loc, tensorType,
ValueRange(),
584 Block &linalgBody = linalgOp.getMapper().emplaceBlock();
585 linalgBody.
addArgument(tensorType.getElementType(), loc);
590 for (int64_t dim = 0; dim < tensorType.getRank(); ++dim)
591 indices.push_back(linalg::IndexOp::create(rewriter, loc, dim));
595 auto yieldOp = cast<tensor::YieldOp>(linalgBody.
getTerminator());
598 return linalgOp.getResult()[0];
602struct GenerateOpInterface
603 :
public BufferizableOpInterface::ExternalModel<GenerateOpInterface,
604 tensor::GenerateOp> {
606 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
608 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
609 const BufferizationOptions &
options,
610 BufferizationState &state)
const {
611 auto generateOp = cast<tensor::GenerateOp>(op);
613 auto type = generateOp.getResult().getType();
616 if (
options.defaultMemorySpaceFn(cast<TensorLikeType>(type)) != Attribute())
617 return op->
emitError(
"memory space not implemented yet");
620 Location loc = op->
getLoc();
621 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
622 rewriter, loc, generateOp.getResult(),
options, state,
627 Value
result = lowerGenerateLikeOpBody(rewriter, loc, *tensorAlloc,
628 generateOp.getDynamicExtents(),
629 generateOp.getBody());
640struct InsertOpInterface
641 :
public DstBufferizableOpInterfaceExternalModel<InsertOpInterface,
643 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
644 const BufferizationOptions &
options,
645 BufferizationState &state)
const {
646 auto insertOp = cast<tensor::InsertOp>(op);
647 FailureOr<Value> destMemref =
648 getBuffer(rewriter, insertOp.getDest(),
options, state);
651 memref::StoreOp::create(rewriter, insertOp.getLoc(), insertOp.getScalar(),
652 *destMemref, insertOp.getIndices());
653 replaceOpWithBufferizedValues(rewriter, op, *destMemref);
658template <
typename InsertOpTy>
659static bool insertSliceOpRequiresRead(InsertOpTy insertSliceOp,
660 OpOperand &opOperand) {
662 if (opOperand == insertSliceOp.getSourceMutable())
666 assert(opOperand == insertSliceOp.getDestMutable() &&
"expected dest");
670 bool allOffsetsZero =
671 llvm::all_of(insertSliceOp.getMixedOffsets(),
isZeroInteger);
672 RankedTensorType destType = insertSliceOp.getDestType();
673 bool sizesMatchDestSizes =
677 return !(allOffsetsZero && sizesMatchDestSizes && allStridesOne);
685struct InsertSliceOpInterface
686 :
public DstBufferizableOpInterfaceExternalModel<InsertSliceOpInterface,
687 tensor::InsertSliceOp> {
688 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
689 const AnalysisState &state)
const {
690 return insertSliceOpRequiresRead(cast<tensor::InsertSliceOp>(op),
694 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
695 const BufferizationOptions &
options,
696 BufferizationState &state)
const {
702 auto insertSliceOp = cast<tensor::InsertSliceOp>(op);
703 SmallVector<OpFoldResult> mixedOffsets = insertSliceOp.getMixedOffsets();
704 SmallVector<OpFoldResult> mixedSizes = insertSliceOp.getMixedSizes();
705 SmallVector<OpFoldResult> mixedStrides = insertSliceOp.getMixedStrides();
706 Location loc = insertSliceOp.getLoc();
709 FailureOr<Value> dstMemref =
710 getBuffer(rewriter, insertSliceOp.getDest(),
options, state);
715 auto dstMemrefType = cast<MemRefType>(dstMemref->getType());
716 MemRefType subviewMemRefType =
717 memref::SubViewOp::inferRankReducedResultType(
718 insertSliceOp.getSourceType().getShape(), dstMemrefType,
719 mixedOffsets, mixedSizes, mixedStrides);
721 memref::SubViewOp::create(rewriter, loc, subviewMemRefType, *dstMemref,
722 mixedOffsets, mixedSizes, mixedStrides);
726 FailureOr<Value> srcMemref =
727 getBuffer(rewriter, insertSliceOp.getSource(),
options, state);
730 if (
failed(
options.memCpyFn(rewriter, loc, *srcMemref, subView)))
733 replaceOpWithBufferizedValues(rewriter, op, *dstMemref);
743 :
public BufferizableOpInterface::ExternalModel<PadOpInterface,
745 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
747 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
748 const AnalysisState &state)
const {
752 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
753 const AnalysisState &state)
const {
757 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
758 const AnalysisState &state)
const {
762 FailureOr<BufferLikeType>
764 const BufferizationState &state,
765 SmallVector<Value> &invocationStack)
const {
767 auto padOp = cast<tensor::PadOp>(op);
768 auto maybeSrcBufferType =
769 bufferization::detail::asMemRefType(bufferization::getBufferType(
770 padOp.getSource(),
options, state, invocationStack));
771 if (
failed(maybeSrcBufferType))
773 MemRefLayoutAttrInterface layout;
774 return cast<BufferLikeType>(
775 MemRefType::get(padOp.getResultType().getShape(),
776 padOp.getResultType().getElementType(), layout,
777 maybeSrcBufferType->getMemorySpace()));
780 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
781 const BufferizationOptions &
options,
782 BufferizationState &state)
const {
783 auto padOp = cast<tensor::PadOp>(op);
784 Location loc = padOp.getLoc();
785 RankedTensorType resultType = padOp.getResultType();
786 RankedTensorType srcType = padOp.getSourceType();
788 auto toValue = [&](OpFoldResult ofr) {
789 if (
auto value = dyn_cast<Value>(ofr))
797 SmallVector<OpFoldResult> mixedLowPad = padOp.getMixedLowPad();
798 SmallVector<OpFoldResult> mixedHighPad = padOp.getMixedHighPad();
799 SmallVector<Value> dynamicSizes;
800 for (int64_t i = 0; i < resultType.getRank(); ++i) {
801 if (!resultType.isDynamicDim(i))
803 Value srcDim = tensor::DimOp::create(rewriter, loc, padOp.getSource(), i);
804 Value lowPad = toValue(mixedLowPad[i]);
805 Value highPad = toValue(mixedHighPad[i]);
806 AffineExpr s0, s1, s2;
808 AffineExpr sumExpr = s0 + s1 + s2;
809 Value sum = affine::AffineApplyOp::create(
810 rewriter, loc, sumExpr,
ValueRange{srcDim, lowPad, highPad});
811 dynamicSizes.push_back(sum);
815 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
816 rewriter, loc, padOp.getResult(),
options, state,
824 Value filledBuffer = lowerGenerateLikeOpBody(
825 rewriter, loc, *tensorAlloc, dynamicSizes, padOp.getBodyRegion());
828 SmallVector<OpFoldResult> sliceSizes =
830 SmallVector<OpFoldResult> sliceStrides(srcType.getRank(),
833 padOp, padOp.getSource(), filledBuffer,
834 padOp.getMixedLowPad(), sliceSizes, sliceStrides);
841struct RankOpInterface
842 :
public BufferizableOpInterface::ExternalModel<RankOpInterface,
844 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
845 const AnalysisState &state)
const {
850 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
851 const AnalysisState &state)
const {
855 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
856 const AnalysisState &state)
const {
860 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
861 const BufferizationOptions &
options,
862 BufferizationState &state)
const {
863 auto rankOp = cast<tensor::RankOp>(op);
865 getBuffer(rewriter, rankOp.getTensor(),
options, state);
868 replaceOpWithNewBufferizedOp<memref::RankOp>(rewriter, op, rankOp.getType(),
875struct ReshapeOpInterface
876 :
public BufferizableOpInterface::ExternalModel<ReshapeOpInterface,
878 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
879 const AnalysisState &state)
const {
881 auto reshapeOp = cast<tensor::ReshapeOp>(op);
882 return opOperand == reshapeOp.getShapeMutable();
885 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
886 const AnalysisState &state)
const {
890 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
891 const AnalysisState &state)
const {
893 auto reshapeOp = cast<tensor::ReshapeOp>(op);
894 if (reshapeOp.getSourceMutable() != opOperand)
896 return {{op->
getOpResult(0), BufferRelation::Equivalent}};
899 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
900 const BufferizationOptions &
options,
901 BufferizationState &state)
const {
902 auto reshapeOp = cast<tensor::ReshapeOp>(op);
903 FailureOr<Value> srcBuffer =
904 getBuffer(rewriter, reshapeOp.getSource(),
options, state);
905 FailureOr<Value> shapeBuffer =
906 getBuffer(rewriter, reshapeOp.getShape(),
options, state);
909 auto maybeResultMemRefType =
910 bufferization::getBufferType(reshapeOp.getResult(),
options, state);
911 if (
failed(maybeResultMemRefType))
917 auto srcType = llvm::dyn_cast<MemRefType>(srcBuffer->getType());
918 if (srcType && !srcType.getLayout().isIdentity()) {
919 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
920 rewriter, op->
getLoc(), reshapeOp.getSource(),
options, state);
923 auto memrefType = MemRefType::get(
924 srcType.getShape(), srcType.getElementType(), AffineMap(),
925 cast<BaseMemRefType>(srcBuffer->getType()).getMemorySpace());
926 srcBuffer = bufferization::ToBufferOp::create(rewriter, op->
getLoc(),
927 memrefType, *tensorAlloc)
931 replaceOpWithNewBufferizedOp<memref::ReshapeOp>(
932 rewriter, op, maybeResultMemRefType.value(), *srcBuffer, *shapeBuffer);
936 FailureOr<BufferLikeType>
938 const BufferizationState &state,
939 SmallVector<Value> &invocationStack)
const {
940 auto reshapeOp = cast<tensor::ReshapeOp>(op);
941 assert(value == reshapeOp.getResult() &&
"unexpected value provided");
942 auto maybeSourceBufferType = bufferization::getBufferType(
943 reshapeOp.getSource(),
options, state, invocationStack);
944 if (
failed(maybeSourceBufferType))
946 return cast<BufferLikeType>(getMemRefTypeWithStaticIdentityLayout(
947 reshapeOp.getResult().getType(),
948 cast<BaseMemRefType>(maybeSourceBufferType.value()).getMemorySpace()));
953struct ParallelInsertSliceOpInterface
954 :
public BufferizableOpInterface::ExternalModel<
955 ParallelInsertSliceOpInterface, ParallelInsertSliceOp> {
956 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
957 const AnalysisState &state)
const {
961 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
962 const AnalysisState &state)
const {
963 return opOperand == cast<ParallelInsertSliceOp>(op).getSourceMutable();
966 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
967 const AnalysisState &state)
const {
968 auto parallelInsertSliceOp = cast<ParallelInsertSliceOp>(op);
969 return opOperand == parallelInsertSliceOp.getDestMutable();
972 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
973 const BufferizationOptions &
options,
974 BufferizationState &state)
const {
975 OpBuilder::InsertionGuard g(rewriter);
976 auto parallelInsertSliceOp = cast<ParallelInsertSliceOp>(op);
977 InParallelOpInterface parallelCombiningParent =
978 parallelInsertSliceOp.getParallelCombiningParent();
984 FailureOr<Value> destBuffer =
985 getBuffer(rewriter, parallelInsertSliceOp.getDest(),
options, state);
988 FailureOr<Value> srcBuffer =
989 getBuffer(rewriter, parallelInsertSliceOp.getSource(),
options, state);
994 auto destBufferType = cast<MemRefType>(destBuffer->getType());
995 MemRefType subviewMemRefType =
996 memref::SubViewOp::inferRankReducedResultType(
997 parallelInsertSliceOp.getSourceType().getShape(), destBufferType,
998 parallelInsertSliceOp.getMixedOffsets(),
999 parallelInsertSliceOp.getMixedSizes(),
1000 parallelInsertSliceOp.getMixedStrides());
1001 Value subview = memref::SubViewOp::create(
1002 rewriter, parallelInsertSliceOp.getLoc(), subviewMemRefType,
1003 *destBuffer, parallelInsertSliceOp.getMixedOffsets(),
1004 parallelInsertSliceOp.getMixedSizes(),
1005 parallelInsertSliceOp.getMixedStrides());
1008 if (
failed(
options.memCpyFn(rewriter, parallelInsertSliceOp.getLoc(),
1009 *srcBuffer, subview)))
1019 for (Operation *user : srcBuffer->getUsers()) {
1021 if (user->getBlock() == parallelCombiningParent->getBlock())
1022 rewriter.
moveOpBefore(user, user->getBlock()->getTerminator());
1035 resolveConflicts(Operation *op, RewriterBase &rewriter,
1036 const AnalysisState &analysisState,
1037 const BufferizationState &bufferizationState)
const {
1044struct SplatOpInterface
1045 :
public BufferizableOpInterface::ExternalModel<SplatOpInterface,
1048 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
1050 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
1051 const BufferizationOptions &
options,
1052 BufferizationState &state)
const {
1053 OpBuilder::InsertionGuard g(rewriter);
1054 auto splatOp = cast<tensor::SplatOp>(op);
1057 Location loc = op->
getLoc();
1058 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
1059 rewriter, loc, splatOp.getResult(),
options, state,
1065 auto tensorType = cast<RankedTensorType>(tensorAlloc->getType());
1068 if (
options.defaultMemorySpaceFn(cast<TensorLikeType>(tensorType)) !=
1070 return op->
emitError(
"memory space not implemented yet");
1072 auto linalgOp = linalg::MapOp::create(rewriter, loc, tensorType,
1075 Block &linalgBody = linalgOp.getMapper().emplaceBlock();
1076 linalgBody.
addArgument(tensorType.getElementType(), loc);
1080 linalg::YieldOp::create(rewriter, loc, splatOp.getInput());
1081 rewriter.
replaceOp(splatOp, linalgOp.getResult()[0]);
1090struct ConcatOpInterface
1091 :
public BufferizableOpInterface::ExternalModel<ConcatOpInterface,
1094 bool bufferizesToAllocation(Operation *op, Value value)
const {
return true; }
1096 bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
1097 const AnalysisState &state)
const {
1101 bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
1102 const AnalysisState &state)
const {
1106 AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
1107 const AnalysisState &state)
const {
1111 LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
1112 const BufferizationOptions &
options,
1113 BufferizationState &state)
const {
1114 OpBuilder::InsertionGuard g(rewriter);
1115 auto concatOp = cast<tensor::ConcatOp>(op);
1118 Location loc = op->
getLoc();
1119 FailureOr<Value> tensorAlloc = allocateTensorForShapedValue(
1120 rewriter, loc, concatOp.getResult(),
options, state,
1124 auto tensorType = cast<RankedTensorType>(tensorAlloc->getType());
1125 FailureOr<BufferLikeType> memrefType =
1126 bufferization::getBufferType(*tensorAlloc,
options, state);
1129 Value dstBuffer = bufferization::ToBufferOp::create(
1130 rewriter, op->
getLoc(), *memrefType, *tensorAlloc);
1133 uint64_t concatDim = concatOp.getDim();
1135 SmallVector<OpFoldResult> offsets(tensorType.getRank(),
1137 SmallVector<OpFoldResult> strides(tensorType.getRank(),
1139 SmallVector<OpFoldResult> sizes =
1144 auto sum = [&](OpFoldResult v1, OpFoldResult v2) {
1149 OpFoldResult concatDimOffset = rewriter.
getIndexAttr(0);
1150 for (
auto operand : concatOp.getInputs()) {
1152 FailureOr<Value> srcBuffer = getBuffer(rewriter, operand,
options, state);
1159 auto operandTensorType = cast<RankedTensorType>(operand.getType());
1160 offsets[concatDim] = concatDimOffset;
1161 OpFoldResult concatDimSize =
1163 sizes[concatDim] = concatDimSize;
1166 auto dstMemrefType = cast<MemRefType>(*memrefType);
1167 MemRefType subviewMemRefType =
1168 memref::SubViewOp::inferRankReducedResultType(
1169 operandTensorType.getShape(), dstMemrefType, offsets, sizes,
1171 Value subview = memref::SubViewOp::create(
1172 rewriter, loc, subviewMemRefType, dstBuffer, offsets, sizes, strides);
1175 if (
failed(
options.memCpyFn(rewriter, loc, *srcBuffer, subview)))
1178 concatDimOffset = sum(concatDimOffset, concatDimSize);
1181 replaceOpWithBufferizedValues(rewriter, op, dstBuffer);
1193 CastOp::attachInterface<CastOpInterface>(*ctx);
1194 CollapseShapeOp::attachInterface<CollapseShapeOpInterface>(*ctx);
1195 ConcatOp::attachInterface<ConcatOpInterface>(*ctx);
1196 DimOp::attachInterface<DimOpInterface>(*ctx);
1197 EmptyOp::attachInterface<EmptyOpInterface>(*ctx);
1198 ExpandShapeOp::attachInterface<ExpandShapeOpInterface>(*ctx);
1199 ExtractSliceOp::attachInterface<ExtractSliceOpInterface>(*ctx);
1200 ExtractOp::attachInterface<ExtractOpInterface>(*ctx);
1201 FromElementsOp::attachInterface<FromElementsOpInterface>(*ctx);
1202 GenerateOp::attachInterface<GenerateOpInterface>(*ctx);
1203 InsertOp::attachInterface<InsertOpInterface>(*ctx);
1204 InsertSliceOp::attachInterface<InsertSliceOpInterface>(*ctx);
1205 PadOp::attachInterface<PadOpInterface>(*ctx);
1206 ParallelInsertSliceOp::attachInterface<ParallelInsertSliceOpInterface>(
1208 RankOp::attachInterface<RankOpInterface>(*ctx);
1209 ReshapeOp::attachInterface<ReshapeOpInterface>(*ctx);
1210 SplatOp::attachInterface<SplatOpInterface>(*ctx);
1213 ctx->
loadDialect<arith::ArithDialect, linalg::LinalgDialect>();
static llvm::ManagedStatic< PassManagerOptions > options
template bool mlir::hasEffect< MemoryEffects::Free >(Operation *)
static RankedTensorType getBufferType(const SparseTensorType &stt, bool needTmpCOO)
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
IntegerAttr getIndexAttr(int64_t value)
MLIRContext * getContext() const
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
MLIRContext is the top-level object for a collection of MLIR operations.
void loadDialect()
Load a dialect in the context.
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.
OpResult getOpResult(unsigned idx)
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
use_range getUses()
Returns a range of all uses, which is useful for iterating over all uses.
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumArguments()
bool hasOneBlock()
Return true if this region has exactly one block.
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 moveOpBefore(Operation *op, Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void mergeBlocks(Block *source, Block *dest, ValueRange argValues={})
Inline the operations of block 'source' into the end of block 'dest'.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Type getType() const
Return the type of this value.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
OpFoldResult makeComposedFoldedAffineApply(OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands, bool composeAffineMin=false)
Constructs an AffineApplyOp that applies map to operands after composing the map with the maps of any...
OpFoldResult getMixedSize(OpBuilder &builder, Location loc, Value value, int64_t dim)
Return the dimension of the given memref value.
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given memref value.
void registerSubsetOpInterfaceExternalModels(DialectRegistry ®istry)
void registerBufferizableOpInterfaceExternalModels(DialectRegistry ®istry)
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given tensor value.
Include the generated interface declarations.
bool areConstantIntValues(ArrayRef< OpFoldResult > ofrs, ArrayRef< int64_t > values)
Return true if all of ofrs are constant integers equal to the corresponding value in values.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
bool areAllConstantIntValue(ArrayRef< OpFoldResult > ofrs, int64_t value)
Return true if all of ofrs are constant integers equal to value.
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .