[Mlir-commits] [mlir] [MLIR][XeVM] XeVM to LLVM: Add conversion patterns for id ops (PR #162536)
Sang Ik Lee
llvmlistbot at llvm.org
Thu Oct 9 17:51:55 PDT 2025
https://github.com/silee2 updated https://github.com/llvm/llvm-project/pull/162536
>From 407c4d5f63c47f8658282339c400d10512ff582c Mon Sep 17 00:00:00 2001
From: "Lee, Sang Ik" <sang.ik.lee at intel.com>
Date: Tue, 7 Oct 2025 17:45:18 +0000
Subject: [PATCH 1/4] Add comments.
---
mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
index f449d90eb67a5..289cbc15ac0d8 100644
--- a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
+++ b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
@@ -714,6 +714,39 @@ class LLVMLoadStoreToOCLPattern : public OpConversionPattern<OpType> {
}
};
+//===----------------------------------------------------------------------===//
+// GPU index id operations
+//===----------------------------------------------------------------------===//
+/*
+// Launch Config ops
+// get_local_id
+xevm::WorkitemIdXOp;
+xevm::WorkitemIdYOp;
+xevm::WorkitemIdZOp;
+// get_local_size
+xevm::WorkgroupDimXOp;
+xevm::WorkgroupDimYOp;
+xevm::WorkgroupDimZOp;
+// get_group_id
+xevm::WorkgroupIdXOp;
+xevm::WorkgroupIdYOp;
+xevm::WorkgroupIdZOp;
+// get_num_groups
+xevm::GridDimXOp;
+xevm::GridDimYOp;
+xevm::GridDimZOp;
+// get_global_id : missing
+
+// Subgroup ops
+// get_sub_group_local_id
+xevm::LaneIdOp;
+// get_sub_group_id
+xevm::SubgroupIdOp;
+// get_sub_group_size
+xevm::SubgroupSizeOp;
+// get_num_sub_groups : missing
+*/
+
//===----------------------------------------------------------------------===//
// Pass Definition
//===----------------------------------------------------------------------===//
>From 5dd57885bc037125748d12650dabd8684265b2c7 Mon Sep 17 00:00:00 2001
From: "Lee, Sang Ik" <sang.ik.lee at intel.com>
Date: Wed, 8 Oct 2025 18:14:57 +0000
Subject: [PATCH 2/4] Add lowering patterns.
---
mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp | 119 +++++++++++++++++-
1 file changed, 116 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
index 289cbc15ac0d8..4214d09c3e5ef 100644
--- a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
+++ b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
@@ -719,6 +719,8 @@ class LLVMLoadStoreToOCLPattern : public OpConversionPattern<OpType> {
//===----------------------------------------------------------------------===//
/*
// Launch Config ops
+// dimidx - x, y, x - is fixed to i32
+// return type is set by XeVM type converter
// get_local_id
xevm::WorkitemIdXOp;
xevm::WorkitemIdYOp;
@@ -735,8 +737,77 @@ xevm::WorkgroupIdZOp;
xevm::GridDimXOp;
xevm::GridDimYOp;
xevm::GridDimZOp;
-// get_global_id : missing
+// get_global_id : to be added if needed
+*/
+// Helpers to get the OpenCL function name and dimension argument for each op.
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkitemIdXOp) {
+ return {"get_local_id", 0};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkitemIdYOp) {
+ return {"get_local_id", 1};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkitemIdZOp) {
+ return {"get_local_id", 2};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupDimXOp) {
+ return {"get_local_size", 0};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupDimYOp) {
+ return {"get_local_size", 1};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupDimZOp) {
+ return {"get_local_size", 2};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupIdXOp) {
+ return {"get_group_id", 0};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupIdYOp) {
+ return {"get_group_id", 1};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::WorkgroupIdZOp) {
+ return {"get_group_id", 2};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::GridDimXOp) {
+ return {"get_num_groups", 0};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::GridDimYOp) {
+ return {"get_num_groups", 1};
+}
+static std::pair<StringRef, int64_t> getConfig(xevm::GridDimZOp) {
+ return {"get_num_groups", 2};
+}
+/// Replace `xevm.*` with an `llvm.call` to the corresponding OpenCL func with
+/// a constant argument for the dimension - x, y or z.
+template <typename OpType>
+class LaunchConfigOpToOCLPattern : public OpConversionPattern<OpType> {
+ using OpConversionPattern<OpType>::OpConversionPattern;
+ LogicalResult
+ matchAndRewrite(OpType op, typename OpType::Adaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ Location loc = op->getLoc();
+ std::pair<StringRef, int64_t> config = getConfig(op);
+ std::string baseName = config.first.str();
+ Type dimTy = rewriter.getI32Type();
+ int64_t dim = config.second;
+ Value dimVal = LLVM::ConstantOp::create(rewriter, loc, dimTy,
+ static_cast<int64_t>(dim));
+ std::string func = mangle(baseName, {dimTy}, {true});
+ Type resTy = op.getType();
+ auto call =
+ createDeviceFunctionCall(rewriter, func, resTy, {dimTy}, {dimVal}, {},
+ noUnwindWillReturnAttrs, op.getOperation());
+ constexpr auto noModRef = LLVM::ModRefInfo::NoModRef;
+ auto memAttr = rewriter.getAttr<LLVM::MemoryEffectsAttr>(
+ /*other=*/noModRef,
+ /*argMem=*/noModRef, /*inaccessibleMem=*/noModRef);
+ call.setMemoryEffectsAttr(memAttr);
+ rewriter.replaceOp(op, call);
+ return success();
+ }
+};
+
+/*
// Subgroup ops
// get_sub_group_local_id
xevm::LaneIdOp;
@@ -744,9 +815,36 @@ xevm::LaneIdOp;
xevm::SubgroupIdOp;
// get_sub_group_size
xevm::SubgroupSizeOp;
-// get_num_sub_groups : missing
+// get_num_sub_groups : to be added if needed
*/
+// Helpers to get the OpenCL function name for each op.
+static StringRef getConfig(xevm::LaneIdOp) { return "get_sub_group_local_id"; }
+static StringRef getConfig(xevm::SubgroupIdOp) { return "get_sub_group_id"; }
+static StringRef getConfig(xevm::SubgroupSizeOp) {
+ return "get_sub_group_size";
+}
+template <typename OpType>
+class SubgroupOpWorkitemOpToOCLPattern : public OpConversionPattern<OpType> {
+ using OpConversionPattern<OpType>::OpConversionPattern;
+ LogicalResult
+ matchAndRewrite(OpType op, typename OpType::Adaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ std::string func = mangle(getConfig(op).str(), {});
+ Type resTy = op.getType();
+ auto call =
+ createDeviceFunctionCall(rewriter, func, resTy, {}, {}, {},
+ noUnwindWillReturnAttrs, op.getOperation());
+ constexpr auto noModRef = LLVM::ModRefInfo::NoModRef;
+ auto memAttr = rewriter.getAttr<LLVM::MemoryEffectsAttr>(
+ /*other=*/noModRef,
+ /*argMem=*/noModRef, /*inaccessibleMem=*/noModRef);
+ call.setMemoryEffectsAttr(memAttr);
+ rewriter.replaceOp(op, call);
+ return success();
+ }
+};
+
//===----------------------------------------------------------------------===//
// Pass Definition
//===----------------------------------------------------------------------===//
@@ -808,7 +906,22 @@ void ::mlir::populateXeVMToLLVMConversionPatterns(ConversionTarget &target,
LLVMLoadStoreToOCLPattern<LLVM::LoadOp>,
LLVMLoadStoreToOCLPattern<LLVM::StoreOp>,
BlockLoadStore1DToOCLPattern<BlockLoadOp>,
- BlockLoadStore1DToOCLPattern<BlockStoreOp>>(
+ BlockLoadStore1DToOCLPattern<BlockStoreOp>,
+ LaunchConfigOpToOCLPattern<WorkitemIdXOp>,
+ LaunchConfigOpToOCLPattern<WorkitemIdYOp>,
+ LaunchConfigOpToOCLPattern<WorkitemIdZOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupDimXOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupDimYOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupDimZOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupIdXOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupIdYOp>,
+ LaunchConfigOpToOCLPattern<WorkgroupIdZOp>,
+ LaunchConfigOpToOCLPattern<GridDimXOp>,
+ LaunchConfigOpToOCLPattern<GridDimYOp>,
+ LaunchConfigOpToOCLPattern<GridDimZOp>,
+ SubgroupOpWorkitemOpToOCLPattern<LaneIdOp>,
+ SubgroupOpWorkitemOpToOCLPattern<SubgroupIdOp>,
+ SubgroupOpWorkitemOpToOCLPattern<SubgroupSizeOp>>(
patterns.getContext());
}
>From 66ad232211e9d32255f92b8765bcdf53bdb33a3e Mon Sep 17 00:00:00 2001
From: "Lee, Sang Ik" <sang.ik.lee at intel.com>
Date: Wed, 8 Oct 2025 18:56:19 +0000
Subject: [PATCH 3/4] Add conversion test cases.
---
.../Conversion/XeVMToLLVM/xevm-to-llvm.mlir | 147 +++++++++++++++++-
1 file changed, 146 insertions(+), 1 deletion(-)
diff --git a/mlir/test/Conversion/XeVMToLLVM/xevm-to-llvm.mlir b/mlir/test/Conversion/XeVMToLLVM/xevm-to-llvm.mlir
index b31a973ffd6a1..72e70ff519b77 100644
--- a/mlir/test/Conversion/XeVMToLLVM/xevm-to-llvm.mlir
+++ b/mlir/test/Conversion/XeVMToLLVM/xevm-to-llvm.mlir
@@ -35,7 +35,7 @@ llvm.func @blockload2d(%a: !llvm.ptr<1>, %base_width_a: i32, %base_height_a: i32
// -----
// CHECK-LABEL: llvm.func spir_funccc @_Z41intel_sub_group_2d_block_read_16b_8r16x1cPU3AS1viiiDv2_iPt(
llvm.func @blockload2d_cache_control(%a: !llvm.ptr<1>, %base_width_a: i32, %base_height_a: i32, %base_pitch_a: i32, %x: i32, %y: i32) -> vector<8xi16> {
- // CHECK: xevm.DecorationCacheControl =
+ // CHECK: xevm.DecorationCacheControl =
// CHECK-SAME: 6442 : i32, 0 : i32, 1 : i32, 0 : i32
// CHECK-SAME: 6442 : i32, 1 : i32, 1 : i32, 0 : i32
%loaded_a = xevm.blockload2d %a, %base_width_a, %base_height_a, %base_pitch_a, %x, %y
@@ -345,3 +345,148 @@ llvm.func @blockstore_scalar(%ptr: !llvm.ptr<3>, %data: i64) {
xevm.blockstore %ptr, %data <{cache_control=#xevm.store_cache_control<L1wt_L2uc_L3wb>}> : (!llvm.ptr<3>, i64)
llvm.return
}
+
+// -----
+// CHECK-LABEL: llvm.func @local_id.x() -> i32 {
+llvm.func @local_id.x() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(0 : i32) : i32
+ // CHECK: %[[VAR1:.*]] = llvm.call spir_funccc @_Z12get_local_idj(%[[VAR0]])
+ // CHECK-SAME: {function_type = !llvm.func<i32 (i32)>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z12get_local_idj", visibility_ = 0 : i64, will_return} : (i32) -> i32
+ %1 = xevm.local_id.x : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @local_id.y() -> i32 {
+llvm.func @local_id.y() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(1 : i32) : i32
+ %1 = xevm.local_id.y : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @local_id.z() -> i32 {
+llvm.func @local_id.z() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %1 = xevm.local_id.z : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @local_size.x() -> i32 {
+llvm.func @local_size.x() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(0 : i32) : i32
+ // CHECK: %[[VAR1:.*]] = llvm.call spir_funccc @_Z14get_local_sizej(%[[VAR0]])
+ // CHECK-SAME: {function_type = !llvm.func<i32 (i32)>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z14get_local_sizej", visibility_ = 0 : i64, will_return} : (i32) -> i32
+ %1 = xevm.local_size.x : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @local_size.y() -> i32 {
+llvm.func @local_size.y() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(1 : i32) : i32
+ %1 = xevm.local_size.y : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @local_size.z() -> i32 {
+llvm.func @local_size.z() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %1 = xevm.local_size.z : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_id.x() -> i32 {
+llvm.func @group_id.x() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(0 : i32) : i32
+ // CHECK: %[[VAR1:.*]] = llvm.call spir_funccc @_Z12get_group_idj(%[[VAR0]])
+ // CHECK-SAME: {function_type = !llvm.func<i32 (i32)>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z12get_group_idj", visibility_ = 0 : i64, will_return} : (i32) -> i32
+ %1 = xevm.group_id.x : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_id.y() -> i32 {
+llvm.func @group_id.y() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(1 : i32) : i32
+ %1 = xevm.group_id.y : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_id.z() -> i32 {
+llvm.func @group_id.z() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %1 = xevm.group_id.z : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_count.x() -> i32 {
+llvm.func @group_count.x() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(0 : i32) : i32
+ // CHECK: %[[VAR1:.*]] = llvm.call spir_funccc @_Z14get_num_groupsj(%[[VAR0]])
+ // CHECK-SAME: {function_type = !llvm.func<i32 (i32)>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z14get_num_groupsj", visibility_ = 0 : i64, will_return} : (i32) -> i32
+ %1 = xevm.group_count.x : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_count.y() -> i32 {
+llvm.func @group_count.y() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(1 : i32) : i32
+ %1 = xevm.group_count.y : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func @group_count.z() -> i32 {
+llvm.func @group_count.z() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %1 = xevm.group_count.z : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func spir_funccc @_Z22get_sub_group_local_id() -> i32 attributes {no_unwind, will_return}
+llvm.func @lane_id() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.call spir_funccc @_Z22get_sub_group_local_id()
+ // CHECK-SAME: {function_type = !llvm.func<i32 ()>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z22get_sub_group_local_id", visibility_ = 0 : i64, will_return} : () -> i32
+ %1 = xevm.lane_id : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func spir_funccc @_Z18get_sub_group_size() -> i32 attributes {no_unwind, will_return}
+llvm.func @subgroup_size() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.call spir_funccc @_Z18get_sub_group_size()
+ // CHECK-SAME: {function_type = !llvm.func<i32 ()>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z18get_sub_group_size", visibility_ = 0 : i64, will_return} : () -> i32
+ %1 = xevm.subgroup_size : i32
+ llvm.return %1 : i32
+}
+
+// -----
+// CHECK-LABEL: llvm.func spir_funccc @_Z16get_sub_group_id() -> i32 attributes {no_unwind, will_return}
+llvm.func @subgroup_id() -> i32 {
+ // CHECK: %[[VAR0:.*]] = llvm.call spir_funccc @_Z16get_sub_group_id()
+ // CHECK-SAME: {function_type = !llvm.func<i32 ()>, linkage = #llvm.linkage<external>,
+ // CHECK-SAME: memory_effects = #llvm.memory_effects<other = none, argMem = none, inaccessibleMem = none>,
+ // CHECK-SAME: no_unwind, sym_name = "_Z16get_sub_group_id", visibility_ = 0 : i64, will_return} : () -> i32
+ %1 = xevm.subgroup_id : i32
+ llvm.return %1 : i32
+}
>From 7b294374d7dabcebebbb2e1ed063c09cb9543207 Mon Sep 17 00:00:00 2001
From: "Lee, Sang Ik" <sang.ik.lee at intel.com>
Date: Fri, 10 Oct 2025 00:20:04 +0000
Subject: [PATCH 4/4] Address reviewer comments.
---
mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
index 4214d09c3e5ef..f2769846abbd9 100644
--- a/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
+++ b/mlir/lib/Conversion/XeVMToLLVM/XeVMToLLVM.cpp
@@ -719,7 +719,7 @@ class LLVMLoadStoreToOCLPattern : public OpConversionPattern<OpType> {
//===----------------------------------------------------------------------===//
/*
// Launch Config ops
-// dimidx - x, y, x - is fixed to i32
+// dimidx - x, y, z - is fixed to i32
// return type is set by XeVM type converter
// get_local_id
xevm::WorkitemIdXOp;
@@ -786,10 +786,8 @@ class LaunchConfigOpToOCLPattern : public OpConversionPattern<OpType> {
matchAndRewrite(OpType op, typename OpType::Adaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
Location loc = op->getLoc();
- std::pair<StringRef, int64_t> config = getConfig(op);
- std::string baseName = config.first.str();
+ auto [baseName, dim] = getConfig(op);
Type dimTy = rewriter.getI32Type();
- int64_t dim = config.second;
Value dimVal = LLVM::ConstantOp::create(rewriter, loc, dimTy,
static_cast<int64_t>(dim));
std::string func = mangle(baseName, {dimTy}, {true});
More information about the Mlir-commits
mailing list