[Mlir-commits] [mlir] [mlir][linalg] Document and diagnose pack/unpack memref limits (PR #225773)
Federico Bruzzone
llvmlistbot at llvm.org
Wed Sep 23 07:01:13 PDT 2026
https://github.com/FedericoBruzzone updated https://github.com/llvm/llvm-project/pull/225773
>From f61c0ebce02c7db37ac4466e2291a4b6754f5458 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Wed, 23 Sep 2026 15:40:54 +0200
Subject: [PATCH] [mlir][linalg] Document and diagnose pack/unpack memref
limits
Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
.../Dialect/Linalg/IR/LinalgRelayoutOps.td | 10 +++++
mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp | 19 +++++---
.../TransformOps/LinalgTransformOps.cpp | 39 +++++++++++++++++
.../Linalg/Transforms/BlockPackMatmul.cpp | 3 +-
.../Transforms/DataLayoutPropagation.cpp | 21 +++++++++
.../Transforms/PackAndUnpackPatterns.cpp | 36 ++++++++++++----
.../Linalg/Transforms/TilingInterfaceImpl.cpp | 16 +++++--
.../Dialect/Linalg/Transforms/Transforms.cpp | 12 ++++--
.../Linalg/Transforms/Vectorization.cpp | 6 ++-
.../Dialect/Linalg/transform-lower-pack.mlir | 43 +++++++++++++++++++
.../Dialect/Linalg/transform-op-pack.mlir | 40 ++++++++++++++++-
11 files changed, 219 insertions(+), 26 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td b/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td
index 95383e6262f713..b40549a278c697 100644
--- a/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td
+++ b/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td
@@ -193,6 +193,11 @@ def Linalg_PackOp : Linalg_RelayoutOp<"pack", [
// \
// expect tensor<2x8xf32> because CeilDiv(9, 8) = 2
```
+
+ Memref semantics: `source` and `dest` may be memrefs, but only as the
+ result of bufferization or of subsequent scalar lowering. Transformations
+ on `linalg.pack` operate on the tensor form only. See
+ #225650 for the reasoning.
}];
let arguments = (ins TensorOrMemRef<[AnyType]>:$source,
TensorOrMemRef<[AnyType]>:$dest,
@@ -357,6 +362,11 @@ def Linalg_UnPackOp : Linalg_RelayoutOp<"unpack"> {
// \ / \ /
// Outer Dims: 9x3x8 Inner Dims: 4x2
```
+
+ Memref semantics: `source` and `dest` may be memrefs, but only as the
+ result of bufferization or of subsequent scalar lowering. Transformations
+ on `linalg.unpack` operate on the tensor form only. See
+ #225650 for the reasoning.
}];
let arguments = (ins TensorOrMemRef<[AnyType]>:$source,
TensorOrMemRef<[AnyType]>:$dest,
diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
index 87b14439597b43..d13ad8ef1e3397 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
@@ -6168,7 +6168,8 @@ static bool inferStaticShape(PackOp packOp, SmallVectorImpl<int64_t> &srcShape,
}
LogicalResult PackOp::canonicalize(PackOp packOp, PatternRewriter &rewriter) {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -6268,6 +6269,8 @@ bool PackOp::isLikePad() {
::mlir::LogicalResult
PackOp::fold(FoldAdaptor adaptor,
::llvm::SmallVectorImpl<OpFoldResult> &results) {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!hasPureTensorSemantics())
return failure();
std::optional<Attribute> paddingValue;
@@ -6301,7 +6304,9 @@ struct FoldTensorCastPackOp : public OpRewritePattern<PackOp> {
LogicalResult matchAndRewrite(PackOp op,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!op.hasPureTensorSemantics())
return failure();
@@ -6634,7 +6639,8 @@ static bool inferStaticShape(UnPackOp op, SmallVectorImpl<int64_t> &srcShape,
LogicalResult UnPackOp::canonicalize(UnPackOp unPackOp,
PatternRewriter &rewriter) {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -6751,7 +6757,8 @@ bool UnPackOp::isLikeUnPad() {
::mlir::LogicalResult
UnPackOp::fold(FoldAdaptor adaptor,
::llvm::SmallVectorImpl<OpFoldResult> &results) {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!hasPureTensorSemantics())
return failure();
@@ -6783,7 +6790,9 @@ struct FoldTensorCastUnPackOp : public OpRewritePattern<UnPackOp> {
LogicalResult matchAndRewrite(UnPackOp op,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!op.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 16b03ab5426a0d..d2fae01b1e23e7 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -1549,6 +1549,11 @@ DiagnosedSilenceableFailure transform::LowerPackOp::applyToOne(
transform::TransformRewriter &rewriter, linalg::PackOp target,
transform::ApplyToEachResultList &transformResults,
transform::TransformState &state) {
+ if (!target.hasPureTensorSemantics()) {
+ return mlir::emitSilenceableFailure(target->getLoc())
+ << "lower_pack only supports tensor semantics. The target has "
+ "memref operands, see #225650";
+ }
rewriter.setInsertionPoint(target);
bool lowerPadLikeWithInsertSlice = getLowerPadLikeWithInsertSlice();
FailureOr<LowerPackResult> res =
@@ -1571,6 +1576,14 @@ DiagnosedSilenceableFailure transform::LowerUnPackOp::applyToOne(
transform::TransformRewriter &rewriter, linalg::UnPackOp target,
transform::ApplyToEachResultList &transformResults,
transform::TransformState &state) {
+ if (!target.hasPureTensorSemantics()) {
+ DiagnosedSilenceableFailure diag =
+ emitSilenceableError()
+ << "lower_unpack only supports tensor semantics. The target has "
+ "memref operands, see #225650";
+ diag.attachNote(target->getLoc()) << "target payload op";
+ return diag;
+ }
rewriter.setInsertionPoint(target);
bool lowerUnpadLikeWithExtractSlice = getLowerUnpadLikeWithExtractSlice();
FailureOr<LowerUnPackOpResult> res =
@@ -1863,6 +1876,12 @@ transform::PackOp::apply(transform::TransformRewriter &rewriter,
<< "requires target to map to exactly 1 LinalgOp (got "
<< llvm::range_size(targetOps) << ")";
}
+ // Fail on memref operands: pack only supports tensor semantics.
+ if (!linalgOp.hasPureTensorSemantics()) {
+ return emitSilenceableError()
+ << "structured.pack only supports tensor semantics. The target "
+ "has memref operands, see #225650";
+ }
// Fail on mismatched number of pack sizes.
if (getMixedPackedSizes().size() != linalgOp.getNumLoops()) {
return emitSilenceableError()
@@ -3727,6 +3746,16 @@ transform::TileUsingForOp::apply(transform::TransformRewriter &rewriter,
diag.attachNote(op->getLoc()) << "target op";
return diag;
}
+ if (auto relayoutOp = dyn_cast<linalg::RelayoutOpInterface>(op);
+ relayoutOp &&
+ !cast<DestinationStyleOpInterface>(op).hasPureTensorSemantics()) {
+ DiagnosedSilenceableFailure diag =
+ emitSilenceableError()
+ << "tiling only supports tensor semantics for linalg.pack / "
+ "linalg.unpack. The target has memref operands, see #225650";
+ diag.attachNote(op->getLoc()) << "target op";
+ return diag;
+ }
int64_t iterspaceRank = tilingInterface.getLoopIteratorTypes().size();
if (tileInterchange.size() > static_cast<size_t>(iterspaceRank)) {
@@ -4046,6 +4075,16 @@ DiagnosedSilenceableFailure transform::tileToForallOpImpl(
diag.attachNote(target->getLoc()) << "target op";
return diag;
}
+ if (auto relayoutOp = dyn_cast<linalg::RelayoutOpInterface>(target);
+ relayoutOp &&
+ !cast<DestinationStyleOpInterface>(target).hasPureTensorSemantics()) {
+ DiagnosedSilenceableFailure diag =
+ transformOp.emitSilenceableError()
+ << "tiling only supports tensor semantics for linalg.pack / "
+ "linalg.unpack. The target has memref operands, see #225650";
+ diag.attachNote(target->getLoc()) << "target op";
+ return diag;
+ }
rewriter.setInsertionPoint(tileableOp);
scf::SCFTilingOptions options;
options.setLoopType(scf::SCFTilingOptions::LoopType::ForallOp);
diff --git a/mlir/lib/Dialect/Linalg/Transforms/BlockPackMatmul.cpp b/mlir/lib/Dialect/Linalg/Transforms/BlockPackMatmul.cpp
index 1f4cda459e738c..d5f44152af545c 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/BlockPackMatmul.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/BlockPackMatmul.cpp
@@ -92,7 +92,8 @@ transposePackedMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp,
linalg::PackOp packOp, AffineMap operandMap,
ArrayRef<unsigned> blocksStartDimPos,
bool transposeOuterBlocks, bool transposeInnerBlocks) {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp b/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp
index d36ca43a6cbb36..6dbbb854176c4d 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp
@@ -572,6 +572,9 @@ struct BubbleUpPackOpThroughGenericOpPattern
LogicalResult matchAndRewrite(linalg::PackOp packOp,
PatternRewriter &rewriter) const override {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -598,6 +601,9 @@ class BubbleUpPackThroughPadOp final : public OpRewritePattern<linalg::PackOp> {
LogicalResult matchAndRewrite(linalg::PackOp packOp,
PatternRewriter &rewriter) const override {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -770,6 +776,8 @@ static LogicalResult
bubbleUpPackOpThroughCollapseShape(tensor::CollapseShapeOp collapseOp,
linalg::PackOp packOp,
PatternRewriter &rewriter) {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -878,6 +886,8 @@ static LogicalResult
bubbleUpPackOpThroughExpandShape(tensor::ExpandShapeOp expandOp,
linalg::PackOp packOp,
PatternRewriter &rewriter) {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -964,6 +974,9 @@ class BubbleUpPackOpThroughReshapeOp final
LogicalResult matchAndRewrite(linalg::PackOp packOp,
PatternRewriter &rewriter) const override {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -1017,6 +1030,8 @@ class BubbleUpPackOpThroughReshapeOp final
static LogicalResult pushDownUnPackOpThroughExpandShape(
linalg::UnPackOp unPackOp, tensor::ExpandShapeOp expandOp,
PatternRewriter &rewriter, ControlPropagationFn controlFn) {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -1094,6 +1109,9 @@ class PushDownUnPackOpThroughReshapeOp final
LogicalResult matchAndRewrite(linalg::UnPackOp unPackOp,
PatternRewriter &rewriter) const override {
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -1296,6 +1314,9 @@ struct PushDownUnPackThroughPadOp : public OpRewritePattern<tensor::PadOp> {
if (!unpackOp)
return failure();
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unpackOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp b/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp
index c8e9f021938e56..7269197cf76b32 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp
@@ -154,7 +154,9 @@ struct SimplifyPackToExpandShape : public OpRewritePattern<PackOp> {
PatternRewriter &rewriter) const override {
if (packOp.getPaddingValue())
return rewriter.notifyMatchFailure(packOp, "expects no padding value");
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -219,7 +221,9 @@ struct SimplifyUnPackToCollapseShape : public OpRewritePattern<UnPackOp> {
LogicalResult matchAndRewrite(UnPackOp unpackOp,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unpackOp.hasPureTensorSemantics())
return failure();
@@ -323,7 +327,9 @@ struct FoldUnpackWithExtractSliceOp
if (!unpackOp)
return failure();
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unpackOp.hasPureTensorSemantics())
return failure();
@@ -389,7 +395,9 @@ struct FoldProducerPackWithConsumerLinalgTransposeOp
if (!packOp)
return failure();
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -452,7 +460,9 @@ struct FoldConsumerPackWithProducerLinalgTransposeOp
LogicalResult matchAndRewrite(PackOp packOp,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -517,7 +527,9 @@ struct FoldProducerUnPackWithConsumerLinalgTransposeOp
if (!unPackOp)
return failure();
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -569,7 +581,9 @@ struct FoldConsumerUnPackWithProducerLinalgTransposeOp
LogicalResult matchAndRewrite(UnPackOp unPackOp,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -637,7 +651,9 @@ struct FoldEmptyTensorWithPackOp : public OpRewritePattern<PackOp> {
LogicalResult matchAndRewrite(PackOp packOp,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -665,7 +681,9 @@ struct FoldEmptyTensorWithUnPackOp : public OpRewritePattern<UnPackOp> {
LogicalResult matchAndRewrite(UnPackOp unPackOp,
PatternRewriter &rewriter) const override {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp
index bbb23c00e5e193..f4688ba7fd219b 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp
@@ -1130,7 +1130,9 @@ struct PackOpTiling
ArrayRef<OpFoldResult> offsets,
ArrayRef<OpFoldResult> sizes) const {
auto packOp = cast<PackOp>(op);
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -1505,7 +1507,9 @@ struct PackOpTiling
ArrayRef<OpFoldResult> sizes(allSizes[0]);
auto packOp = cast<PackOp>(op);
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -1723,7 +1727,9 @@ struct UnPackOpTiling
ArrayRef<OpFoldResult> sizes,
ArrayRef<InnerTileAlignment> innerTileAlignments) const {
auto unpackOp = cast<UnPackOp>(op);
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unpackOp.hasPureTensorSemantics())
return failure();
@@ -1976,7 +1982,9 @@ struct UnPackOpTiling
return failure();
}
auto unPackOp = cast<UnPackOp>(op);
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for
+ // details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp b/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
index a2d16c0a5b7d44..c3276f9aacdd48 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
@@ -221,7 +221,8 @@ struct PackedOperandsDimList {
FailureOr<LowerPackResult> linalg::lowerPack(RewriterBase &rewriter,
linalg::PackOp packOp,
bool lowerPadLikeWithInsertSlice) {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
@@ -355,7 +356,8 @@ FailureOr<LowerPackResult> linalg::lowerPack(RewriterBase &rewriter,
FailureOr<LowerUnPackOpResult>
linalg::lowerUnPack(RewriterBase &rewriter, linalg::UnPackOp unPackOp,
bool lowerUnpadLikeWithExtractSlice) {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!unPackOp.hasPureTensorSemantics())
return failure();
@@ -1044,7 +1046,8 @@ LogicalResult ExtractSliceOfPadTensorSwapPattern::matchAndRewrite(
static Value getPackOpSourceOrPaddedSource(OpBuilder &builder,
linalg::PackOp packOp) {
Value input = packOp.getSource();
- // TODO: Support Memref PackOp. Temporarily return just Op Source.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return input;
@@ -1164,7 +1167,8 @@ getPackUnpackRankReducedPerm(ArrayRef<int64_t> shape,
LogicalResult DecomposeOuterUnitDimsPackOpPattern::matchAndRewrite(
linalg::PackOp packOp, PatternRewriter &rewriter) const {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index bb620641951dc6..ec59433182d26a 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -1937,7 +1937,8 @@ vectorizeDynamicLinalgOpPrecondition(linalg::LinalgOp op,
static LogicalResult
vectorizeUnPackOpPrecondition(linalg::UnPackOp unpackOp,
ArrayRef<int64_t> inputVectorSizes) {
- // TODO: Support Memref UnPackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!unpackOp.hasPureTensorSemantics())
return failure();
@@ -2315,7 +2316,8 @@ static LogicalResult vectorizeLinalgOpPrecondition(
static LogicalResult
vectorizePackOpPrecondition(linalg::PackOp packOp,
ArrayRef<int64_t> inputVectorSizes) {
- // TODO: Support Memref PackOp. Temporarily return failure.
+ // Pack/unpack transformations operate at tensor level. The memref form is
+ // only for inline bufferization and scalar lowering, see #225650 for details.
if (!packOp.hasPureTensorSemantics())
return failure();
diff --git a/mlir/test/Dialect/Linalg/transform-lower-pack.mlir b/mlir/test/Dialect/Linalg/transform-lower-pack.mlir
index efe832233f1cc1..9d17d2fa1904b4 100644
--- a/mlir/test/Dialect/Linalg/transform-lower-pack.mlir
+++ b/mlir/test/Dialect/Linalg/transform-lower-pack.mlir
@@ -804,3 +804,46 @@ module attributes {transform.with_named_sequence} {
transform.yield
}
}
+
+// -----
+
+func.func @pack_unsupported_memref(%arg0: memref<128x8xf32>, %arg1: memref<8x8x16x1xf32>) {
+ // expected-error @below {{lower_pack only supports tensor semantics. The target has memref operands}}
+ linalg.pack %arg0 inner_dims_pos = [0, 1] inner_tiles = [16, 1] into %arg1
+ : memref<128x8xf32> -> memref<8x8x16x1xf32>
+ return
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%module_op: !transform.any_op {transform.readonly}) {
+ %pack = transform.structured.match ops{["linalg.pack"]} in %module_op
+ : (!transform.any_op) -> !transform.op<"linalg.pack">
+ transform.structured.lower_pack %pack : (!transform.op<"linalg.pack">)
+ -> (!transform.op<"tensor.pad">, !transform.op<"tensor.expand_shape">, !transform.op<"linalg.transpose">)
+ transform.yield
+ }
+}
+
+// -----
+
+func.func @unpack_unsupported_memref(%arg0: memref<8x8x16x1xf32>, %arg1: memref<128x8xf32>) {
+ // expected-note @below {{target payload op}}
+ linalg.unpack %arg0 inner_dims_pos = [0, 1] inner_tiles = [16, 1] into %arg1
+ : memref<8x8x16x1xf32> -> memref<128x8xf32>
+ return
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%module_op: !transform.any_op {transform.readonly}) {
+ %unpack = transform.structured.match ops{["linalg.unpack"]} in %module_op
+ : (!transform.any_op) -> !transform.op<"linalg.unpack">
+ // expected-error @below {{lower_unpack only supports tensor semantics. The target has memref operands}}
+ transform.structured.lower_unpack %unpack : (!transform.op<"linalg.unpack">)
+ -> (!transform.op<"tensor.empty">,
+ !transform.op<"linalg.transpose">,
+ !transform.op<"tensor.collapse_shape">,
+ !transform.op<"tensor.extract_slice">,
+ !transform.op<"linalg.copy">)
+ transform.yield
+ }
+}
diff --git a/mlir/test/Dialect/Linalg/transform-op-pack.mlir b/mlir/test/Dialect/Linalg/transform-op-pack.mlir
index 13a07cc38e10bf..bf25198ddf6c5b 100644
--- a/mlir/test/Dialect/Linalg/transform-op-pack.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-pack.mlir
@@ -455,7 +455,7 @@ func.func @matmul_unsupported_memref_pack(%A: memref<?x?xf32>,
module attributes {transform.with_named_sequence} {
transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
%0 = transform.structured.match ops{["linalg.matmul"]} in %arg1 : (!transform.any_op) -> !transform.any_op
- // expected-error @below {{data tiling failed}}
+ // expected-error @below {{structured.pack only supports tensor semantics. The target has memref operands}}
%1 = transform.structured.pack %0 packed_sizes = [2, 3, 4]
: (!transform.any_op) -> (!transform.op<"linalg.generic">)
transform.yield
@@ -464,6 +464,44 @@ module attributes {transform.with_named_sequence} {
// -----
+func.func @pack_unsupported_memref_tile_using_for(%arg0: memref<128x256xf32>, %arg1: memref<4x8x32x32xf32>) {
+ // expected-note @below {{target op}}
+ linalg.pack %arg0 inner_dims_pos = [0, 1] inner_tiles = [32, 32] into %arg1
+ : memref<128x256xf32> -> memref<4x8x32x32xf32>
+ return
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.pack"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ // expected-error @below {{tiling only supports tensor semantics for linalg.pack / linalg.unpack. The target has memref operands}}
+ %1, %loops:2 = transform.structured.tile_using_for %0 tile_sizes [2, 4]
+ : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
+ transform.yield
+ }
+}
+
+// -----
+
+func.func @pack_unsupported_memref_tile_using_forall(%arg0: memref<128x256xf32>, %arg1: memref<4x8x32x32xf32>) {
+ // expected-note @below {{target op}}
+ linalg.pack %arg0 inner_dims_pos = [0, 1] inner_tiles = [32, 32] into %arg1
+ : memref<128x256xf32> -> memref<4x8x32x32xf32>
+ return
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+ %0 = transform.structured.match ops{["linalg.pack"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ // expected-error @below {{tiling only supports tensor semantics for linalg.pack / linalg.unpack. The target has memref operands}}
+ %1:2 = transform.structured.tile_using_forall %0 num_threads [2, 4]
+ : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
+ transform.yield
+ }
+}
+
+// -----
+
func.func @no_single_packing_op(%source: tensor<128x256xf32>, %dest: tensor<4x16x32x16xf32>) {
%0 = linalg.pack %source inner_dims_pos = [0, 1] inner_tiles = [32, 16] into %dest : tensor<128x256xf32> -> tensor<4x16x32x16xf32>
%1 = linalg.unpack %0 inner_dims_pos = [0, 1] inner_tiles = [32, 16] into %source : tensor<4x16x32x16xf32> -> tensor<128x256xf32>
More information about the Mlir-commits
mailing list