[Mlir-commits] [mlir] [mlir][Vector] Reject scalable masks in maskedload/maskedstore emulation (PR #223316)
Cheng-Chieh Liu
llvmlistbot at llvm.org
Mon Sep 14 00:14:56 PDT 2026
https://github.com/jay87406 created https://github.com/llvm/llvm-project/pull/223316
`VectorMaskedLoadOpConverter` and `VectorMaskedStoreOpConverter` unroll into a fixed number of `scf.if` blocks based on `maskVType.getShape()[0]`. For a scalable mask like `vector<[4]xi1>` that's only the static minimum, not the actual (`vscale`-scaled) element count, so lanes past the fixed 4 iterations were silently dropped whenever `vscale > 1`.
Reject scalable masks the same way the existing rank check does, and add `lit` coverage for both ops.
>From 7609107c3520685082bf1b3400a8928871615785 Mon Sep 17 00:00:00 2001
From: Cheng-Chieh Liu <jay87406 at gmail.com>
Date: Mon, 14 Sep 2026 01:48:04 -0500
Subject: [PATCH] [mlir][Vector] Reject scalable masks in
maskedload/maskedstore emulation
VectorMaskedLoadOpConverter and VectorMaskedStoreOpConverter unroll
into a fixed number of scf.if blocks based on maskVType.getShape()[0].
For a scalable mask like vector<[4]xi1> that's only the static
minimum, not the actual (vscale-scaled) element count, so lanes past
the fixed 4 iterations were silently dropped whenever vscale > 1.
Reject scalable masks the same way the existing rank check does, and
add lit coverage for both ops.
---
.../VectorEmulateMaskedLoadStore.cpp | 6 ++++++
.../vector-emulate-masked-load-store.mlir | 19 +++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp b/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
index 3ca08f3099bd3..53df3d3c48c6a 100644
--- a/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
+++ b/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
@@ -56,6 +56,9 @@ struct VectorMaskedLoadOpConverter final
if (maskVType.getShape().size() != 1)
return rewriter.notifyMatchFailure(
maskedLoadOp, "expected vector.maskedstore with 1-D mask");
+ if (maskVType.isScalable())
+ return rewriter.notifyMatchFailure(
+ maskedLoadOp, "cannot unroll a scalable mask");
Location loc = maskedLoadOp.getLoc();
int64_t maskLength = maskVType.getShape()[0];
@@ -125,6 +128,9 @@ struct VectorMaskedStoreOpConverter final
if (maskVType.getShape().size() != 1)
return rewriter.notifyMatchFailure(
maskedStoreOp, "expected vector.maskedstore with 1-D mask");
+ if (maskVType.isScalable())
+ return rewriter.notifyMatchFailure(
+ maskedStoreOp, "cannot unroll a scalable mask");
Location loc = maskedStoreOp.getLoc();
int64_t maskLength = maskVType.getShape()[0];
diff --git a/mlir/test/Dialect/Vector/vector-emulate-masked-load-store.mlir b/mlir/test/Dialect/Vector/vector-emulate-masked-load-store.mlir
index 7c492781c8c55..76646a21c899b 100644
--- a/mlir/test/Dialect/Vector/vector-emulate-masked-load-store.mlir
+++ b/mlir/test/Dialect/Vector/vector-emulate-masked-load-store.mlir
@@ -145,3 +145,22 @@ func.func @vector_maskedstore_rank0(%arg0: memref<f32>, %arg3: vector<1xi1>, %ar
vector.maskedstore %arg0[], %arg3, %arg4 : memref<f32>, vector<1xi1>, vector<1xf32>
return
}
+
+// A scalable mask cannot be unrolled at compile time, so these must not be
+// converted.
+
+// CHECK-LABEL: @vector_maskedload_scalable
+// CHECK: vector.maskedload
+func.func @vector_maskedload_scalable(%arg0: memref<?xf32>, %mask: vector<[4]xi1>, %pass_thru: vector<[4]xf32>) -> vector<[4]xf32> {
+ %idx_0 = arith.constant 0 : index
+ %0 = vector.maskedload %arg0[%idx_0], %mask, %pass_thru : memref<?xf32>, vector<[4]xi1>, vector<[4]xf32> into vector<[4]xf32>
+ return %0 : vector<[4]xf32>
+}
+
+// CHECK-LABEL: @vector_maskedstore_scalable
+// CHECK: vector.maskedstore
+func.func @vector_maskedstore_scalable(%arg0: memref<?xf32>, %mask: vector<[4]xi1>, %value: vector<[4]xf32>) {
+ %idx_0 = arith.constant 0 : index
+ vector.maskedstore %arg0[%idx_0], %mask, %value : memref<?xf32>, vector<[4]xi1>, vector<[4]xf32>
+ return
+}
More information about the Mlir-commits
mailing list