[Mlir-commits] [mlir] [mlir][VectorToGPU] Only convert an scf.yield that terminates an scf.for (PR #218226)
Alessandro Potenza
llvmlistbot at llvm.org
Mon Aug 24 08:46:28 PDT 2026
https://github.com/alepot55 updated https://github.com/llvm/llvm-project/pull/218226
>From 6b7b52cae2ce872fe016dfd9baf70aa2263a5f70 Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Sun, 23 Aug 2026 12:29:03 +0200
Subject: [PATCH] [mlir][VectorToGPU] Only convert an scf.yield that terminates
an scf.for
supportsMMaMatrixType() accepts every scf::YieldOp without looking at its
parent, so a yield terminating an scf.if enters the conversion set and reaches
convertYieldOp(), which opens with cast<scf::ForOp>(op->getParentOp()) and
rewrites the yielded values against the loop's init args. With assertions that
aborts; without them the cast is unchecked.
Guard the yield arm on the parent being an scf.for, which keeps a
non-convertible yield out of the set rather than bailing out later.
Fixes #205068.
Assisted-by: Claude (Anthropic)
---
.../Conversion/VectorToGPU/VectorToGPU.cpp | 6 +++-
.../vector-to-mma-ops-mma-sync.mlir | 28 +++++++++++++++++++
.../VectorToGPU/vector-to-mma-ops.mlir | 28 +++++++++++++++++++
3 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
index 975fe28399609..93c6c024b9681 100644
--- a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
+++ b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
@@ -297,8 +297,12 @@ extractStridedSliceSupportsMMAMatrixType(vector::ExtractStridedSliceOp op) {
}
static bool supportsMMaMatrixType(Operation *op, bool useNvGpu) {
- if (isa<scf::ForOp, scf::YieldOp>(op))
+ if (isa<scf::ForOp>(op))
return true;
+ // A yield is only convertible as the terminator of an scf.for body:
+ // convertYieldOp rewrites the yielded values against the loop's init args.
+ if (isa<scf::YieldOp>(op))
+ return isa<scf::ForOp>(op->getParentOp());
if (auto transferRead = dyn_cast<vector::TransferReadOp>(op))
return useNvGpu ? nvgpu::canLowerToWarpMatrixOperation(transferRead)
: transferReadSupportsMMAMatrixType(transferRead);
diff --git a/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops-mma-sync.mlir b/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops-mma-sync.mlir
index 988122ae0fd45..b6dfcb5a6780d 100644
--- a/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops-mma-sync.mlir
+++ b/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops-mma-sync.mlir
@@ -835,3 +835,31 @@ func.func @unsupported_transposed_store(%arg0: !smem_type,
vector.transfer_write %D, %arg2[%c0, %c0] {in_bounds = [true, true], permutation_map = affine_map<(d0, d1)->(d1, d0)>} : vector<16x8xf16>, !smem_type
return
}
+
+// -----
+
+#map0 = affine_map<(d0, d1) -> (d1, d0)>
+#map1 = affine_map<(d0, d1, d2) -> (d0, d2)>
+#map2 = affine_map<(d0, d1, d2) -> (d1, d2)>
+#map3 = affine_map<(d0, d1, d2) -> (d0, d1)>
+
+// Same guard on the nvgpu path: getOpToConvert feeds both entry points, and a
+// yield that does not terminate an scf.for body is not convertible in either.
+// CHECK-LABEL: func @no_convert_yield_of_scf_if
+// CHECK: scf.if
+// CHECK-NOT: nvgpu.
+func.func @no_convert_yield_of_scf_if(%arg0: memref<128x128xf16>, %arg1: memref<128x128xf16>, %arg2: memref<128x128xf16>, %cond: i1) {
+ %c0 = arith.constant 0 : index
+ %cst = arith.constant 0.000000e+00 : f16
+ %C = vector.transfer_read %arg2[%c0, %c0], %cst {in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %r = scf.if %cond -> (vector<16x16xf16>) {
+ %a = vector.transfer_read %arg0[%c0, %c0], %cst {in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %b = vector.transfer_read %arg1[%c0, %c0], %cst {permutation_map = #map0, in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %d = vector.contract {indexing_maps = [#map1, #map2, #map3], iterator_types = ["parallel", "parallel", "reduction"], kind = #vector.kind<add>} %a, %b, %C : vector<16x16xf16>, vector<16x16xf16> into vector<16x16xf16>
+ scf.yield %d : vector<16x16xf16>
+ } else {
+ scf.yield %C : vector<16x16xf16>
+ }
+ vector.transfer_write %r, %arg2[%c0, %c0] {in_bounds = [true, true]} : vector<16x16xf16>, memref<128x128xf16>
+ return
+}
diff --git a/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops.mlir b/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops.mlir
index 00e5966eb2a34..fa2359d8a696e 100644
--- a/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops.mlir
+++ b/mlir/test/Conversion/VectorToGPU/vector-to-mma-ops.mlir
@@ -684,3 +684,31 @@ func.func @read_transpose_with_broadcast_3d(%arg0: memref<2x2x2xf16>, %arg1: mem
vector.transfer_write %B, %arg1[%c0, %c0] {in_bounds = [true, true]} : vector<2x2xf16>, memref<2x2xf16>
return
}
+
+// -----
+
+#map0 = affine_map<(d0, d1) -> (d1, d0)>
+#map1 = affine_map<(d0, d1, d2) -> (d0, d2)>
+#map2 = affine_map<(d0, d1, d2) -> (d1, d2)>
+#map3 = affine_map<(d0, d1, d2) -> (d0, d1)>
+
+// A yield that terminates something other than an scf.for body is not
+// convertible: convertYieldOp rewrites against the loop's init args.
+// CHECK-LABEL: func @no_convert_yield_of_scf_if
+// CHECK: scf.if
+// CHECK-NOT: gpu.subgroup_mma
+func.func @no_convert_yield_of_scf_if(%arg0: memref<128x128xf16>, %arg1: memref<128x128xf16>, %arg2: memref<128x128xf16>, %cond: i1) {
+ %c0 = arith.constant 0 : index
+ %cst = arith.constant 0.000000e+00 : f16
+ %C = vector.transfer_read %arg2[%c0, %c0], %cst {in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %r = scf.if %cond -> (vector<16x16xf16>) {
+ %a = vector.transfer_read %arg0[%c0, %c0], %cst {in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %b = vector.transfer_read %arg1[%c0, %c0], %cst {permutation_map = #map0, in_bounds = [true, true]} : memref<128x128xf16>, vector<16x16xf16>
+ %d = vector.contract {indexing_maps = [#map1, #map2, #map3], iterator_types = ["parallel", "parallel", "reduction"], kind = #vector.kind<add>} %a, %b, %C : vector<16x16xf16>, vector<16x16xf16> into vector<16x16xf16>
+ scf.yield %d : vector<16x16xf16>
+ } else {
+ scf.yield %C : vector<16x16xf16>
+ }
+ vector.transfer_write %r, %arg2[%c0, %c0] {in_bounds = [true, true]} : vector<16x16xf16>, memref<128x128xf16>
+ return
+}
More information about the Mlir-commits
mailing list