https://github.com/YuriPlyakhin updated 
https://github.com/llvm/llvm-project/pull/215437

>From 07ad88603214a05f58c89b41600710c920392e07 Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <[email protected]>
Date: Tue, 7 Jul 2026 00:36:50 +0200
Subject: [PATCH 1/4] [clang][SYCL] Emit non-exported device symbols with
 internal/linkonce_odr linkage

Add SYCL device-side linkage handling for relocatable (RDC) and
non-relocatable (no-RDC) device code compilation.

SYCL device compilation defaults to RDC. The driver now passes -fgpu-rdc
to the SYCL device -cc1 invocation by default (disabled with
-fno-gpu-rdc), setting the GPURelocatableDeviceCode LangOpt.

In getLLVMLinkageForDeclarator, SYCL device symbols that are not part of
the module interface (not SYCL kernels and not marked
[[clang::sycl_external]]) are emitted with linkonce_odr linkage in RDC
mode (enabling cross-translation-unit deduplication) and internal
linkage in no-RDC mode (single-TU device program, enabling more
aggressive optimization).

Co-Authored-By: Claude <[email protected]>
---
 clang/lib/CodeGen/CodeGenModule.cpp           | 13 +++++++++++++
 clang/lib/Driver/ToolChains/Clang.cpp         |  8 ++++++--
 .../amd-address-space-conversions.cpp         |  8 ++++----
 clang/test/CodeGenSYCL/function-attrs.cpp     |  4 ++--
 .../CodeGenSYCL/kernel-caller-entry-point.cpp |  6 +++---
 .../test/CodeGenSYCL/no-sycl-rdc-linkage.cpp  | 19 +++++++++++++++++++
 clang/test/CodeGenSYCL/sycl-external-attr.cpp |  2 +-
 clang/test/Driver/sycl-offload-jit.cpp        | 13 +++++++++++++
 8 files changed, 61 insertions(+), 12 deletions(-)
 create mode 100644 clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 5ed5385c90f26..9fb091d4f28af 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6821,6 +6821,19 @@ CodeGenModule::getLLVMLinkageForDeclarator(const 
DeclaratorDecl *D,
   if (Linkage == GVA_AvailableExternally)
     return llvm::GlobalValue::AvailableExternallyLinkage;
 
+  // SYCL device symbols that are not part of the module interface (i.e. not
+  // SYCL kernels and not marked with [[clang::sycl_external]]) are not
+  // externally visible. In RDC mode they are emitted with linkonce_odr linkage
+  // so equivalent definitions can be deduplicated across translation units.
+  // In non-RDC mode the whole device program lives in a single translation
+  // unit, so they are given internal linkage to enable more aggressive
+  // optimization.
+  if (getLangOpts().SYCLIsDevice && !D->hasAttr<SYCLKernelAttr>() &&
+      !D->hasAttr<SYCLExternalAttr>())
+    return getLangOpts().GPURelocatableDeviceCode
+               ? llvm::Function::LinkOnceODRLinkage
+               : llvm::Function::InternalLinkage;
+
   // Note that Apple's kernel linker doesn't support symbol
   // coalescing, so we need to avoid linkonce and weak linkages there.
   // Normally, this means we just map to internal, but for explicit
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 596df3ce9df92..9784e89e8231d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5171,8 +5171,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
                     options::OPT_no_offload_new_driver,
                     C.getActiveOffloadKinds() != Action::OFK_None));
 
-  bool IsRDCMode =
-      Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false);
+  // SYCL defaults to RDC; CUDA/HIP default to non-RDC.
+  bool IsRDCMode = Args.hasFlag(options::OPT_fgpu_rdc, 
options::OPT_fno_gpu_rdc,
+                                /*Default=*/IsSYCL);
 
   auto LTOMode = TC.getLTOMode(Args, JA.getOffloadingDeviceKind());
   bool IsUsingLTO = LTOMode != LTOK_None;
@@ -7398,6 +7399,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     }
   }
 
+  if (IsSYCLDevice && IsRDCMode)
+    CmdArgs.push_back("-fgpu-rdc");
+
   // Forward --no-offloadlib to -cc1.
   if (!Args.hasFlag(options::OPT_offloadlib, options::OPT_no_offloadlib, true))
     CmdArgs.push_back("--no-offloadlib");
