[clang] [clang-sycl-linker][NFC] Drop SYCL/device qualifiers from generic link step (PR #199777)
Yury Plyakhin via cfe-commits
cfe-commits at lists.llvm.org
Tue May 26 14:55:05 PDT 2026
https://github.com/YuriPlyakhin created https://github.com/llvm/llvm-project/pull/199777
The bitcode link phase has nothing SYCL-specific, as the removed TODO noted. Rename linkDeviceCode/getSYCLDeviceLibs and strip "SYCL"/"device" wording from the verbose output, error messages, and comments. Tests updated accordingly.
>From 6793aed127007d6b1db8fe31d0cc5b77f35ee98e Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Tue, 26 May 2026 23:49:51 +0200
Subject: [PATCH] [clang-sycl-linker][NFC] Drop SYCL/device qualifiers from
generic link step
The bitcode link phase has nothing SYCL-specific, as the removed TODO
noted. Rename linkDeviceCode/getSYCLDeviceLibs and strip "SYCL"/"device"
wording from the verbose output, error messages, and comments. Tests
updated accordingly.
---
.../OffloadTools/clang-sycl-linker/basic.ll | 10 +--
.../clang-sycl-linker/split-mode.ll | 6 +-
.../clang-sycl-linker/ClangSYCLLinker.cpp | 69 +++++++++----------
3 files changed, 41 insertions(+), 44 deletions(-)
diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
index 5bb15b3ca9b4f..f0e1c9c010ee4 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
@@ -9,7 +9,7 @@
; Test the dry run of a simple case to link two input files.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc %t/input2.bc -o %t/spirv.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=SIMPLE-FO
-; SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; SIMPLE-FO: link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; SIMPLE-FO-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: {{.*}}_0.spv
; SIMPLE-FO-NOT: {{.+}}
;
@@ -23,7 +23,7 @@
; RUN: touch %t/libs/lib2.bc
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc %t/input2.bc --library-path=%t/libs --device-libs=lib1.bc,lib2.bc -o a.spv 2>&1 \
; RUN: | FileCheck %s --check-prefix=DEVLIBS
-; DEVLIBS: sycl-device-link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc
+; DEVLIBS: link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc
; DEVLIBS-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: a_0.spv
;
; Test a simple case with a random file (not bitcode) as input.
@@ -38,13 +38,13 @@
; DEVLIBSERR1: Number of device library files cannot be zero
; RUN: not clang-sycl-linker --dry-run %t/input1.bc %t/input2.bc --library-path=%t/libs --device-libs=lib1.bc,lib2.bc,lib3.bc -o a.spv 2>&1 \
; RUN: | FileCheck %s --check-prefix=DEVLIBSERR2
-; DEVLIBSERR2: '{{.*}}lib3.bc' SYCL device library file is not found
+; DEVLIBSERR2: '{{.*}}lib3.bc' device library file is not found
;
; Test AOT compilation for an Intel GPU.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none -arch=bmg_g21 %t/input1.bc %t/input2.bc -o %t/aot-gpu.out 2>&1 \
; RUN: --ocloc-options="-a -b" \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-GPU
-; AOT-INTEL-GPU: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; AOT-INTEL-GPU: link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; AOT-INTEL-GPU-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: [[SPIRVTRANSLATIONOUT:.*]]_0.spv
; AOT-INTEL-GPU-NEXT: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 -a -b {{.*}}-output [[SPIRVTRANSLATIONOUT]]_0.out -file [[SPIRVTRANSLATIONOUT]]_0.spv
;
@@ -56,7 +56,7 @@
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none -arch=graniterapids %t/input1.bc %t/input2.bc -o %t/aot-cpu.out 2>&1 \
; RUN: --opencl-aot-options="-a -b" \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-CPU
-; AOT-INTEL-CPU: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; AOT-INTEL-CPU: link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; AOT-INTEL-CPU-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: [[SPIRVTRANSLATIONOUT:.*]]_0.spv
; AOT-INTEL-CPU-NEXT: "{{.*}}opencl-aot{{.*}}" {{.*}}--device=cpu -a -b {{.*}}-o [[SPIRVTRANSLATIONOUT]]_0.out [[SPIRVTRANSLATIONOUT]]_0.spv
;
diff --git a/clang/test/OffloadTools/clang-sycl-linker/split-mode.ll b/clang/test/OffloadTools/clang-sycl-linker/split-mode.ll
index ab6ccfaf64e70..56a6b3e082550 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/split-mode.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/split-mode.ll
@@ -12,14 +12,14 @@
; Test the split mode ("none"): kernels from different TUs are not split into separate images.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t.bc -o %t-none.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=SPLIT-NONE
-; SPLIT-NONE: sycl-device-link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; SPLIT-NONE: link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; SPLIT-NONE-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: {{.*}}_0.spv
; SPLIT-NONE-NOT: {{.+}}
;
; Test the split mode ("kernel"): each SPIR_KERNEL function produces its own device image.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=kernel %t.bc -o %t-split-kernel.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=SPLIT-KERNEL
-; SPLIT-KERNEL: sycl-device-link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; SPLIT-KERNEL: link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; SPLIT-KERNEL-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, mode: kernel
; SPLIT-KERNEL-NEXT: [[SPLIT0:.*]].bc [kernel_c ]
; SPLIT-KERNEL-NEXT: [[SPLIT1:.*]].bc [kernel_b ]
@@ -39,7 +39,7 @@
; Test per-TU split ('source' explicitly provided)
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=source %t.bc -o %t-src.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=SPLIT-SRC
-; SPLIT-SRC: sycl-device-link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
+; SPLIT-SRC: link: inputs: {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
; SPLIT-SRC-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, mode: source
; SPLIT-SRC-NEXT: [[S0:.*]].bc [kernel_b kernel_c ]
; SPLIT-SRC-NEXT: [[S1:.*]].bc [kernel_a ]
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 88a09d0a3ecc7..92e2cfdf8f4eb 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -217,10 +217,9 @@ Expected<std::unique_ptr<Module>> getBitcodeModule(StringRef File,
return createStringError(Err.getMessage());
}
-/// Gather all SYCL device library files that will be linked with input device
-/// files.
+/// Gather all device library files.
/// The list of files and its location are passed from driver.
-Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) {
+Expected<SmallVector<std::string>> getDeviceLibs(const ArgList &Args) {
SmallVector<std::string> DeviceLibFiles;
StringRef LibraryPath;
if (Arg *A = Args.getLastArg(OPT_library_path_EQ))
@@ -236,7 +235,7 @@ Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) {
DeviceLibFiles.push_back(std::string(LibName));
else
return createStringError("'" + LibName +
- "' SYCL device library file is not found.");
+ "' device library file is not found.");
}
}
return DeviceLibFiles;
@@ -248,32 +247,26 @@ struct LinkResult {
llvm::Triple TargetTriple;
};
-/// TODO: There is nothing SYCL specific in linkDeviceCode function. Remove:
-/// 1. Mentions of SYCL.
-/// 2. "fat" file formats. This linker shouldn't refer to input files as
-/// "device code"/"device libraries".
-
/// Following tasks are performed:
/// 1. Resolve the target triple: use --triple= when given, otherwise take the
/// first input that supplies a triple as canonical. Issue an error if any
/// triple inputs disagree.
-/// 2. Link all SYCL device bitcode images into one image. Device linking is
-/// performed using the linkInModule API.
-/// 3. Gather all SYCL device library bitcode images.
+/// 2. Link all input bitcode images into one image using the linkInModule API.
+/// 3. Gather all device library bitcode images.
/// 4. Link all the images gathered in Step 3 with the output of Step 2 using
/// linkInModule API. LinkOnlyNeeded flag is used.
-Expected<LinkResult> linkDeviceCode(ArrayRef<std::string> InputFiles,
- const ArgList &Args, LLVMContext &C) {
- llvm::TimeTraceScope TimeScope("SYCL link device code");
+Expected<LinkResult> link(ArrayRef<std::string> InputFiles, const ArgList &Args,
+ LLVMContext &C) {
+ llvm::TimeTraceScope TimeScope("Link code");
assert(InputFiles.size() && "No inputs to link");
- // Get all SYCL device library files, if any.
- auto SYCLDeviceLibFiles = getSYCLDeviceLibs(Args);
- if (!SYCLDeviceLibFiles)
- return SYCLDeviceLibFiles.takeError();
+ // Get all device library files, if any.
+ Expected<SmallVector<std::string>> DeviceLibFiles = getDeviceLibs(Args);
+ if (!DeviceLibFiles)
+ return DeviceLibFiles.takeError();
- // Create a new file to write the linked device file to.
+ // Create a new file to write the linked file to.
auto BitcodeOutput =
createTempFile(Args, sys::path::filename(OutputFile), "bc");
if (!BitcodeOutput)
@@ -281,17 +274,16 @@ Expected<LinkResult> linkDeviceCode(ArrayRef<std::string> InputFiles,
if (Verbose || DryRun) {
std::string Inputs = llvm::join(InputFiles.begin(), InputFiles.end(), ", ");
- std::string LibInputs = llvm::join((*SYCLDeviceLibFiles).begin(),
- (*SYCLDeviceLibFiles).end(), ", ");
- errs() << formatv(
- "sycl-device-link: inputs: {0} libfiles: {1} output: {2}\n", Inputs,
- LibInputs, *BitcodeOutput);
+ std::string LibInputs =
+ llvm::join((*DeviceLibFiles).begin(), (*DeviceLibFiles).end(), ", ");
+ errs() << formatv("link: inputs: {0} libfiles: {1} output: {2}\n", Inputs,
+ LibInputs, *BitcodeOutput);
}
- // Link SYCL device input files. Resolve the target triple.
+ // Link input files. Resolve the target triple.
llvm::Triple TargetTriple(Args.getLastArgValue(OPT_triple_EQ));
StringRef TripleSource = TargetTriple.empty() ? "" : "--triple=";
- auto LinkerOutput = std::make_unique<Module>("sycl-device-link", C);
+ auto LinkerOutput = std::make_unique<Module>("linker-output", C);
Linker L(*LinkerOutput);
for (auto &File : InputFiles) {
@@ -319,8 +311,8 @@ Expected<LinkResult> linkDeviceCode(ArrayRef<std::string> InputFiles,
return createStringError(
"Target triple must be specified or inferable from inputs");
- // Link in SYCL device library files.
- for (auto &File : *SYCLDeviceLibFiles) {
+ // Link in device library files.
+ for (auto &File : *DeviceLibFiles) {
auto LibMod = getBitcodeModule(File, C);
if (!LibMod)
return LibMod.takeError();
@@ -417,7 +409,7 @@ static Error runCodeGen(StringRef File, const llvm::Triple &TargetTriple,
/// \param OutputFile The output file name.
/// \param Args Encompasses all arguments required for linking and wrapping
/// device code and will be parsed to generate options required to be passed
-/// into the SYCL AOT compilation step.
+/// into the AOT compilation step.
static Error runAOTCompileIntelCPU(StringRef InputFile, StringRef OutputFile,
const ArgList &Args) {
SmallVector<StringRef, 8> CmdArgs;
@@ -445,7 +437,7 @@ static Error runAOTCompileIntelCPU(StringRef InputFile, StringRef OutputFile,
/// \param OutputFile The output file name.
/// \param Args Encompasses all arguments required for linking and wrapping
/// device code and will be parsed to generate options required to be passed
-/// into the SYCL AOT compilation step.
+/// into the AOT compilation step.
static Error runAOTCompileIntelGPU(StringRef InputFile, StringRef OutputFile,
const ArgList &Args) {
SmallVector<StringRef, 8> CmdArgs;
@@ -481,7 +473,7 @@ static Error runAOTCompileIntelGPU(StringRef InputFile, StringRef OutputFile,
/// \param OutputFile The output file name.
/// \param Args Encompasses all arguments required for linking and wrapping
/// device code and will be parsed to generate options required to be passed
-/// into the SYCL AOT compilation step.
+/// into the AOT compilation step.
static Error runAOTCompile(StringRef InputFile, StringRef OutputFile,
const ArgList &Args) {
StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
@@ -653,15 +645,20 @@ static bool canSkipModuleSplit(IRSplitMode Mode, const Module &M,
}
/// Performs the following steps:
-/// 1. Link input device code (user code and SYCL device library code).
-/// 2. Run SPIR-V code generation.
+/// 1. Link all input bitcode files together with device library files.
+/// 2. Optionally split the linked module according to the requested
+/// IRSplitMode.
+/// 3. Run SPIR-V code generation on each (split) module.
+/// 4. Optionally run AOT compilation when targeting an Intel offload arch.
+/// 5. Pack the resulting images into a single OffloadBinary written to the
+/// output file.
Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
llvm::TimeTraceScope TimeScope("SYCL device linking");
LLVMContext C;
- // Link all input bitcode files and SYCL device library files, if any.
- Expected<LinkResult> LinkedOrErr = linkDeviceCode(Files, Args, C);
+ // Link all input bitcode files and device library files, if any.
+ Expected<LinkResult> LinkedOrErr = link(Files, Args, C);
if (!LinkedOrErr)
return LinkedOrErr.takeError();
LinkResult &Result = *LinkedOrErr;
More information about the cfe-commits
mailing list