[Mlir-commits] [mlir] aa673fa - [mlir][linalg] Fix rank-reducing insert_slice vectorization writing to wrong dims (#226490)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Oct 17 02:30:41 PDT 2026
Author: Dhairyashil R G
Date: 2026-10-17T15:00:35+05:30
New Revision: aa673fae32d57e8d9bd65dabc48eb361439aa55f
URL: https://github.com/llvm/llvm-project/commit/aa673fae32d57e8d9bd65dabc48eb361439aa55f
DIFF: https://github.com/llvm/llvm-project/commit/aa673fae32d57e8d9bd65dabc48eb361439aa55f.diff
LOG: [mlir][linalg] Fix rank-reducing insert_slice vectorization writing to wrong dims (#226490)
Vectorizing a rank-reducing `tensor.insert_slice` took the vector shape
from the non-dropped result dims, but wrote the vector back with an
implied minor-identity permutation map, i.e. onto the trailing result
dims. When the dropped unit dims are not the trailing ones, those are
the wrong dims.
Inserting a `tensor<5xi32>` into `tensor<5x3xi32>` at `[0, 2] [5, 1] [1,
1]` fills column 2, one element per row. Vectorized, the write went
along dim 1, so only the first element landed and the other four were
discarded by the out-of-bounds check. With user-provided vector sizes
the write was masked with `dim(1) - index(0)` and stored past the end of
the row instead.
Fixed by passing a permutation map built from the non-dropped result
dims, and by making `createWriteOrMaskedWrite` use the dims that map
selects, both to decide whether a mask is needed and to size it: each
mask size is `dim - index` for that dim.
This also fixes the masked write for a dropped leading dim at a non-zero
offset. Each offset used to be subtracted from the wrong dim, so, for
example, a 4-row vector written from row 6 of an 8-row dim was left
unmasked.
Three of the four existing rank-reducing tests in insert-slice.mlir were
checking the old write; they now check the permutation map. New tests
cover the masked path, and a new integration test requires the
vectorized and un-vectorized forms to print the same result.
Part of #227821.
Related: #221293 (same bug; its stride check is still needed).
Context:
https://discourse.llvm.org/t/rfc-should-vector-transfer-read-write-keep-in-bounds-measurements-on-the-masking-alternative/91649
Assisted-by: Claude
Added:
mlir/test/Integration/Dialect/Linalg/CPU/vectorize-insert-slice-rank-reducing.mlir
Modified:
mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
mlir/lib/Dialect/Vector/Utils/VectorUtils.cpp
mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index 8c0a2ce0b9ec1e..081a6220c85ccb 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -3079,9 +3079,20 @@ vectorizeAsInsertSliceOp(RewriterBase &rewriter, tensor::InsertSliceOp sliceOp,
// Create write
auto writeIndices =
getValueOrCreateConstantIndexOp(rewriter, loc, sliceOp.getMixedOffsets());
- Operation *write =
- vector::createWriteOrMaskedWrite(rewriter, loc, read, sliceOp.getDest(),
- writeIndices, inputVectorSizes.empty());
+ // For a rank-reducing slice the vector need not cover the trailing result
+ // dims, so state which result dim each vector dim writes to.
+ AffineMap writeMap;
+ if (sourceType.getRank() != resultType.getRank()) {
+ SmallVector<AffineExpr> exprs;
+ for (int64_t resultDim : resultDimsForSourceDims)
+ exprs.push_back(rewriter.getAffineDimExpr(resultDim));
+ writeMap = AffineMap::get(resultType.getRank(), /*symbolCount=*/0, exprs,
+ rewriter.getContext());
+ }
+
+ Operation *write = vector::createWriteOrMaskedWrite(
+ rewriter, loc, read, sliceOp.getDest(), writeIndices,
+ inputVectorSizes.empty(), writeMap);
// 4. Finalize
newResults.push_back(write->getResult(0));
diff --git a/mlir/lib/Dialect/Vector/Utils/VectorUtils.cpp b/mlir/lib/Dialect/Vector/Utils/VectorUtils.cpp
index bd889a82bdb59a..14a6571549897d 100644
--- a/mlir/lib/Dialect/Vector/Utils/VectorUtils.cpp
+++ b/mlir/lib/Dialect/Vector/Utils/VectorUtils.cpp
@@ -584,37 +584,42 @@ Operation *vector::createWriteOrMaskedWrite(OpBuilder &builder, Location loc,
if (useInBoundsInsteadOfMasking)
return write;
+ // The dest dims written to are those the permutation map selects. A null map
+ // means a minor identity: the trailing dims.
+ AffineMap map = permutationMap
+ ? permutationMap
+ : AffineMap::getMinorIdentityMap(destRank, vecToStoreRank,
+ builder.getContext());
+
// Check if masking is needed. If not, exit.
- if (llvm::equal(vecToStoreShape, destShape.take_back(vecToStoreRank)))
+ if (llvm::equal(vecToStoreShape, applyPermutationMap(map, destShape)))
return write;
// Compute the mask and mask the write Op.
- auto writeMaskType = VectorType::get(vecToStoreShape, builder.getI1Type(),
- vecToStoreType.getScalableDims());
+ VectorType writeMaskType = inferTransferOpMaskType(vecToStoreType, map);
SmallVector<OpFoldResult> destSizes =
isa<MemRefType>(dest.getType())
? memref::getMixedSizes(builder, loc, dest)
: tensor::getMixedSizes(builder, loc, dest);
- // Compute sizes for write-mask
+ // Compute sizes for write-mask: `dim - index` for each dest dim written to,
+ // in increasing order, as the mask dims are.
+ SmallVector<int64_t> writtenDims;
+ for (AffineExpr expr : map.getResults())
+ writtenDims.push_back(cast<AffineDimExpr>(expr).getPosition());
+ llvm::sort(writtenDims);
SmallVector<OpFoldResult> maskSizes;
- if (useDefaultWriteIdxs) {
- maskSizes = SmallVector<OpFoldResult>(destSizes.end() - vecToStoreRank,
- destSizes.end());
- } else {
- size_t
diff = destShape.size() - vecToStoreRank;
- for (int64_t idx = 0; idx < vecToStoreRank; idx++) {
- auto value =
- getValueOrCreateConstantIndexOp(builder, loc, destSizes[
diff + idx]);
- auto neg =
- builder.createOrFold<arith::SubIOp>(loc, value, writeIndices[idx]);
- maskSizes.push_back(OpFoldResult(neg));
- }
+ for (int64_t dim : writtenDims) {
+ Value size = getValueOrCreateConstantIndexOp(builder, loc, destSizes[dim]);
+ maskSizes.push_back(
+ builder.createOrFold<arith::SubIOp>(loc, size, writeIndices[dim]));
}
- if (isMaskTriviallyFoldable(maskSizes, writeIndices, destShape,
- vecToStoreShape))
+ // TODO: isMaskTriviallyFoldable checks the trailing dims against the leading
+ // indices. Make it use the dims that the map selects and their indices.
+ if (!permutationMap && isMaskTriviallyFoldable(maskSizes, writeIndices,
+ destShape, vecToStoreShape))
return write;
Value maskForWrite =
diff --git a/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir b/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
index a73b4b8035adbf..319095f97e1513 100644
--- a/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
+++ b/mlir/test/Dialect/Linalg/vectorization/insert-slice.mlir
@@ -97,13 +97,16 @@ func.func private @insert_slice_dynamic_src_dim_non_leading_unit_dim_dropped(
return %res : tensor<8x1x4xi32>
}
+// CHECK-DAG: #[[$MAP_0_2:.*]] = affine_map<(d0, d1, d2) -> (d0, d2)>
+
// 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>
+// Dim 1 is dropped, so the source dims map to result dims 0 and 2.
+// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}] {{.*}}permutation_map = #[[$MAP_0_2]]{{.*}} : vector<8x4xi32>, tensor<8x1x4xi32>
// CHECK: return %[[RES]] : tensor<8x1x4xi32>
module attributes {transform.with_named_sequence} {
@@ -131,6 +134,8 @@ func.func private @insert_slice_dynamic_src_dim_leading_unit_dim_dropped(
// CHECK-DAG: %[[PAD:.*]] = arith.constant 0 : i32
// CHECK: %[[INIT:.*]] = linalg.fill ins(%[[PAD]] : i32) outs({{.*}} : tensor<1x8x4xi32>) -> tensor<1x8x4xi32>
// CHECK: %[[READ:.*]] = vector.transfer_read %[[SRC]][%{{.*}}, %{{.*}}], %[[PAD]] {{.*}} : tensor<?x4xi32>, vector<8x4xi32>
+// Dim 0 is dropped, so the source dims are already the trailing result dims.
+// CHECK-NOT: permutation_map
// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}] {{.*}} : vector<8x4xi32>, tensor<1x8x4xi32>
// CHECK: return %[[RES]] : tensor<1x8x4xi32>
@@ -153,13 +158,16 @@ func.func private @insert_slice_dynamic_src_dim_trailing_unit_dim_dropped(
return %res : tensor<8x4x1xi32>
}
+// CHECK-DAG: #[[$MAP_0_1:.*]] = affine_map<(d0, d1, d2) -> (d0, d1)>
+
// CHECK-LABEL: func.func private @insert_slice_dynamic_src_dim_trailing_unit_dim_dropped(
// CHECK-SAME: %[[SRC:.*]]: tensor<?x4xi32>,
// CHECK-SAME: %[[SIZE:.*]]: index) -> tensor<8x4x1xi32> {
// CHECK-DAG: %[[PAD:.*]] = arith.constant 0 : i32
// CHECK: %[[INIT:.*]] = linalg.fill ins(%[[PAD]] : i32) outs({{.*}} : tensor<8x4x1xi32>) -> tensor<8x4x1xi32>
// CHECK: %[[READ:.*]] = vector.transfer_read %[[SRC]][%{{.*}}, %{{.*}}], %[[PAD]] {{.*}} : tensor<?x4xi32>, vector<8x4xi32>
-// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}] : vector<8x4xi32>, tensor<8x4x1xi32>
+// Dim 2 is dropped, so the source dims map to result dims 0 and 1.
+// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}] {{.*}}permutation_map = #[[$MAP_0_1]]{{.*}} : vector<8x4xi32>, tensor<8x4x1xi32>
// CHECK: return %[[RES]] : tensor<8x4x1xi32>
module attributes {transform.with_named_sequence} {
@@ -181,13 +189,16 @@ func.func private @insert_slice_dynamic_src_dim_leading_and_trailing_unit_dims_d
return %res : tensor<1x8x4x1xi32>
}
+// CHECK-DAG: #[[$MAP_1_2:.*]] = affine_map<(d0, d1, d2, d3) -> (d1, d2)>
+
// CHECK-LABEL: func.func private @insert_slice_dynamic_src_dim_leading_and_trailing_unit_dims_dropped(
// CHECK-SAME: %[[SRC:.*]]: tensor<?x4xi32>,
// CHECK-SAME: %[[SIZE:.*]]: index) -> tensor<1x8x4x1xi32> {
// CHECK-DAG: %[[PAD:.*]] = arith.constant 0 : i32
// CHECK: %[[INIT:.*]] = linalg.fill ins(%[[PAD]] : i32) outs({{.*}} : tensor<1x8x4x1xi32>) -> tensor<1x8x4x1xi32>
// CHECK: %[[READ:.*]] = vector.transfer_read %[[SRC]][%{{.*}}, %{{.*}}], %[[PAD]] {{.*}} : tensor<?x4xi32>, vector<8x4xi32>
-// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : vector<8x4xi32>, tensor<1x8x4x1xi32>
+// Dims 0 and 3 are dropped, so the source dims map to result dims 1 and 2.
+// CHECK: %[[RES:.*]] = vector.transfer_write %[[READ]], %[[INIT]][%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] {{.*}}permutation_map = #[[$MAP_1_2]]{{.*}} : vector<8x4xi32>, tensor<1x8x4x1xi32>
// CHECK: return %[[RES]] : tensor<1x8x4x1xi32>
module attributes {transform.with_named_sequence} {
@@ -359,3 +370,88 @@ func.func private @insert_slice_non_zero_offset_for_dyn_dim(%source: tensor<?x3x
transform.yield
}
}
+
+// -----
+
+/// Dim 1 is dropped, so the vector is written to result dims 0 and 2. Its shape
+/// (1x4) equals the trailing result dims (1x4), but result dim 0 is dynamic, so
+/// the write needs a mask. The mask sizes come from result dims 0 and 2.
+
+func.func private @insert_slice_non_leading_unit_dim_dropped_dynamic_dest_dim(
+ %source: tensor<?x4xi32>, %dest: tensor<?x1x4xi32>, %size: index, %offset: index) -> tensor<?x1x4xi32> {
+ %res = tensor.insert_slice %source into %dest[%offset, 0, 0] [%size, 1, 4] [1, 1, 1] : tensor<?x4xi32> into tensor<?x1x4xi32>
+ return %res : tensor<?x1x4xi32>
+}
+
+// CHECK-DAG: #[[$MAP_D0_D2:.*]] = affine_map<(d0, d1, d2) -> (d0, d2)>
+
+// CHECK-LABEL: func.func private @insert_slice_non_leading_unit_dim_dropped_dynamic_dest_dim(
+// CHECK-SAME: %[[SRC:.*]]: tensor<?x4xi32>,
+// CHECK-SAME: %[[DEST:.*]]: tensor<?x1x4xi32>,
+// CHECK-SAME: %[[SIZE:.*]]: index,
+// CHECK-SAME: %[[OFFSET:.*]]: index) -> tensor<?x1x4xi32> {
+// CHECK: %[[PAD:.*]] = arith.constant 0 : i32
+// CHECK: %[[C_0:.*]] = arith.constant 0 : index
+// CHECK: %[[C_0_1:.*]] = arith.constant 0 : index
+// CHECK: %[[C_0_2:.*]] = arith.constant 0 : index
+// CHECK: %[[SRC_DIM_0:.*]] = tensor.dim %[[SRC]], %[[C_0_2]] : tensor<?x4xi32>
+// CHECK: %[[C_4:.*]] = arith.constant 4 : index
+// CHECK: %[[MASK_READ:.*]] = vector.create_mask %[[SRC_DIM_0]], %[[C_4]] : vector<1x4xi1>
+// CHECK: %[[READ:.*]] = vector.mask %[[MASK_READ]] { vector.transfer_read %[[SRC]][%[[C_0_1]], %[[C_0_1]]], %[[PAD]] {in_bounds = [true, true]} : tensor<?x4xi32>, vector<1x4xi32> } : vector<1x4xi1> -> vector<1x4xi32>
+// CHECK: %[[C_0_3:.*]] = arith.constant 0 : index
+// CHECK: %[[C_0_4:.*]] = arith.constant 0 : index
+// CHECK: %[[C_0_5:.*]] = arith.constant 0 : index
+// CHECK: %[[DEST_DIM_0:.*]] = tensor.dim %[[DEST]], %[[C_0_5]] : tensor<?x1x4xi32>
+// CHECK: %[[SIZE_0:.*]] = arith.subi %[[DEST_DIM_0]], %[[OFFSET]] : index
+// CHECK: %[[C_4_1:.*]] = arith.constant 4 : index
+// CHECK: %[[MASK_WRITE:.*]] = vector.create_mask %[[SIZE_0]], %[[C_4_1]] : vector<1x4xi1>
+// CHECK: %[[RES:.*]] = vector.mask %[[MASK_WRITE]] { vector.transfer_write %[[READ]], %[[DEST]][%[[OFFSET]], %[[C_0_3]], %[[C_0_4]]] {in_bounds = [true, true], permutation_map = #[[$MAP_D0_D2]]} : vector<1x4xi32>, tensor<?x1x4xi32> } : vector<1x4xi1> -> tensor<?x1x4xi32>
+// CHECK: return %[[RES]] : tensor<?x1x4xi32>
+
+ 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 vector_sizes [1, 4] : !transform.any_op
+ transform.yield
+ }
+ }
+
+// -----
+
+/// The leading unit dim is dropped and the insert index for result dim 1 is
+/// != 0. The source has fewer dims than the result, so each mask size must be
+/// computed from the result dim and the index of that same dim (8 - 6, 8 - 0).
+
+func.func private @insert_slice_leading_unit_dim_dropped_non_zero_offset(
+ %source: tensor<2x2xi32>, %dest: tensor<1x8x8xi32>) -> tensor<1x8x8xi32> {
+ %res = tensor.insert_slice %source into %dest[0, 6, 0] [1, 2, 2] [1, 1, 1] : tensor<2x2xi32> into tensor<1x8x8xi32>
+ return %res : tensor<1x8x8xi32>
+}
+
+// CHECK-LABEL: func.func private @insert_slice_leading_unit_dim_dropped_non_zero_offset(
+// CHECK-SAME: %[[SRC:.*]]: tensor<2x2xi32>,
+// CHECK-SAME: %[[DEST:.*]]: tensor<1x8x8xi32>) -> tensor<1x8x8xi32> {
+// CHECK: %[[PAD:.*]] = arith.constant 0 : i32
+// CHECK: %[[C_0:.*]] = arith.constant 0 : index
+// CHECK: %[[C_0_1:.*]] = arith.constant 0 : index
+// CHECK: %[[C_2:.*]] = arith.constant 2 : index
+// CHECK: %[[C_2_1:.*]] = arith.constant 2 : index
+// CHECK: %[[MASK_READ:.*]] = vector.create_mask %[[C_2]], %[[C_2_1]] : vector<4x2xi1>
+// CHECK: %[[READ:.*]] = vector.mask %[[MASK_READ]] { vector.transfer_read %[[SRC]][%[[C_0_1]], %[[C_0_1]]], %[[PAD]] {in_bounds = [true, true]} : tensor<2x2xi32>, vector<4x2xi32> } : vector<4x2xi1> -> vector<4x2xi32>
+// CHECK: %[[C_0_2:.*]] = arith.constant 0 : index
+// CHECK: %[[C_6:.*]] = arith.constant 6 : index
+// CHECK: %[[C_0_3:.*]] = arith.constant 0 : index
+// CHECK: %[[C_8:.*]] = arith.constant 8 : index
+// CHECK: %[[C_2_2:.*]] = arith.constant 2 : index
+// CHECK: %[[C_8_1:.*]] = arith.constant 8 : index
+// CHECK: %[[MASK_WRITE:.*]] = vector.create_mask %[[C_2_2]], %[[C_8_1]] : vector<4x2xi1>
+// CHECK: %[[RES:.*]] = vector.mask %[[MASK_WRITE]] { vector.transfer_write %[[READ]], %[[DEST]][%[[C_0_2]], %[[C_6]], %[[C_0_3]]] {in_bounds = [true, true]} : vector<4x2xi32>, tensor<1x8x8xi32> } : vector<4x2xi1> -> tensor<1x8x8xi32>
+// CHECK: return %[[RES]] : tensor<1x8x8xi32>
+
+ 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 vector_sizes [4, 2] : !transform.any_op
+ transform.yield
+ }
+ }
diff --git a/mlir/test/Integration/Dialect/Linalg/CPU/vectorize-insert-slice-rank-reducing.mlir b/mlir/test/Integration/Dialect/Linalg/CPU/vectorize-insert-slice-rank-reducing.mlir
new file mode 100644
index 00000000000000..df4cf3729eab85
--- /dev/null
+++ b/mlir/test/Integration/Dialect/Linalg/CPU/vectorize-insert-slice-rank-reducing.mlir
@@ -0,0 +1,51 @@
+// DEFINE: %{entry_point} = main
+
+// DEFINE: %{vectorize} = mlir-opt -transform-interpreter
+// DEFINE: %{lower} = mlir-opt -one-shot-bufferize=bufferize-function-boundaries \
+// DEFINE: -test-lower-to-llvm -test-transform-dialect-erase-schedule
+// DEFINE: %{run} = mlir-runner -e %{entry_point} -entry-point-result=void \
+// DEFINE: -shared-libs=%mlir_runner_utils,%mlir_c_runner_utils
+
+/// End-to-end test for vectorizing a rank-reducing tensor.insert_slice. Both
+/// runs use the same lowering and must print the same thing.
+
+/// _Without_ vectorization (reference)
+// RUN: %{lower} %s | %{run} | FileCheck %s
+
+/// _With_ vectorization
+// RUN: %{vectorize} %s | %{lower} | %{run} | FileCheck %s
+
+func.func @main() {
+ %pad = arith.constant 0 : i32
+ %src = arith.constant dense<[1, 2, 3, 4, 5]> : tensor<5xi32>
+ %empty = tensor.empty() : tensor<5x3xi32>
+ %init = linalg.fill ins(%pad : i32) outs(%empty : tensor<5x3xi32>) -> tensor<5x3xi32>
+
+ /// Dim 1 of the slice is dropped, so the source's only dim corresponds to
+ /// dim 0 of the result.
+ %res = tensor.insert_slice %src into %init[0, 2] [5, 1] [1, 1]
+ : tensor<5xi32> into tensor<5x3xi32>
+
+ %res_cast = tensor.cast %res : tensor<5x3xi32> to tensor<*xi32>
+
+ // CHECK: Unranked Memref base@ = 0x{{.*}} rank = 2 offset = 0 sizes = [5, 3] strides = [3, 1] data =
+ // CHECK-NEXT: [0, 0, 1]
+ // CHECK-NEXT: [0, 0, 2]
+ // CHECK-NEXT: [0, 0, 3]
+ // CHECK-NEXT: [0, 0, 4]
+ // CHECK-NEXT: [0, 0, 5]
+ call @printMemrefI32(%res_cast) : (tensor<*xi32>) -> ()
+
+ return
+}
+
+module @transforms attributes { transform.with_named_sequence } {
+ transform.named_sequence @__transform_main(%module: !transform.any_op {transform.readonly}) {
+ %slice = transform.structured.match ops{["tensor.insert_slice"]} in %module
+ : (!transform.any_op) -> !transform.any_op
+ transform.structured.vectorize %slice : !transform.any_op
+ transform.yield
+ }
+}
+
+func.func private @printMemrefI32(%ptr : tensor<*xi32>)
More information about the Mlir-commits
mailing list