diff --git a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp 
b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
index 9a25bab240fde..5bcb16764a166 100644
--- a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
+++ b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
@@ -121,8 +121,8 @@ void tmpl(T t) {}
   // CHECK-DAG: call void @_Z4tmplIPiEvT_(ptr noundef [[NoAS_LOAD5]])
 }
 
-// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) 
noundef %
-// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) 
noundef %
-// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) 
noundef %
-// CHECK-DAG: define linkonce_odr void @_Z4tmplIPiEvT_(ptr noundef %
+// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef 
%
+// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef 
%
+// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef 
%
+// CHECK-DAG: define {{.*}} void @_Z4tmplIPiEvT_(ptr noundef %
 
diff --git a/clang/test/CodeGenSYCL/function-attrs.cpp 
b/clang/test/CodeGenSYCL/function-attrs.cpp
index 60d3cf10055ec..548bd65f3be99 100644
--- a/clang/test/CodeGenSYCL/function-attrs.cpp
+++ b/clang/test/CodeGenSYCL/function-attrs.cpp
@@ -4,7 +4,7 @@
 
 int foo();
 
-// CHECK-LABEL: define dso_local spir_func void @_Z3barv(
+// CHECK-LABEL: define internal spir_func void @_Z3barv(
 // CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
@@ -17,7 +17,7 @@ void bar() {
   int a = foo();
 }
 
-// CHECK-LABEL: define dso_local spir_func noundef i32 @_Z3foov(
+// CHECK-LABEL: define internal spir_func noundef i32 @_Z3foov(
 // CHECK-SAME: ) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i32 1
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp 
b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index cc751cc683b59..6236fe74bd16c 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -394,7 +394,7 @@ int main() {
 // CHECK-AMDGCN-SAME:     (ptr noundef nonnull align 1 dereferenceable(1) 
%kernelFunc.ascast) #[[AMDGCN_ATTR1:[0-9]+]]
 // CHECK-AMDGCN-NEXT:   ret void
 // CHECK-AMDGCN-NEXT: }
-// CHECK-AMDGCN:      define linkonce_odr void @_ZNK21single_purpose_kernelclEv
+// CHECK-AMDGCN:      define {{.*}} void @_ZNK21single_purpose_kernelclEv
 //
 // CHECK-NVPTX:       Function Attrs: convergent mustprogress noinline 
norecurse nounwind optnone
 // CHECK-NVPTX-NEXT:  define dso_local ptx_kernel void 
@_ZTS26single_purpose_kernel_name
@@ -404,7 +404,7 @@ int main() {
 // CHECK-NVPTX-SAME:      (ptr noundef nonnull align 1 dereferenceable(1) 
%kernelFunc) #[[NVPTX_ATTR1:[0-9]+]]
 // CHECK-NVPTX-NEXT:    ret void
 // CHECK-NVPTX-NEXT:  }
-// CHECK-NVPTX:       define linkonce_odr void @_ZNK21single_purpose_kernelclEv
+// CHECK-NVPTX:       define {{.*}} void @_ZNK21single_purpose_kernelclEv
 //
 // CHECK-SPIR:        Function Attrs: convergent mustprogress noinline 
norecurse nounwind optnone
 // CHECK-SPIR-NEXT:   define {{[a-z_ ]*}}spir_kernel void 
@_ZTS26single_purpose_kernel_name
@@ -415,7 +415,7 @@ int main() {
 // CHECK-SPIR-SAME:       (ptr addrspace(4) noundef align 1 
dereferenceable_or_null(1) %kernelFunc.ascast) #[[SPIR_ATTR1:[0-9]+]]
 // CHECK-SPIR-NEXT:     ret void
 // CHECK-SPIR-NEXT:   }
-// CHECK-SPIR:        define linkonce_odr spir_func void 
@_ZNK21single_purpose_kernelclEv
+// CHECK-SPIR:        define {{.*}} spir_func void 
@_ZNK21single_purpose_kernelclEv
 
 // IR for the SYCL kernel caller function generated for kernel_single_task with
 // lambda_kernel_name as the SYCL kernel name type.
