https://github.com/YuriPlyakhin updated https://github.com/llvm/llvm-project/pull/199777
>From 84ae86c7403516e22048145fdd2c9506673e8ea6 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Tue, 26 May 2026 23:49:51 +0200 Subject: [PATCH 1/8] [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; >From 1e117e814f24de3dad2f219118235c17beb84c66 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 02:12:34 +0200 Subject: [PATCH 2/8] addressed feedback --- clang/test/Driver/link-device-code.test | 2 +- .../OffloadTools/clang-sycl-linker/basic.ll | 9 +-- .../clang-sycl-linker/ClangSYCLLinker.cpp | 79 +++++++++++-------- clang/tools/clang-sycl-linker/SYCLLinkOpts.td | 15 ++-- 4 files changed, 59 insertions(+), 46 deletions(-) diff --git a/clang/test/Driver/link-device-code.test b/clang/test/Driver/link-device-code.test index eb75eaf1fe5c2..e1c58beb0d02c 100644 --- a/clang/test/Driver/link-device-code.test +++ b/clang/test/Driver/link-device-code.test @@ -8,7 +8,7 @@ # RUN: not clang-sycl-linker %t.bar.bc %t.baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS -# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc -device-libs=%t.libLLVMSYCL.bc -library-path= -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB +# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc --bc-library %t.libLLVMSYCL.bc -L "" -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB ; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}} ; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}} diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll index f0e1c9c010ee4..4ee3135904c56 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll @@ -21,7 +21,7 @@ ; RUN: mkdir -p %t/libs ; RUN: touch %t/libs/lib1.bc ; 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: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc %t/input2.bc --library-path=%t/libs --bc-library lib1.bc --bc-library lib2.bc -o a.spv 2>&1 \ ; RUN: | FileCheck %s --check-prefix=DEVLIBS ; DEVLIBS: link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc ; DEVLIBS-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: a_0.spv @@ -33,12 +33,9 @@ ; FILETYPEERROR: Unsupported file type ; ; Test to see if device library related errors are emitted. -; RUN: not clang-sycl-linker --dry-run %t/input1.bc %t/input2.bc --library-path=%t/libs --device-libs= -o a.spv 2>&1 \ -; RUN: | FileCheck %s --check-prefix=DEVLIBSERR1 -; 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: not clang-sycl-linker --dry-run %t/input1.bc %t/input2.bc --library-path=%t/libs --bc-library lib1.bc --bc-library lib2.bc --bc-library lib3.bc -o a.spv 2>&1 \ ; RUN: | FileCheck %s --check-prefix=DEVLIBSERR2 -; DEVLIBSERR2: '{{.*}}lib3.bc' device library file is not found +; DEVLIBSERR2: '{{.*}}lib3.bc' library file 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 \ diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp index 92e2cfdf8f4eb..9db3c7e3f83c6 100644 --- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp +++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp @@ -184,7 +184,7 @@ Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) { } Expected<SmallVector<std::string>> getInput(const ArgList &Args) { - // Collect all input bitcode files to be passed to the device linking stage. + // Collect all input bitcode files to be passed to the linking stage. SmallVector<std::string> BitcodeFiles; for (const opt::Arg *Arg : Args.filtered(OPT_INPUT)) { std::optional<std::string> Filename = std::string(Arg->getValue()); @@ -217,28 +217,39 @@ Expected<std::unique_ptr<Module>> getBitcodeModule(StringRef File, return createStringError(Err.getMessage()); } -/// Gather all device library files. -/// The list of files and its location are passed from driver. -Expected<SmallVector<std::string>> getDeviceLibs(const ArgList &Args) { - SmallVector<std::string> DeviceLibFiles; - StringRef LibraryPath; - if (Arg *A = Args.getLastArg(OPT_library_path_EQ)) - LibraryPath = A->getValue(); - if (Arg *A = Args.getLastArg(OPT_device_libs_EQ)) { - if (A->getValues().size() == 0) - return createStringError( - "Number of device library files cannot be zero."); - for (StringRef Val : A->getValues()) { - SmallString<128> LibName(LibraryPath); - llvm::sys::path::append(LibName, Val); - if (llvm::sys::fs::exists(LibName)) - DeviceLibFiles.push_back(std::string(LibName)); - else - return createStringError("'" + LibName + - "' device library file is not found."); - } +std::optional<std::string> findFile(StringRef Dir, const Twine &Name) { + SmallString<128> Path(Dir); + llvm::sys::path::append(Path, Name); + if (sys::fs::exists(Path)) + return static_cast<std::string>(Path); + return std::nullopt; +} + +std::optional<std::string> searchLibrary(StringRef Name, + ArrayRef<StringRef> SearchPaths) { + for (StringRef Dir : SearchPaths) + if (std::optional<std::string> File = findFile(Dir, Name)) + return File; + return std::nullopt; +} + +/// Gather all library files. The list of files and its location are passed from +/// driver. +Expected<SmallVector<std::string>> getBCLibraryNames(const ArgList &Args) { + SmallVector<StringRef> LibraryPaths; + for (const opt::Arg *Arg : Args.filtered(OPT_library_path)) + LibraryPaths.push_back(Arg->getValue()); + + SmallVector<std::string> LibraryFiles; + for (const opt::Arg *Arg : Args.filtered(OPT_bc_library_S)) { + std::optional<std::string> LibName = + searchLibrary(Arg->getValue(), LibraryPaths); + if (!LibName) + return createStringError("'%s' library file not found.", Arg->getValue()); + LibraryFiles.push_back(std::move(*LibName)); } - return DeviceLibFiles; + + return LibraryFiles; } struct LinkResult { @@ -252,7 +263,7 @@ struct LinkResult { /// first input that supplies a triple as canonical. Issue an error if any /// triple inputs disagree. /// 2. Link all input bitcode images into one image using the linkInModule API. -/// 3. Gather all device library bitcode images. +/// 3. Gather all 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> link(ArrayRef<std::string> InputFiles, const ArgList &Args, @@ -261,10 +272,10 @@ Expected<LinkResult> link(ArrayRef<std::string> InputFiles, const ArgList &Args, assert(InputFiles.size() && "No inputs to link"); - // Get all device library files, if any. - Expected<SmallVector<std::string>> DeviceLibFiles = getDeviceLibs(Args); - if (!DeviceLibFiles) - return DeviceLibFiles.takeError(); + // Get all library files. + Expected<SmallVector<std::string>> BCLibFiles = getBCLibraryNames(Args); + if (!BCLibFiles) + return BCLibFiles.takeError(); // Create a new file to write the linked file to. auto BitcodeOutput = @@ -275,7 +286,7 @@ Expected<LinkResult> link(ArrayRef<std::string> InputFiles, const ArgList &Args, if (Verbose || DryRun) { std::string Inputs = llvm::join(InputFiles.begin(), InputFiles.end(), ", "); std::string LibInputs = - llvm::join((*DeviceLibFiles).begin(), (*DeviceLibFiles).end(), ", "); + llvm::join((*BCLibFiles).begin(), (*BCLibFiles).end(), ", "); errs() << formatv("link: inputs: {0} libfiles: {1} output: {2}\n", Inputs, LibInputs, *BitcodeOutput); } @@ -311,8 +322,8 @@ Expected<LinkResult> link(ArrayRef<std::string> InputFiles, const ArgList &Args, return createStringError( "Target triple must be specified or inferable from inputs"); - // Link in device library files. - for (auto &File : *DeviceLibFiles) { + // Link in library files. + for (auto &File : *BCLibFiles) { auto LibMod = getBitcodeModule(File, C); if (!LibMod) return LibMod.takeError(); @@ -645,19 +656,19 @@ static bool canSkipModuleSplit(IRSplitMode Mode, const Module &M, } /// Performs the following steps: -/// 1. Link all input bitcode files together with device library files. +/// 1. Link all input bitcode files together with 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. +/// 4. Optionally run AOT compilation when targeting an Intel HW 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"); + llvm::TimeTraceScope TimeScope("SYCL linking"); LLVMContext C; - // Link all input bitcode files and device library files, if any. + // Link all input bitcode files and library files. Expected<LinkResult> LinkedOrErr = link(Files, Args, C); if (!LinkedOrErr) return LinkedOrErr.takeError(); diff --git a/clang/tools/clang-sycl-linker/SYCLLinkOpts.td b/clang/tools/clang-sycl-linker/SYCLLinkOpts.td index 171915c29bd93..de8bd75f752a1 100644 --- a/clang/tools/clang-sycl-linker/SYCLLinkOpts.td +++ b/clang/tools/clang-sycl-linker/SYCLLinkOpts.td @@ -17,12 +17,17 @@ def o : JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, def output : Separate<["--"], "output-file">, Alias<o>, Flags<[HelpHidden]>, HelpText<"Alias for -o">; -def library_path_EQ : Joined<["--", "-"], "library-path=">, - Flags<[HelpHidden]>, HelpText<"Add <dir> to the library search path">; +def library_path : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, + HelpText<"Add <dir> to the library search path">; +def library_path_S : Separate<["--", "-"], "library-path">, Flags<[HelpHidden]>, + Alias<library_path>; +def library_path_EQ : Joined<["--", "-"], "library-path=">, Flags<[HelpHidden]>, + Alias<library_path>; -def device_libs_EQ : CommaJoined<["--", "-"], "device-libs=">, - Flags<[LinkerOnlyOption]>, - HelpText<"A comma separated list of device libraries that are linked during the device link.">; +def bc_library_S : Separate<["--", "-"], "bc-library">, MetaVarName<"<name>">, + HelpText<"Search for LLVM bitcode library <name>. Library name is provided with extension, e.g. --bc-library foo.bc">; +def bc_library_EQ : Joined<["--", "-"], "bc-library=">, Flags<[HelpHidden]>, + Alias<bc_library_S>; def arch_EQ : Joined<["--", "-"], "arch=">, Flags<[LinkerOnlyOption]>, >From 8910f8307175ab3d1199bafb7b76c96dbe5db4da Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 02:28:38 +0200 Subject: [PATCH 3/8] fix lib search --- clang/test/Driver/link-device-code.test | 2 +- clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/test/Driver/link-device-code.test b/clang/test/Driver/link-device-code.test index e1c58beb0d02c..8673e7fc487b8 100644 --- a/clang/test/Driver/link-device-code.test +++ b/clang/test/Driver/link-device-code.test @@ -8,7 +8,7 @@ # RUN: not clang-sycl-linker %t.bar.bc %t.baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS -# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc --bc-library %t.libLLVMSYCL.bc -L "" -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB +# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc --bc-library %t.libLLVMSYCL.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB ; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}} ; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}} diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp index 9db3c7e3f83c6..554fab4b7f827 100644 --- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp +++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp @@ -227,6 +227,8 @@ std::optional<std::string> findFile(StringRef Dir, const Twine &Name) { std::optional<std::string> searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths) { + if (sys::fs::exists(Name)) + return Name.str(); for (StringRef Dir : SearchPaths) if (std::optional<std::string> File = findFile(Dir, Name)) return File; >From c5b897a11683ef0059b5530315e7f68992221a79 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 02:33:25 +0200 Subject: [PATCH 4/8] test clean up --- clang/test/Driver/Inputs/SYCL/bar.ll | 8 -- clang/test/Driver/Inputs/SYCL/baz.ll | 16 --- clang/test/Driver/Inputs/SYCL/foo.ll | 20 ---- clang/test/Driver/Inputs/SYCL/libLLVMSYCL.ll | 14 --- clang/test/Driver/link-device-code.test | 25 ----- .../OffloadTools/clang-sycl-linker/link.ll | 98 +++++++++++++++++++ 6 files changed, 98 insertions(+), 83 deletions(-) delete mode 100644 clang/test/Driver/Inputs/SYCL/bar.ll delete mode 100644 clang/test/Driver/Inputs/SYCL/baz.ll delete mode 100644 clang/test/Driver/Inputs/SYCL/foo.ll delete mode 100644 clang/test/Driver/Inputs/SYCL/libLLVMSYCL.ll delete mode 100644 clang/test/Driver/link-device-code.test create mode 100644 clang/test/OffloadTools/clang-sycl-linker/link.ll diff --git a/clang/test/Driver/Inputs/SYCL/bar.ll b/clang/test/Driver/Inputs/SYCL/bar.ll deleted file mode 100644 index 9f86b8aa54827..0000000000000 --- a/clang/test/Driver/Inputs/SYCL/bar.ll +++ /dev/null @@ -1,8 +0,0 @@ -target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" -target triple = "spirv64" - -define spir_func i32 @bar_func1(i32 %a, i32 %b) { -entry: - %res = add nsw i32 %b, %a - ret i32 %res -} diff --git a/clang/test/Driver/Inputs/SYCL/baz.ll b/clang/test/Driver/Inputs/SYCL/baz.ll deleted file mode 100644 index 1fd7e44881981..0000000000000 --- a/clang/test/Driver/Inputs/SYCL/baz.ll +++ /dev/null @@ -1,16 +0,0 @@ -target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" -target triple = "spirv64" - -define spir_func i32 @bar_func1(i32 %a, i32 %b) { -entry: - %mul = shl nsw i32 %a, 1 - %res = add nsw i32 %mul, %b - ret i32 %res -} - -define spir_func i32 @baz_func1(i32 %a) { -entry: - %add = add nsw i32 %a, 5 - %res = tail call spir_func i32 @bar_func1(i32 %a, i32 %add) - ret i32 %res -} diff --git a/clang/test/Driver/Inputs/SYCL/foo.ll b/clang/test/Driver/Inputs/SYCL/foo.ll deleted file mode 100644 index fbfd8c53bff9c..0000000000000 --- a/clang/test/Driver/Inputs/SYCL/foo.ll +++ /dev/null @@ -1,20 +0,0 @@ -target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" -target triple = "spirv64" - -define spir_func i32 @foo_func1(i32 %a, i32 %b) { -entry: - %call = tail call spir_func i32 @addFive(i32 %b) - %res = tail call spir_func i32 @bar_func1(i32 %a, i32 %call) - ret i32 %res -} - -declare spir_func i32 @bar_func1(i32, i32) - -declare spir_func i32 @addFive(i32) - -define spir_func i32 @foo_func2(i32 %c, i32 %d, i32 %e) { -entry: - %call = tail call spir_func i32 @foo_func1(i32 %c, i32 %d) - %res = mul nsw i32 %call, %e - ret i32 %res -} diff --git a/clang/test/Driver/Inputs/SYCL/libLLVMSYCL.ll b/clang/test/Driver/Inputs/SYCL/libLLVMSYCL.ll deleted file mode 100644 index b161bde3b0c1e..0000000000000 --- a/clang/test/Driver/Inputs/SYCL/libLLVMSYCL.ll +++ /dev/null @@ -1,14 +0,0 @@ -target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" -target triple = "spirv64" - -define spir_func i32 @addFive(i32 %a) { -entry: - %res = add nsw i32 %a, 5 - ret i32 %res -} - -define spir_func i32 @unusedFunc(i32 %a) { -entry: - %res = mul nsw i32 %a, 5 - ret i32 %res -} diff --git a/clang/test/Driver/link-device-code.test b/clang/test/Driver/link-device-code.test deleted file mode 100644 index 8673e7fc487b8..0000000000000 --- a/clang/test/Driver/link-device-code.test +++ /dev/null @@ -1,25 +0,0 @@ -# REQUIRES: spirv-registered-target - -# RUN: llvm-as %S/Inputs/SYCL/foo.ll -o %t.foo.bc -# RUN: llvm-as %S/Inputs/SYCL/bar.ll -o %t.bar.bc -# RUN: llvm-as %S/Inputs/SYCL/baz.ll -o %t.baz.bc -# RUN: llvm-as %S/Inputs/SYCL/libLLVMSYCL.ll -o %t.libLLVMSYCL.bc -# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-SIMPLE - -# RUN: not clang-sycl-linker %t.bar.bc %t.baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS - -# RUN: clang-sycl-linker %t.foo.bc %t.bar.bc --bc-library %t.libLLVMSYCL.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 | FileCheck %s --check-prefix=CHECK-DEVICE-LIB - -; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}} -; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}} -; CHECK-SIMPLE: define {{.*}}bar_func1{{.*}} -; CHECK-SIMPLE-NOT: define {{.*}}addFive{{.*}} -; CHECK-SIMPLE-NOT: define {{.*}}unusedFunc{{.*}} - -; CHECK-MULTIPLE-DEFS: error: Linking globals named {{.*}}bar_func1{{.*}} symbol multiply defined! - -; CHECK-DEVICE-LIB: define {{.*}}foo_func1{{.*}} -; CHECK-DEVICE-LIB: define {{.*}}foo_func2{{.*}} -; CHECK-DEVICE-LIB: define {{.*}}bar_func1{{.*}} -; CHECK-DEVICE-LIB: define {{.*}}addFive{{.*}} -; CHECK-DEVICE-LIB-NOT: define {{.*}}unusedFunc{{.*}} diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll b/clang/test/OffloadTools/clang-sycl-linker/link.ll new file mode 100644 index 0000000000000..62c63e23828a7 --- /dev/null +++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll @@ -0,0 +1,98 @@ +; Tests clang-sycl-linker linking behavior. +; +; REQUIRES: spirv-registered-target +; +; RUN: rm -rf %t && split-file %s %t +; RUN: llvm-as %t/foo.ll -o %t/foo.bc +; RUN: llvm-as %t/bar.ll -o %t/bar.bc +; RUN: llvm-as %t/baz.ll -o %t/baz.bc +; RUN: llvm-as %t/libLLVMSYCL.ll -o %t/libLLVMSYCL.bc +; +; Test linking two input files. +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-SIMPLE +; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}} +; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}} +; CHECK-SIMPLE: define {{.*}}bar_func1{{.*}} +; CHECK-SIMPLE-NOT: define {{.*}}addFive{{.*}} +; CHECK-SIMPLE-NOT: define {{.*}}unusedFunc{{.*}} +; +; Test that multiply defined symbols are reported as errors. +; RUN: not clang-sycl-linker %t/bar.bc %t/baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS +; CHECK-MULTIPLE-DEFS: error: Linking globals named {{.*}}bar_func1{{.*}} symbol multiply defined! +; +; Test linking with a device library file. +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libLLVMSYCL.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-DEVICE-LIB +; CHECK-DEVICE-LIB: define {{.*}}foo_func1{{.*}} +; CHECK-DEVICE-LIB: define {{.*}}foo_func2{{.*}} +; CHECK-DEVICE-LIB: define {{.*}}bar_func1{{.*}} +; CHECK-DEVICE-LIB: define {{.*}}addFive{{.*}} +; CHECK-DEVICE-LIB-NOT: define {{.*}}unusedFunc{{.*}} + +;--- foo.ll +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" +target triple = "spirv64" + +define spir_func i32 @foo_func1(i32 %a, i32 %b) { +entry: + %call = tail call spir_func i32 @addFive(i32 %b) + %res = tail call spir_func i32 @bar_func1(i32 %a, i32 %call) + ret i32 %res +} + +declare spir_func i32 @bar_func1(i32, i32) + +declare spir_func i32 @addFive(i32) + +define spir_func i32 @foo_func2(i32 %c, i32 %d, i32 %e) { +entry: + %call = tail call spir_func i32 @foo_func1(i32 %c, i32 %d) + %res = mul nsw i32 %call, %e + ret i32 %res +} + +;--- bar.ll +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" +target triple = "spirv64" + +define spir_func i32 @bar_func1(i32 %a, i32 %b) { +entry: + %res = add nsw i32 %b, %a + ret i32 %res +} + +;--- baz.ll +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" +target triple = "spirv64" + +define spir_func i32 @bar_func1(i32 %a, i32 %b) { +entry: + %mul = shl nsw i32 %a, 1 + %res = add nsw i32 %mul, %b + ret i32 %res +} + +define spir_func i32 @baz_func1(i32 %a) { +entry: + %add = add nsw i32 %a, 5 + %res = tail call spir_func i32 @bar_func1(i32 %a, i32 %add) + ret i32 %res +} + +;--- libLLVMSYCL.ll +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" +target triple = "spirv64" + +define spir_func i32 @addFive(i32 %a) { +entry: + %res = add nsw i32 %a, 5 + ret i32 %res +} + +define spir_func i32 @unusedFunc(i32 %a) { +entry: + %res = mul nsw i32 %a, 5 + ret i32 %res +} >From 10dd7229194c87a67b95231abf1415296e56bcd7 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 02:42:35 +0200 Subject: [PATCH 5/8] updated test --- clang/test/OffloadTools/clang-sycl-linker/link.ll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll b/clang/test/OffloadTools/clang-sycl-linker/link.ll index 62c63e23828a7..d675f0400b182 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/link.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll @@ -6,7 +6,7 @@ ; RUN: llvm-as %t/foo.ll -o %t/foo.bc ; RUN: llvm-as %t/bar.ll -o %t/bar.bc ; RUN: llvm-as %t/baz.ll -o %t/baz.bc -; RUN: llvm-as %t/libLLVMSYCL.ll -o %t/libLLVMSYCL.bc +; RUN: llvm-as %t/libfoo.ll -o %t/libfoo.bc ; ; Test linking two input files. ; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ @@ -22,8 +22,8 @@ ; RUN: | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS ; CHECK-MULTIPLE-DEFS: error: Linking globals named {{.*}}bar_func1{{.*}} symbol multiply defined! ; -; Test linking with a device library file. -; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libLLVMSYCL.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; Test linking with a BC library file. +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-DEVICE-LIB ; CHECK-DEVICE-LIB: define {{.*}}foo_func1{{.*}} ; CHECK-DEVICE-LIB: define {{.*}}foo_func2{{.*}} @@ -81,7 +81,7 @@ entry: ret i32 %res } -;--- libLLVMSYCL.ll +;--- libfoo.ll target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" target triple = "spirv64" >From 9fbf0bf1c6eefd177876708e389e7cfa880ad8d9 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 02:54:41 +0200 Subject: [PATCH 6/8] cleanup --- clang/test/OffloadTools/clang-sycl-linker/basic.ll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll index 4ee3135904c56..da4d409d60f15 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll @@ -34,8 +34,8 @@ ; ; Test to see if device library related errors are emitted. ; RUN: not clang-sycl-linker --dry-run %t/input1.bc %t/input2.bc --library-path=%t/libs --bc-library lib1.bc --bc-library lib2.bc --bc-library lib3.bc -o a.spv 2>&1 \ -; RUN: | FileCheck %s --check-prefix=DEVLIBSERR2 -; DEVLIBSERR2: '{{.*}}lib3.bc' library file not found +; RUN: | FileCheck %s --check-prefix=DEVLIBSERR +; DEVLIBSERR: '{{.*}}lib3.bc' library file 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 \ >From 8a8c692db4cf4ac80662e9d979973496c95c76d9 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 03:01:12 +0200 Subject: [PATCH 7/8] simplified test --- .../OffloadTools/clang-sycl-linker/link.ll | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll b/clang/test/OffloadTools/clang-sycl-linker/link.ll index d675f0400b182..72473a6e0c34b 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/link.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll @@ -9,21 +9,20 @@ ; RUN: llvm-as %t/libfoo.ll -o %t/libfoo.bc ; ; Test linking two input files. -; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --dry-run -o a.spv --print-linked-module 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-SIMPLE ; CHECK-SIMPLE: define {{.*}}foo_func1{{.*}} ; CHECK-SIMPLE: define {{.*}}foo_func2{{.*}} ; CHECK-SIMPLE: define {{.*}}bar_func1{{.*}} ; CHECK-SIMPLE-NOT: define {{.*}}addFive{{.*}} -; CHECK-SIMPLE-NOT: define {{.*}}unusedFunc{{.*}} ; ; Test that multiply defined symbols are reported as errors. -; RUN: not clang-sycl-linker %t/bar.bc %t/baz.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: not clang-sycl-linker %t/bar.bc %t/baz.bc --dry-run -o a.spv 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-MULTIPLE-DEFS ; CHECK-MULTIPLE-DEFS: error: Linking globals named {{.*}}bar_func1{{.*}} symbol multiply defined! ; ; Test linking with a BC library file. -; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc -triple=spirv64 --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc --dry-run -o a.spv --print-linked-module 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-DEVICE-LIB ; CHECK-DEVICE-LIB: define {{.*}}foo_func1{{.*}} ; CHECK-DEVICE-LIB: define {{.*}}foo_func2{{.*}} @@ -46,10 +45,9 @@ declare spir_func i32 @bar_func1(i32, i32) declare spir_func i32 @addFive(i32) -define spir_func i32 @foo_func2(i32 %c, i32 %d, i32 %e) { +define spir_func i32 @foo_func2(i32 %c, i32 %d) { entry: - %call = tail call spir_func i32 @foo_func1(i32 %c, i32 %d) - %res = mul nsw i32 %call, %e + %res = add nsw i32 %c, %d ret i32 %res } @@ -74,12 +72,6 @@ entry: ret i32 %res } -define spir_func i32 @baz_func1(i32 %a) { -entry: - %add = add nsw i32 %a, 5 - %res = tail call spir_func i32 @bar_func1(i32 %a, i32 %add) - ret i32 %res -} ;--- libfoo.ll target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" >From 04483cb5c82b4b34cfaa7f79295fdec33b03b48d Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Thu, 28 May 2026 03:20:46 +0200 Subject: [PATCH 8/8] improved coverage --- .../OffloadTools/clang-sycl-linker/basic.ll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll index da4d409d60f15..2cadf725f576c 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll @@ -26,6 +26,24 @@ ; DEVLIBS: link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc ; DEVLIBS-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: a_0.spv ; +; Test -L short form (joined) and --bc-library= joined form. +; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc -L%t/libs --bc-library=lib1.bc -o a.spv 2>&1 \ +; RUN: | FileCheck %s --check-prefix=DEVLIBS-SHORT +; DEVLIBS-SHORT: link: inputs: {{.*}}.bc libfiles: {{.*}}libs/lib1.bc output: {{.*}}.bc +; +; Test that search continues past the first -L when the library is not found there. lib1.bc exists only in %t/libs (the second -L). +; RUN: mkdir -p %t/empty +; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc -L %t/empty -L %t/libs --bc-library lib1.bc -o a.spv 2>&1 \ +; RUN: | FileCheck %s --check-prefix=DEVLIBS-FALLTHROUGH +; DEVLIBS-FALLTHROUGH: link: inputs: {{.*}}.bc libfiles: {{.*}}libs/lib1.bc output: {{.*}}.bc +; +; Test that -L paths are searched in order: when the same name exists in multiple -L dirs, the first one wins. +; RUN: mkdir -p %t/libs2 +; RUN: touch %t/libs/shadow.bc %t/libs2/shadow.bc +; RUN: clang-sycl-linker --dry-run -v --module-split-mode=none %t/input1.bc -L %t/libs2 -L %t/libs --bc-library shadow.bc -o a.spv 2>&1 \ +; RUN: | FileCheck %s --check-prefix=DEVLIBS-ORDER +; DEVLIBS-ORDER: link: inputs: {{.*}}.bc libfiles: {{.*}}libs2/shadow.bc output: {{.*}}.bc +; ; Test a simple case with a random file (not bitcode) as input. ; RUN: touch %t/dummy.o ; RUN: not clang-sycl-linker %t/dummy.o -o a.spv 2>&1 \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
