[Mlir-commits] [mlir] [mlir][linalg] Document and diagnose pack/unpack memref limits (PR #225773)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Sep 23 06:50:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Federico Bruzzone (FedericoBruzzone)
<details>
<summary>Changes</summary>
Scoped down from the [original RFC](https://discourse.llvm.org/t/rfc-transformation-support-for-linalg-pack-linalg-unpack-on-memrefs/91832) per discussion in #<!-- -->225650.
- Replace/add the `// TODO: Support Memref Pack/UnPackOp...` comment across all sites with a comment stating the actual invariant, pointing to #<!-- -->225650 for the reasoning.
- Document the invariant in the `Linalg_PackOp`/`Linalg_UnPackOp` descriptions.
- Emit a dedicated diagnostic from `structured.pack`, `lower_pack`, `lower_unpack`, and tiling when the target has memref operands, instead of a generic/silent failure.
- Add test coverage for the new diagnostics, previously untested.
---
Patch is 28.54 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/225773.diff
11 Files Affected:
- (modified) mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td (+10)
- (modified) mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp (+12-5)
- (modified) mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp (+39)
- (modified) mlir/lib/Dialect/Linalg/Transforms/BlockPackMatmul.cpp (+2-1)
- (modified) mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp (+16)
- (modified) mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp (+18-9)
- (modified) mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp (+8-4)
- (modified) mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp (+8-4)
- (modified) mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp (+4-2)
- (modified) mlir/test/Dialect/Linalg/transform-lower-pack.mlir (+43)
- (modified) mlir/test/Dialect/Linalg/transform-op-pack.mlir (+39-1)
``````````diff
diff --git a/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td b/mlir/include/mlir/Dialect/Linalg/IR/LinalgRelayoutOps.td
index 95383e6262f71..b40549a278c69 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 87b14439597b4..51b5f4a30484c 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,8 @@ 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 +6638,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 +6756,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 +6789,8 @@ 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 16b03ab5426a0..d2fae01b1e23e 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 1f4cda459e738..d5f44152af545 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 d36ca43a6cbb3..48531e7005d36 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp
@@ -572,6 +572,8 @@ 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 +600,8 @@ 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 +774,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 +884,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 +972,8 @@ 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 +1027,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 +1106,8 @@ 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 +1310,8 @@ 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 c8e9f021938e5..9389eac96afb0 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/PackAndUnpackPatterns.cpp
@@ -154,7 +154,8 @@ 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 +220,8 @@ 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 +325,8 @@ 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 +392,8 @@ 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 +456,8 @@ 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 +522,8 @@ 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 +575,8 @@ 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 +644,8 @@ 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 +673,8 @@ 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 bbb23c00e5e19..3a6d5d9229aeb 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp
@@ -1130,7 +1130,8 @@ 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 +1506,8 @@ 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 +1725,8 @@ 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 +1979,8 @@ 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 a2d16c0a5b7d4..c3276f9aacdd4 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,
...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/225773
More information about the Mlir-commits
mailing list