diff --git a/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp 
b/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp
new file mode 100644
index 0000000000000..0eabd6ace5335
--- /dev/null
+++ b/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsycl-is-device -triple spirv64 -fgpu-rdc -emit-llvm %s -o 
- | FileCheck --check-prefixes=CHECK,RDC %s
+// RUN: %clang_cc1 -fsycl-is-device -triple spirv64 -emit-llvm %s -o - | 
FileCheck --check-prefixes=CHECK,NORDC %s
+
+// This test verifies the linkage of SYCL device symbols.
+//  * In RDC mode non-exported device functions get linkonce_odr
+//    linkage so they can be deduplicated across translation units.
+//  * In non-RDC mode they get internal linkage.
+//  * Functions marked [[clang::sycl_external]] stay externally visible in 
both modes.
+
+// External linkage prints as nothing in LLVM IR, so the 'exported' check
+// asserts by omission.
+// CHECK-DAG: define{{ }}spir_func noundef i32 @_Z8exportedi
+
+// RDC-DAG:   define linkonce_odr spir_func noundef i32 @_Z6helperi
+// NORDC-DAG: define internal spir_func noundef i32 @_Z6helperi
+
+int helper(int x) { return x * 2; }
+
+[[clang::sycl_external]] int exported(int x) { return helper(x); }
diff --git a/clang/test/CodeGenSYCL/sycl-external-attr.cpp 
b/clang/test/CodeGenSYCL/sycl-external-attr.cpp
index 2c22e65874713..f77b58733e422 100644
--- a/clang/test/CodeGenSYCL/sycl-external-attr.cpp
+++ b/clang/test/CodeGenSYCL/sycl-external-attr.cpp
@@ -54,7 +54,7 @@ class C {
 int ret1() { return 1; }
 [[clang::sycl_external]] int withAttr() { return ret1(); }
 // CHECK: define dso_local spir_func noundef i32 @_Z8withAttrv
-// CHECK: define dso_local spir_func noundef i32 @_Z4ret1v
+// CHECK: define internal spir_func noundef i32 @_Z4ret1v
 
 template <typename T>
 [[clang::sycl_external]] void tFunc1(T arg) {}
diff --git a/clang/test/Driver/sycl-offload-jit.cpp 
b/clang/test/Driver/sycl-offload-jit.cpp
index c8eff1a4dd28f..2d40f2af2202c 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -47,6 +47,19 @@
 // CHK-FSYCL-IS-DEVICE: "-cc1"{{.*}} "-fsycl-is-device" {{.*}} "-emit-llvm-bc"
 // CHK-FSYCL-IS-HOST: "-cc1"{{.*}} "-fsycl-is-host"
 
+/// Check that SYCL device compilation defaults to relocatable device code
+/// (-fgpu-rdc is passed to the device -cc1 invocation) and that -fno-gpu-rdc
+/// disables it.
+// RUN: %clang -### -fsycl -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHK-SYCL-RDC %s
+// RUN: %clang -### -fsycl -fgpu-rdc -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHK-SYCL-RDC %s
+// RUN: %clang -### -fsycl -fno-gpu-rdc -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHK-SYCL-NORDC %s
+// CHK-SYCL-RDC: "-cc1"{{.*}} "-fsycl-is-device" {{.*}} "-fgpu-rdc"
+// CHK-SYCL-NORDC: "-cc1"{{.*}} "-fsycl-is-device"
+// CHK-SYCL-NORDC-NOT: "-fgpu-rdc"
+
 // Check that --allow-partial-linkage and --create-library are not passed to
 // clang-linker-wrapper for SYCL (they are spirv-link flags, not 
clang-sycl-linker flags).
 // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl %s 2>&1 \

>From 46d7a332b95f8e04679c9854a1906f349b9bb860 Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <[email protected]>
Date: Tue, 11 Aug 2026 20:29:56 +0200
Subject: [PATCH 2/4] addressed sarnex feedback

---
 clang/lib/Driver/ToolChains/Clang.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 9784e89e8231d..489b1f99eed7b 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7386,9 +7386,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
                       options::OPT_fno_hip_kernel_arg_name);
   }
 
+  if ((IsCuda || IsHIP || IsSYCLDevice) && IsRDCMode)
+    CmdArgs.push_back("-fgpu-rdc");
+
   if (IsCuda || IsHIP) {
-    if (IsRDCMode)
-      CmdArgs.push_back("-fgpu-rdc");
     Args.addOptInFlag(CmdArgs, options::OPT_fgpu_defer_diag,
                       options::OPT_fno_gpu_defer_diag);
     if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads,
@@ -7399,9 +7400,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     }
   }
 
