[Mlir-commits] [mlir] a9fb8b0 - [MLIR][XeGPU] Support vector.contract transpose_a/transpose_b via 'vector-to-gpu' patterns (#182885)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Mar 5 08:08:59 PST 2026


Author: Dmitry Chigarev
Date: 2026-03-05T17:08:55+01:00
New Revision: a9fb8b06224aec404a2ec9bf101c40e36f46426c

URL: https://github.com/llvm/llvm-project/commit/a9fb8b06224aec404a2ec9bf101c40e36f46426c
DIFF: https://github.com/llvm/llvm-project/commit/a9fb8b06224aec404a2ec9bf101c40e36f46426c.diff

LOG: [MLIR][XeGPU] Support vector.contract transpose_a/transpose_b via 'vector-to-gpu' patterns (#182885)

The PR adds [`vector.contract(transpose_a/transpose_b)` decomposition
patterns](https://github.com/llvm/llvm-project/blob/3215645b8d81bbef7db1d16b88de7ed0288f2274/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp#L1263)
from `vector-to-gpu` to `vector-to-xegpu` pass.

The `populatePrepareVectorToMMAPatterns` adds two patterns:
1. `PrepareContractToGPUMMA` that splits `vector.contract(transpose)`
into `vector.transpose + vector.contract`
2. `CombineTransferReadOpTranspose` that fuses `vector.transpose` into
the permutation map of `vector.transfer_read`

The second pattern doesn't always bring us to the desired result
(`xegpu.load_nd + vector.transpose + xegpu.dpas`) since [not all data
types are supported
](https://github.com/llvm/llvm-project/blob/1237bd6df05a4777f444677186e4814388916ea9/mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp#L570-L575)
for the transposed-read case. There's a second PR (#182875) on this
matter that adds a decomposition-pattern for unsupported types (it might
seem strange that we first fuse and then decompose
transfer_read+transpose but this way we don't have code duplication
between vector-to-gpu&to-xegpu passes and cover all functional cases)

---------

Signed-off-by: dchigarev <dmitry.chigarev at intel.com>

Added: 
    

Modified: 
    mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp
    mlir/test/Conversion/VectorToXeGPU/contract-to-xegpu.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp b/mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp
index 0eac704779e7d..bbb6340f14c51 100644
--- a/mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp
+++ b/mlir/lib/Conversion/VectorToXeGPU/VectorToXeGPU.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Conversion/VectorToXeGPU/VectorToXeGPU.h"
+#include "mlir/Conversion/VectorToGPU/VectorToGPU.h"
 
 #include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/Dialect/MemRef/IR/MemRef.h"
@@ -864,6 +865,7 @@ struct ConvertVectorToXeGPUPass
   void runOnOperation() override {
     RewritePatternSet patterns(&getContext());
     populateVectorToXeGPUConversionPatterns(patterns);
+    populatePrepareVectorToMMAPatterns(patterns);
     if (failed(applyPatternsGreedily(getOperation(), std::move(patterns))))
       return signalPassFailure();
   }

diff  --git a/mlir/test/Conversion/VectorToXeGPU/contract-to-xegpu.mlir b/mlir/test/Conversion/VectorToXeGPU/contract-to-xegpu.mlir
index 38bda39d3aca2..292e4ff882000 100644
--- a/mlir/test/Conversion/VectorToXeGPU/contract-to-xegpu.mlir
+++ b/mlir/test/Conversion/VectorToXeGPU/contract-to-xegpu.mlir
@@ -76,6 +76,56 @@ func.func @dpas_large_dims(%lhs: vector<128x512xf16>, %rhs: vector<512x256xf16>,
 
 // -----
 
+#map = affine_map<(d0, d1, d2) -> (d2, d0)>
+#map1 = affine_map<(d0, d1, d2) -> (d2, d1)>
+#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>
+func.func @gemm_transpose_a(%lhs: vector<16x8xf16>, %rhs: vector<16x16xf16>,
+    %acc: vector<8x16xf32>) -> vector<8x16xf32> {
+  %3 = vector.contract
+    {indexing_maps = [#map, #map1, #map2],
+    iterator_types = ["parallel", "parallel", "reduction"],
+    kind = #vector.kind<add>} %lhs, %rhs, %acc
+    : vector<16x8xf16>, vector<16x16xf16> into vector<8x16xf32>
+  return %3 : vector<8x16xf32>
+}
+
+// CHECK-LABEL: @gemm_transpose_a(
+// CHECK-SAME:  %[[LHS:.+]]: vector<16x8xf16>,
+// CHECK-SAME:  %[[RHS:.+]]: vector<16x16xf16>,
+// CHECK-SAME:  %[[ACC:.+]]: vector<8x16xf32>
+// CHECK:       %[[LHS_TRANSPOSED:.+]] = vector.transpose %[[LHS]], [1, 0] : vector<16x8xf16> to vector<8x16xf16>
+// CHECK:       %[[DPAS:.+]] = xegpu.dpas
+// CHECK-SAME:    %[[LHS_TRANSPOSED]], %[[RHS]], %[[ACC]]
+// CHECK-SAME:    {{.*}}-> vector<8x16xf32>
+// CHECK:       return %[[DPAS]]
+
+// -----
+
+#map = affine_map<(d0, d1, d2) -> (d0, d2)>
+#map1 = affine_map<(d0, d1, d2) -> (d1, d2)>
+#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>
+func.func @gemm_transpose_b(%lhs: vector<8x16xf16>, %rhs: vector<16x16xf16>,
+    %acc: vector<8x16xf32>) -> vector<8x16xf32> {
+  %3 = vector.contract
+    {indexing_maps = [#map, #map1, #map2],
+    iterator_types = ["parallel", "parallel", "reduction"],
+    kind = #vector.kind<add>} %lhs, %rhs, %acc
+    : vector<8x16xf16>, vector<16x16xf16> into vector<8x16xf32>
+  return %3 : vector<8x16xf32>
+}
+
+// CHECK-LABEL: @gemm_transpose_b(
+// CHECK-SAME:  %[[LHS:.+]]: vector<8x16xf16>,
+// CHECK-SAME:  %[[RHS:.+]]: vector<16x16xf16>,
+// CHECK-SAME:  %[[ACC:.+]]: vector<8x16xf32>
+// CHECK:       %[[RHS_TRANSPOSED:.+]] = vector.transpose %[[RHS]], [1, 0] : vector<16x16xf16> to vector<16x16xf16>
+// CHECK:       %[[DPAS:.+]] = xegpu.dpas
+// CHECK-SAME:    %[[LHS]], %[[RHS_TRANSPOSED]], %[[ACC]]
+// CHECK-SAME:    {{.*}}-> vector<8x16xf32>
+// CHECK:       return %[[DPAS]]
+
+// -----
+
 // For simplicity, only plain data layouts are currently supported.
 // VNNI packing is applied later as a separate lowering step.
 
@@ -130,39 +180,3 @@ func.func @negative_accumulator_shape(%lhs: vector<8x16xf16>, %rhs: vector<16x16
 
 // CHECK-LABEL: @negative_accumulator_shape(
 // CHECK:       vector.contract
-
-// -----
-
-#map = affine_map<(d0, d1, d2) -> (d2, d0)>
-#map1 = affine_map<(d0, d1, d2) -> (d2, d1)>
-#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>
-func.func @negative_gemm_transpose_a(%lhs: vector<16x8xf16>, %rhs: vector<16x16xf16>,
-    %acc: vector<8x16xf32>) -> vector<8x16xf32> {
-  %3 = vector.contract
-    {indexing_maps = [#map, #map1, #map2],
-    iterator_types = ["parallel", "parallel", "reduction"],
-    kind = #vector.kind<add>} %lhs, %rhs, %acc
-    : vector<16x8xf16>, vector<16x16xf16> into vector<8x16xf32>
-  return %3 : vector<8x16xf32>
-}
-
-// CHECK-LABEL: @negative_gemm_transpose_a(
-// CHECK:       vector.contract
-
-// -----
-
-#map = affine_map<(d0, d1, d2) -> (d0, d2)>
-#map1 = affine_map<(d0, d1, d2) -> (d1, d2)>
-#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>
-func.func @negative_gemm_transpose_b(%lhs: vector<8x16xf16>, %rhs: vector<16x16xf16>,
-    %acc: vector<8x16xf32>) -> vector<8x16xf32> {
-  %3 = vector.contract
-    {indexing_maps = [#map, #map1, #map2],
-    iterator_types = ["parallel", "parallel", "reduction"],
-    kind = #vector.kind<add>} %lhs, %rhs, %acc
-    : vector<8x16xf16>, vector<16x16xf16> into vector<8x16xf32>
-  return %3 : vector<8x16xf32>
-}
-
-// CHECK-LABEL: @negative_gemm_transpose_b(
-// CHECK:       vector.contract


        


More information about the Mlir-commits mailing list