[clang] [clang][SYCL] Emit "sycl-module-id" function attribute (PR #195965)
Yury Plyakhin via cfe-commits
cfe-commits at lists.llvm.org
Wed May 6 14:53:42 PDT 2026
https://github.com/YuriPlyakhin updated https://github.com/llvm/llvm-project/pull/195965
>From 65a4a7e5eb6edec26c196d62ef2a63ae13d163db Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Wed, 6 May 2026 01:07:34 +0200
Subject: [PATCH 1/2] [clang][SYCL] Emit "sycl-module-id" function attribute
Attach the "sycl-module-id" LLVM function attribute to SYCL device
functions that are candidates for entry points in device-code splitting.
The attribute value is the module identifier (translation unit name),
which clang-sycl-linker uses to group kernels by translation unit when
splitting device code.
The attribute is emitted at two sites:
1. SYCL kernel caller functions (spir_kernel) are synthesized by
EmitSYCLKernelCaller and do not go through EmitFunction, so the
attribute is set directly after SetSYCLKernelAttributes.
2. sycl_external function definitions go through
SetLLVMFunctionAttributesForDefinition; the attribute is added there
when SYCLIsDevice and SYCLExternalAttr are present.
Both sites call the new CodeGenModule::addSYCLModuleIdAttr helper.
Co-authored-by: Claude
---
clang/lib/CodeGen/CodeGenModule.cpp | 13 +++++++++
clang/lib/CodeGen/CodeGenModule.h | 5 ++++
clang/lib/CodeGen/CodeGenSYCL.cpp | 1 +
.../CodeGenSYCL/kernel-caller-entry-point.cpp | 6 ++---
clang/test/CodeGenSYCL/sycl-module-id.cpp | 27 +++++++++++++++++++
5 files changed, 49 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CodeGenSYCL/sycl-module-id.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 20a28c39af88a..e88fed1296667 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3028,6 +3028,19 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->addTypeMetadata(0, Id);
}
}
+
+ // Attach "sycl-module-id" to sycl_external function definitions to mark
+ // them as entry points for per-translation-unit device-code splitting.
+ if (getLangOpts().SYCLIsDevice) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->hasAttr<SYCLExternalAttr>())
+ addSYCLModuleIdAttr(F);
+ }
+}
+
+void CodeGenModule::addSYCLModuleIdAttr(llvm::Function *Fn) {
+ assert(getLangOpts().SYCLIsDevice);
+ Fn->addFnAttr("sycl-module-id", getModule().getModuleIdentifier());
}
void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) {
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index d62707a3355c9..44af19e295bed 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -2075,6 +2075,11 @@ class CodeGenModule : public CodeGenTypeCache {
void EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
ASTContext &Ctx);
+ /// Attach the "sycl-module-id" function attribute to \p Fn, recording the
+ /// translation unit name. Used on SYCL kernels and sycl_external functions
+ /// to enable per-translation-unit device-code splitting.
+ void addSYCLModuleIdAttr(llvm::Function *Fn);
+
/// Determine whether the definition must be emitted; if this returns \c
/// false, the definition can be emitted lazily if it's used.
bool MustBeEmitted(const ValueDecl *D);
diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index 5a52675de299d..7ca749a25fe6c 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -76,6 +76,7 @@ void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
CodeGenFunction CGF(*this);
SetLLVMFunctionAttributes(GlobalDecl(), FnInfo, Fn, false);
SetSYCLKernelAttributes(Fn, CGF);
+ addSYCLModuleIdAttr(Fn);
CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, Fn, FnInfo, Args,
SourceLocation(), SourceLocation());
CGF.EmitFunctionBody(OutlinedFnDecl->getBody());
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 7af4c83d1ba32..410988e16acdc 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -703,11 +703,11 @@ int main() {
// CHECK-SPIR-NEXT: ret void
// CHECK-SPIR-NEXT: }
-// CHECK-AMDGCN: #[[AMDGCN_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+// CHECK-AMDGCN: #[[AMDGCN_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"=
// CHECK-AMDGCN: #[[AMDGCN_ATTR1]] = { convergent nounwind }
//
-// CHECK-NVPTX: #[[NVPTX_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+// CHECK-NVPTX: #[[NVPTX_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"=
// CHECK-NVPTX: #[[NVPTX_ATTR1]] = { convergent nounwind }
//
-// CHECK-SPIR: #[[SPIR_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+// CHECK-SPIR: #[[SPIR_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"=
// CHECK-SPIR: #[[SPIR_ATTR1]] = { convergent nounwind }
diff --git a/clang/test/CodeGenSYCL/sycl-module-id.cpp b/clang/test/CodeGenSYCL/sycl-module-id.cpp
new file mode 100644
index 0000000000000..d9beded116a65
--- /dev/null
+++ b/clang/test/CodeGenSYCL/sycl-module-id.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown \
+// RUN: -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
+
+// Verify that the "sycl-module-id" function attribute is emitted for:
+// 1. SYCL kernels
+// 2. sycl_external functions
+
+// Required by sycl_kernel_entry_point semantics.
+template <typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
+
+template <typename KernelName, typename KernelType>
+[[clang::sycl_kernel_entry_point(KernelName)]]
+void kernel_single_task(KernelType kf) { kf(); }
+
+struct KN;
+struct K { void operator()() const {} };
+void use() { kernel_single_task<KN>(K{}); }
+
+[[clang::sycl_external]] int ext(int x) { return x + 1; }
+
+// Both the kernel and the sycl_external function must carry sycl-module-id
+// with a value equal to the module identifier (the source file path).
+// CHECK: source_filename = "[[MODID:.*]]"
+// CHECK-DAG: define {{.*}}spir_kernel {{.*}}@{{.*}}2KN{{.*}} #[[SATTR:[0-9]+]]
+// CHECK-DAG: define {{.*}}spir_func {{.*}}@_Z3exti{{.*}} #[[SATTR]]
+// CHECK: attributes #[[SATTR]] = { {{.*}}"sycl-module-id"="[[MODID]]"
>From f366b0dd36d1cd37a805ee87afac6bf202f6ef3c Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Wed, 6 May 2026 23:53:22 +0200
Subject: [PATCH 2/2] updated comment pre feedback
---
clang/lib/CodeGen/CodeGenModule.h | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 44af19e295bed..c7e168433e42c 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -2075,9 +2075,11 @@ class CodeGenModule : public CodeGenTypeCache {
void EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
ASTContext &Ctx);
- /// Attach the "sycl-module-id" function attribute to \p Fn, recording the
- /// translation unit name. Used on SYCL kernels and sycl_external functions
- /// to enable per-translation-unit device-code splitting.
+ /// Attach the "sycl-module-id" function attribute to \p Fn, to record the
+ /// module ID for the translation unit. This attribute is applied to SYCL
+ /// kernel entry point functions and functions declared with the
+ /// sycl_external attribute to enable them to be identified as entry points
+ /// by clang-sycl-linker during device-code splitting.
void addSYCLModuleIdAttr(llvm::Function *Fn);
/// Determine whether the definition must be emitted; if this returns \c
More information about the cfe-commits
mailing list