-  if (IsSYCLDevice && IsRDCMode)
-    CmdArgs.push_back("-fgpu-rdc");
-
   // Forward --no-offloadlib to -cc1.
   if (!Args.hasFlag(options::OPT_offloadlib, options::OPT_no_offloadlib, true))
     CmdArgs.push_back("--no-offloadlib");

>From 527d44050fb176248e1ad14e4e442a44b99ab7ad Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <[email protected]>
Date: Wed, 12 Aug 2026 20:24:01 +0200
Subject: [PATCH 3/4] reverted linkage change, added __CLANG_RDC__ for SYCL

---
 clang/docs/SYCLSupport.md                     |  6 ++++++
 clang/lib/CodeGen/CodeGenModule.cpp           | 13 -------------
 clang/lib/Driver/ToolChains/Clang.cpp         |  2 +-
 clang/lib/Frontend/InitPreprocessor.cpp       |  4 ++--
 .../amd-address-space-conversions.cpp         |  8 ++++----
 clang/test/CodeGenSYCL/function-attrs.cpp     |  4 ++--
 .../CodeGenSYCL/kernel-caller-entry-point.cpp |  6 +++---
 .../test/CodeGenSYCL/no-sycl-rdc-linkage.cpp  | 19 -------------------
 clang/test/CodeGenSYCL/sycl-external-attr.cpp |  2 +-
 clang/test/Driver/sycl-offload-jit.cpp        | 12 ++++++------
 clang/test/Preprocessor/sycl-macro.cpp        | 10 ++++++++++
 11 files changed, 35 insertions(+), 51 deletions(-)
 delete mode 100644 clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp

diff --git a/clang/docs/SYCLSupport.md b/clang/docs/SYCLSupport.md
index 4271c8e12cdfa..f03497760ad15 100644
--- a/clang/docs/SYCLSupport.md
+++ b/clang/docs/SYCLSupport.md
@@ -11,6 +11,12 @@ library. More details are provided in
 [external 
document](https://github.com/intel/llvm/blob/sycl/sycl/doc/design/CompilerAndRuntimeDesign.md),
 which are going to be added to clang documentation in the future.
 
+## Predefined Macros
+
+| Macro | Description |
+| --- | --- |
+| `__CLANG_RDC__` | Defined when Clang is compiling code in Relocatable Device 
Code (RDC) mode. RDC is necessary for linking device codes across translation 
units. It is enabled by default for SYCL and can be disabled with 
`-fno-gpu-rdc` compiler option. |
+
 ## Address space handling
 
 The SYCL specification represents pointers to disjoint memory regions using C++
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 9fb091d4f28af..5ed5385c90f26 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6821,19 +6821,6 @@ CodeGenModule::getLLVMLinkageForDeclarator(const 
DeclaratorDecl *D,
   if (Linkage == GVA_AvailableExternally)
     return llvm::GlobalValue::AvailableExternallyLinkage;
 
-  // SYCL device symbols that are not part of the module interface (i.e. not
-  // SYCL kernels and not marked with [[clang::sycl_external]]) are not
-  // externally visible. In RDC mode they are emitted with linkonce_odr linkage
-  // so equivalent definitions can be deduplicated across translation units.
-  // In non-RDC mode the whole device program lives in a single translation
-  // unit, so they are given internal linkage to enable more aggressive
-  // optimization.
-  if (getLangOpts().SYCLIsDevice && !D->hasAttr<SYCLKernelAttr>() &&
-      !D->hasAttr<SYCLExternalAttr>())
-    return getLangOpts().GPURelocatableDeviceCode
-               ? llvm::Function::LinkOnceODRLinkage
-               : llvm::Function::InternalLinkage;
-
   // Note that Apple's kernel linker doesn't support symbol
   // coalescing, so we need to avoid linkonce and weak linkages there.
   // Normally, this means we just map to internal, but for explicit
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 489b1f99eed7b..86ee12cd82ae7 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7386,7 +7386,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
                       options::OPT_fno_hip_kernel_arg_name);
   }
 
