https://github.com/YuriPlyakhin created https://github.com/llvm/llvm-project/pull/195965
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 >From edb1620e13b207f718376a192153ae3118accea5 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Wed, 6 May 2026 01:07:34 +0200 Subject: [PATCH] [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]]" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
