[Mlir-commits] [mlir] [mlir][linalg] Support non-trailing dropped dims when vectorizing ran… (PR #219192)

Federico Bruzzone llvmlistbot at llvm.org
Thu Aug 27 04:59:16 PDT 2026


https://github.com/FedericoBruzzone created https://github.com/llvm/llvm-project/pull/219192

…

`vectorizeAsInsertSliceOp` inferred a dynamic source dim's vector size from
`resultType.getDimSize(rankDiff + i)`, which only covers the case where the
rank-reducing dims dropped from `resultType` are the leading ones and
`source` maps to the trailing result dims.

Generalize this to the general case, where a dropped unit dim can be
anywhere, by using `sliceOp.getDroppedDims()` to map each source dim to
its actual corresponding (non-dropped) result dim.

>From 07392e83d0e1925dfd9d45a2c3bb78fc3dd22122 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Thu, 27 Aug 2026 13:58:03 +0200
Subject: [PATCH] [mlir][linalg] Support non-trailing dropped dims when
 vectorizing rank-reducing `InsertSliceOp`

Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
 .../Linalg/Transforms/Vectorization.cpp       | 20 +++++++++----
 .../Linalg/vectorization/insert-slice.mlir    | 28 +++++++++++++++++++
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index 21ca3108efcd6..18d3d12e01cd1 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -2979,20 +2979,30 @@ vectorizeAsInsertSliceOp(RewriterBase &rewriter, tensor::InsertSliceOp sliceOp,
   }
 
   // 2. Get the vector shape
+  // Map each source dim to its corresponding (non-dropped) result dim: for a
+  // rank-reducing slice, dropped dims need not be the trailing ones.
+  llvm::SmallBitVector droppedDims = sliceOp.getDroppedDims();
+  SmallVector<int64_t> resultDimsForSourceDims;
+  resultDimsForSourceDims.reserve(sourceType.getRank());
+  for (int64_t resultDim = 0, end = resultType.getRank(); resultDim < end;
+       ++resultDim)
+    if (!droppedDims[resultDim])
+      resultDimsForSourceDims.push_back(resultDim);
+  assert(resultDimsForSourceDims.size() ==
+             static_cast<size_t>(sourceType.getRank()) &&
+         "expected one non-dropped result dim per source dim");
+
   SmallVector<int64_t> vecShape;
-  size_t rankDiff = resultType.getRank() - sourceType.getRank();
   for (int64_t i = 0, end = sourceType.getRank(); i < end; ++i) {
     if (!inputVectorSizes.empty()) {
       vecShape.push_back(inputVectorSizes[i]);
     } else if (!sourceType.isDynamicDim(i)) {
       vecShape.push_back(sourceType.getDimSize(i));
-    } else if (!resultType.isDynamicDim(i)) {
+    } else if (!resultType.isDynamicDim(resultDimsForSourceDims[i])) {
       // Source shape is not statically known, but result shape is.
       // Vectorize with size of result shape. This may be larger than the
       // source size.
-      // FIXME: Using rankDiff implies that the source tensor is inserted at
-      // the end of the destination tensor. However, that's not required.
-      vecShape.push_back(resultType.getDimSize(rankDiff + i));
+      vecShape.push_back(resultType.getDimSize(resultDimsForSourceDims[i]));
     } else {
       // Neither source nor result dim of padOp is static. Cannot vectorize
       // the copy.
diff --git a/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir b/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
index 91ceea3b394c3..c2e4d83b14886 100644
--- a/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
+++ b/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
@@ -88,6 +88,34 @@ func.func private @insert_slice_dynamic_src_dim(%source: tensor<?x3x?x1xi32>, %s
 
 // -----
 
+func.func private @insert_slice_dynamic_src_dim_non_leading_unit_dim_dropped(
+    %source: tensor<?x4xi32>, %size: index) -> tensor<8x1x4xi32> {
+  %pad = arith.constant 0 : i32
+  %empty = tensor.empty() : tensor<8x1x4xi32>
+  %init = linalg.fill ins(%pad : i32) outs(%empty : tensor<8x1x4xi32>) -> tensor<8x1x4xi32>
+  %res = tensor.insert_slice %source into %init[0, 0, 0] [%size, 1, 4] [1, 1, 1] : tensor<?x4xi32> into tensor<8x1x4xi32>
+  return %res : tensor<8x1x4xi32>
+}
+
+// CHECK-LABEL:   func.func private @insert_slice_dynamic_src_dim_non_leading_unit_dim_dropped(
+// CHECK-SAME:      %[[SRC:.*]]: tensor<?x4xi32>,
+// CHECK-SAME:      %[[SIZE:.*]]: index) -> tensor<8x1x4xi32> {
+// CHECK-DAG:       %[[PAD:.*]] = arith.constant 0 : i32
+// CHECK:           %[[INIT:.*]] = linalg.fill ins(%[[PAD]] : i32) outs({{.*}} : tensor<8x1x4xi32>) -> tensor<8x1x4xi32>
+// CHECK:           %[[READ:.*]] = vector.transfer_read %[[SRC]][%{{.*}}, %{{.*}}], %[[PAD]] {{.*}} : tensor<?x4xi32>, vector<8x4xi32>
+// CHECK:           %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}] {{.*}} : vector<8x4xi32>, tensor<8x1x4xi32>
+// CHECK:           return %[[RES]] : tensor<8x1x4xi32>
+
+ module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %0 = transform.structured.match ops{["tensor.insert_slice"]} in %arg0 : (!transform.any_op) -> !transform.any_op
+    transform.structured.vectorize %0 : !transform.any_op
+    transform.yield
+  }
+ }
+
+// -----
+
 // One of the _destination_ dimensions is dynamic (but _source_ dimensions are static).
 
 func.func private @insert_slice_dynamic_dest_dim(%source: tensor<?x3x?x1xi32>, %size: index) -> tensor<?x3xi32> {



More information about the Mlir-commits mailing list