-  if ((IsCuda || IsHIP || IsSYCLDevice) && IsRDCMode)
+  if ((IsCuda || IsHIP || IsSYCL) && IsRDCMode)
     CmdArgs.push_back("-fgpu-rdc");
 
   if (IsCuda || IsHIP) {
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp 
b/clang/lib/Frontend/InitPreprocessor.cpp
index 349628c3439bf..7f32f70fe52a3 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -585,9 +585,9 @@ static void InitializeStandardPredefinedMacros(const 
TargetInfo &TI,
   // Not "standard" per se, but available even with the -undef flag.
   if (LangOpts.AsmPreprocessor)
     Builder.defineMacro("__ASSEMBLER__");
+  if ((LangOpts.CUDA || LangOpts.isSYCL()) && 
LangOpts.GPURelocatableDeviceCode)
+    Builder.defineMacro("__CLANG_RDC__");
   if (LangOpts.CUDA) {
-    if (LangOpts.GPURelocatableDeviceCode)
-      Builder.defineMacro("__CLANG_RDC__");
     if (!LangOpts.HIP)
       Builder.defineMacro("__CUDA__");
     if (LangOpts.GPUDefaultStream ==
diff --git a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp 
b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
index 5bcb16764a166..9a25bab240fde 100644
--- a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
+++ b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp
@@ -121,8 +121,8 @@ void tmpl(T t) {}
   // CHECK-DAG: call void @_Z4tmplIPiEvT_(ptr noundef [[NoAS_LOAD5]])
 }
 
-// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) noundef 
%
-// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) noundef 
%
-// CHECK-DAG: define {{.*}} void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) noundef 
%
-// CHECK-DAG: define {{.*}} void @_Z4tmplIPiEvT_(ptr noundef %
+// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS1iEvT_(ptr addrspace(1) 
noundef %
+// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS3iEvT_(ptr addrspace(3) 
noundef %
+// CHECK-DAG: define linkonce_odr void @_Z4tmplIPU3AS5iEvT_(ptr addrspace(5) 
noundef %
+// CHECK-DAG: define linkonce_odr void @_Z4tmplIPiEvT_(ptr noundef %
 
diff --git a/clang/test/CodeGenSYCL/function-attrs.cpp 
b/clang/test/CodeGenSYCL/function-attrs.cpp
index 548bd65f3be99..60d3cf10055ec 100644
--- a/clang/test/CodeGenSYCL/function-attrs.cpp
+++ b/clang/test/CodeGenSYCL/function-attrs.cpp
@@ -4,7 +4,7 @@
 
 int foo();
 
-// CHECK-LABEL: define internal spir_func void @_Z3barv(
+// CHECK-LABEL: define dso_local spir_func void @_Z3barv(
 // CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
@@ -17,7 +17,7 @@ void bar() {
   int a = foo();
 }
 
-// CHECK-LABEL: define internal spir_func noundef i32 @_Z3foov(
+// CHECK-LABEL: define dso_local spir_func noundef i32 @_Z3foov(
 // CHECK-SAME: ) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    ret i32 1
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp 
b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 6236fe74bd16c..cc751cc683b59 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -394,7 +394,7 @@ int main() {
 // CHECK-AMDGCN-SAME:     (ptr noundef nonnull align 1 dereferenceable(1) 
%kernelFunc.ascast) #[[AMDGCN_ATTR1:[0-9]+]]
 // CHECK-AMDGCN-NEXT:   ret void
 // CHECK-AMDGCN-NEXT: }
-// CHECK-AMDGCN:      define {{.*}} void @_ZNK21single_purpose_kernelclEv
+// CHECK-AMDGCN:      define linkonce_odr void @_ZNK21single_purpose_kernelclEv
 //
 // CHECK-NVPTX:       Function Attrs: convergent mustprogress noinline 
norecurse nounwind optnone
 // CHECK-NVPTX-NEXT:  define dso_local ptx_kernel void 
@_ZTS26single_purpose_kernel_name
@@ -404,7 +404,7 @@ int main() {
 // CHECK-NVPTX-SAME:      (ptr noundef nonnull align 1 dereferenceable(1) 
%kernelFunc) #[[NVPTX_ATTR1:[0-9]+]]
 // CHECK-NVPTX-NEXT:    ret void
 // CHECK-NVPTX-NEXT:  }
-// CHECK-NVPTX:       define {{.*}} void @_ZNK21single_purpose_kernelclEv
+// CHECK-NVPTX:       define linkonce_odr void @_ZNK21single_purpose_kernelclEv
 //
 // CHECK-SPIR:        Function Attrs: convergent mustprogress noinline 
norecurse nounwind optnone
 // CHECK-SPIR-NEXT:   define {{[a-z_ ]*}}spir_kernel void 
@_ZTS26single_purpose_kernel_name
@@ -415,7 +415,7 @@ int main() {
 // CHECK-SPIR-SAME:       (ptr addrspace(4) noundef align 1 
dereferenceable_or_null(1) %kernelFunc.ascast) #[[SPIR_ATTR1:[0-9]+]]
 // CHECK-SPIR-NEXT:     ret void
 // CHECK-SPIR-NEXT:   }
-// CHECK-SPIR:        define {{.*}} spir_func void 
@_ZNK21single_purpose_kernelclEv
+// CHECK-SPIR:        define linkonce_odr spir_func void 
@_ZNK21single_purpose_kernelclEv
 
 // IR for the SYCL kernel caller function generated for kernel_single_task with
 // lambda_kernel_name as the SYCL kernel name type.
diff --git a/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp 
b/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp
deleted file mode 100644
index 0eabd6ace5335..0000000000000
--- a/clang/test/CodeGenSYCL/no-sycl-rdc-linkage.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clang_cc1 -fsycl-is-device -triple spirv64 -fgpu-rdc -emit-llvm %s -o 
- | FileCheck --check-prefixes=CHECK,RDC %s
-// RUN: %clang_cc1 -fsycl-is-device -triple spirv64 -emit-llvm %s -o - | 
FileCheck --check-prefixes=CHECK,NORDC %s
-
-// This test verifies the linkage of SYCL device symbols.
-//  * In RDC mode non-exported device functions get linkonce_odr
-//    linkage so they can be deduplicated across translation units.
-//  * In non-RDC mode they get internal linkage.
-//  * Functions marked [[clang::sycl_external]] stay externally visible in 
both modes.
-
-// External linkage prints as nothing in LLVM IR, so the 'exported' check
-// asserts by omission.
-// CHECK-DAG: define{{ }}spir_func noundef i32 @_Z8exportedi
-
-// RDC-DAG:   define linkonce_odr spir_func noundef i32 @_Z6helperi
-// NORDC-DAG: define internal spir_func noundef i32 @_Z6helperi
-
-int helper(int x) { return x * 2; }
-
-[[clang::sycl_external]] int exported(int x) { return helper(x); }
diff --git a/clang/test/CodeGenSYCL/sycl-external-attr.cpp 
b/clang/test/CodeGenSYCL/sycl-external-attr.cpp
index f77b58733e422..2c22e65874713 100644
--- a/clang/test/CodeGenSYCL/sycl-external-attr.cpp
+++ b/clang/test/CodeGenSYCL/sycl-external-attr.cpp
@@ -54,7 +54,7 @@ class C {
 int ret1() { return 1; }
 [[clang::sycl_external]] int withAttr() { return ret1(); }
 // CHECK: define dso_local spir_func noundef i32 @_Z8withAttrv
-// CHECK: define internal spir_func noundef i32 @_Z4ret1v
+// CHECK: define dso_local spir_func noundef i32 @_Z4ret1v
 
 template <typename T>
 [[clang::sycl_external]] void tFunc1(T arg) {}
diff --git a/clang/test/Driver/sycl-offload-jit.cpp 
b/clang/test/Driver/sycl-offload-jit.cpp
index 2d40f2af2202c..6720e8d250381 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -47,17 +47,17 @@
 // CHK-FSYCL-IS-DEVICE: "-cc1"{{.*}} "-fsycl-is-device" {{.*}} "-emit-llvm-bc"
 // CHK-FSYCL-IS-HOST: "-cc1"{{.*}} "-fsycl-is-host"
 
-/// Check that SYCL device compilation defaults to relocatable device code
-/// (-fgpu-rdc is passed to the device -cc1 invocation) and that -fno-gpu-rdc
-/// disables it.
+/// Check that SYCL compilation defaults to relocatable device code (-fgpu-rdc
+/// is passed to both the device and the host -cc1 invocation) and that
+/// -fno-gpu-rdc disables it.
 // RUN: %clang -### -fsycl -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefix=CHK-SYCL-RDC %s
+// RUN:   | FileCheck -check-prefixes=CHK-SYCL-RDC,CHK-SYCL-RDC-HOST %s
 // RUN: %clang -### -fsycl -fgpu-rdc -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefix=CHK-SYCL-RDC %s
+// RUN:   | FileCheck -check-prefixes=CHK-SYCL-RDC,CHK-SYCL-RDC-HOST %s
 // RUN: %clang -### -fsycl -fno-gpu-rdc -c %s 2>&1 \
 // RUN:   | FileCheck -check-prefix=CHK-SYCL-NORDC %s
 // CHK-SYCL-RDC: "-cc1"{{.*}} "-fsycl-is-device" {{.*}} "-fgpu-rdc"
-// CHK-SYCL-NORDC: "-cc1"{{.*}} "-fsycl-is-device"
+// CHK-SYCL-RDC-HOST: "-cc1"{{.*}} "-fsycl-is-host" {{.*}} "-fgpu-rdc"
 // CHK-SYCL-NORDC-NOT: "-fgpu-rdc"
 
 // Check that --allow-partial-linkage and --create-library are not passed to
diff --git a/clang/test/Preprocessor/sycl-macro.cpp 
b/clang/test/Preprocessor/sycl-macro.cpp
index a509086f99e41..9537237f0d8de 100644
--- a/clang/test/Preprocessor/sycl-macro.cpp
+++ b/clang/test/Preprocessor/sycl-macro.cpp
@@ -7,8 +7,18 @@
 // RUN: %clang_cc1 %s -fsycl-is-device -sycl-std=2020 -E -dM | FileCheck 
--check-prefix=CHECK-SYCL-STD-2020 %s
 // RUN: %clang_cc1 %s -fsycl-is-device -E -dM | FileCheck 
--check-prefixes=CHECK-SYCL %s
 
+/// __CLANG_RDC__ tells a SYCL implementation whether device symbols may be
+/// referenced across translation units. It is predefined in both the device 
and
+/// the host pass, and only when relocatable device code is enabled.
+// RUN: %clang_cc1 %s -fsycl-is-device -fgpu-rdc -E -dM | FileCheck 
--check-prefix=CHECK-RDC %s
+// RUN: %clang_cc1 %s -fsycl-is-host -fgpu-rdc -E -dM | FileCheck 
--check-prefix=CHECK-RDC %s
+// RUN: %clang_cc1 %s -fsycl-is-device -E -dM | FileCheck 
--check-prefix=CHECK-NO-RDC %s
+// RUN: %clang_cc1 %s -fsycl-is-host -E -dM | FileCheck 
--check-prefix=CHECK-NO-RDC %s
+
 // CHECK-NOT:#define __SYCL_DEVICE_ONLY__ 1
 // CHECK-NOT:#define CL_SYCL_LANGUAGE_VERSION 121
 // CHECK-SYCL-STD:#define CL_SYCL_LANGUAGE_VERSION 121
 // CHECK-SYCL-STD-2020:#define SYCL_LANGUAGE_VERSION 202012
 // CHECK-SYCL:#define __SYCL_DEVICE_ONLY__ 1
+// CHECK-RDC:#define __CLANG_RDC__ 1
+// CHECK-NO-RDC-NOT:#define __CLANG_RDC__

>From 5f802419c50f83468a71e8ab5f4fc63463a44f0d Mon Sep 17 00:00:00 2001
From: Yury Plyakhin <[email protected]>
Date: Wed, 12 Aug 2026 11:56:42 -0700
Subject: [PATCH 4/4] Update clang/docs/SYCLSupport.md per sarnex feedback

Co-authored-by: Nick Sarnie <[email protected]>
---
 clang/docs/SYCLSupport.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/SYCLSupport.md b/clang/docs/SYCLSupport.md
index f03497760ad15..f97d1853980b1 100644
--- a/clang/docs/SYCLSupport.md
+++ b/clang/docs/SYCLSupport.md
@@ -15,7 +15,7 @@ which are going to be added to clang documentation in the 
future.
 
 | Macro | Description |
 | --- | --- |
-| `__CLANG_RDC__` | Defined when Clang is compiling code in Relocatable Device 
Code (RDC) mode. RDC is necessary for linking device codes across translation 
units. It is enabled by default for SYCL and can be disabled with 
`-fno-gpu-rdc` compiler option. |
+| `__CLANG_RDC__` | Defined when Clang is compiling code in Relocatable Device 
Code (RDC) mode. RDC is necessary for linking device code across translation 
units. It is enabled by default for SYCL and can be disabled with the 
`-fno-gpu-rdc` compiler option. |
 
 ## Address space handling
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to