Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 53 additions & 37 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11266,43 +11266,6 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_fsycl_link_EQ))
CmdArgs.push_back(Args.MakeArgString("--sycl-device-link"));

// -sycl-device-libraries=<comma separated list> contains all of the SYCL
// device specific libraries that are needed. This generic list will be
// populated with device binaries for all target triples in the current
// compilation flow.

// Create a comma separated list to pass along to the linker wrapper.
SmallString<256> LibList;
llvm::Triple TargetTriple;
auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
for (auto &I :
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
const ToolChain *TC = I.second;
// Note: For AMD targets, we do not pass any SYCL device libraries.
if (TC->getTriple().isSPIROrSPIRV() || TC->getTriple().isNVPTX()) {
TargetTriple = TC->getTriple();
SmallVector<std::string, 8> SYCLDeviceLibs;
bool IsSPIR = TargetTriple.isSPIROrSPIRV();
bool IsSpirvAOT = TargetTriple.isSPIRAOT();
bool UseJitLink =
IsSPIR &&
Args.hasFlag(options::OPT_fsycl_device_lib_jit_link,
options::OPT_fno_sycl_device_lib_jit_link, false);
bool UseAOTLink = IsSPIR && (IsSpirvAOT || !UseJitLink);
SYCLDeviceLibs = SYCL::getDeviceLibraries(C, TargetTriple, UseAOTLink);
for (const auto &AddLib : SYCLDeviceLibs) {
if (LibList.size() > 0)
LibList += ",";
LibList += AddLib;
}
}
}
// -sycl-device-libraries=<libs> provides a comma separate list of
// libraries to add to the device linking step.
if (LibList.size())
CmdArgs.push_back(
Args.MakeArgString(Twine("-sycl-device-libraries=") + LibList));

// -sycl-device-library-location=<dir> provides the location in which the
// SYCL device libraries can be found.
SmallString<128> DeviceLibDir(D.Dir);
Expand All @@ -11327,6 +11290,59 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
}

// Create a comma separated list to pass along to the linker wrapper.
SmallString<256> LibList;
SmallVector<std::string, 4> BCLibList;

auto appendToList = [](SmallString<256> &List, const Twine &Arg) {
if (List.size() > 0)
List += ",";
List += Arg.str();
};

llvm::Triple TargetTriple;
auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
for (auto &I :
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
const ToolChain *TC = I.second;
TargetTriple = TC->getTriple();
SmallVector<std::string, 8> SYCLDeviceLibs;
bool IsSPIR = TargetTriple.isSPIROrSPIRV();
bool IsSpirvAOT = TargetTriple.isSPIRAOT();
bool UseJitLink =
IsSPIR &&
Args.hasFlag(options::OPT_fsycl_device_lib_jit_link,
options::OPT_fno_sycl_device_lib_jit_link, false);
bool UseAOTLink = IsSPIR && (IsSpirvAOT || !UseJitLink);
SYCLDeviceLibs = SYCL::getDeviceLibraries(C, TargetTriple, UseAOTLink);
for (const auto &AddLib : SYCLDeviceLibs) {
if (llvm::sys::path::extension(AddLib) == ".bc") {
SmallString<256> LibPath(DeviceLibDir);
llvm::sys::path::append(LibPath, AddLib);
BCLibList.push_back((Twine(TC->getTriple().str()) + "=" + LibPath).str());
continue;
}

appendToList(LibList, AddLib);
}

if (TC->getTriple().isNVPTX())
if (const char *LibSpirvFile = SYCLInstallation.findLibspirvPath(
TC->getTriple(), Args, *TC->getAuxTriple()))
BCLibList.push_back((Twine(TC->getTriple().str()) + "=" + LibSpirvFile).str());
}
// -sycl-device-libraries=<libs> provides a comma separate list of
// libraries to add to the device linking step.
if (LibList.size())
CmdArgs.push_back(
Args.MakeArgString(Twine("-sycl-device-libraries=") + LibList));

if (BCLibList.size()) {
for (const std::string &Lib : BCLibList)
CmdArgs.push_back(Args.MakeArgString(Twine("--bitcode-library=") + Lib));
}

CmdArgs.push_back(Args.MakeArgString(
Twine("-sycl-device-library-location=") + DeviceLibDir));

Expand Down
61 changes: 61 additions & 0 deletions clang/test/Driver/sycl-bc-device-libraries.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/// Test that SYCL bitcode device libraries are properly separated for NVIDIA and AMD targets

/// Check devicelib and libspirv are linked for nvptx
// RUN: %clang -### -fsycl --offload-new-driver \
// RUN: -fsycl-targets=nvptx64-nvidia-cuda \
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-NVPTX-BC %s

// CHECK-NVPTX-BC: clang-linker-wrapper
// CHECK-NVPTX-BC-SAME: "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc" "--bitcode-library=nvptx64-nvidia-cuda={{.*}}libspirv-nvptx64-nvidia-cuda.bc"

/// Check devicelib is linked for amdgcn
// RUN: %clang -### -fsycl --offload-new-driver \
// RUN: -fsycl-targets=amdgcn-amd-amdhsa \
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
// RUN: --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-AMD-BC %s

// CHECK-AMD-BC: clang-linker-wrapper
// CHECK-AMD-BC-SAME: "--bitcode-library=amdgcn-amd-amdhsa={{.*}}devicelib-amdgcn-amd-amdhsa.bc"

/// Check linking with multiple targets
// RUN: %clang -### -fsycl --offload-new-driver \
// RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
// RUN: --rocm-path=%S/Inputs/rocm \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-MULTI-TARGET %s

// CHECK-MULTI-TARGET: clang-linker-wrapper
// CHECK-MULTI-TARGET-SAME: "--bitcode-library=amdgcn-amd-amdhsa={{.*}}devicelib-amdgcn-amd-amdhsa.bc" "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc" "--bitcode-library=nvptx64-nvidia-cuda={{.*}}libspirv-nvptx64-nvidia-cuda.bc"

/// Test --bitcode-library with nvptx dummy libraries
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.nvptx.devicelib.bc
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.nvptx.libspirv.bc
// RUN: %clang++ -fsycl -fsycl-targets=nvptx64-nvidia-cuda --offload-new-driver -c %s -o %t.nvptx.o -nocudalib
// RUN: clang-linker-wrapper --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.devicelib.bc --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.libspirv.bc \
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld %t.nvptx.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-NVPTX %s

// CHECK-WRAPPER-NVPTX: llvm-link{{.*}} {{.*}}.nvptx.devicelib.bc {{.*}}.nvptx.libspirv.bc

/// Test --bitcode-library with amdgcn dummy library
// RUN: %clang -cc1 %s -triple amdgcn-amd-amdhsa -emit-llvm-bc -o %t.amd.devicelib.bc
// RUN: %clang++ -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 --offload-new-driver -c %s -o %t.amd.o -nogpulib
// RUN: clang-linker-wrapper --bitcode-library=amdgcn-amd-amdhsa=%t.amd.devicelib.bc \
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld %t.amd.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-AMD %s

// CHECK-WRAPPER-AMD: llvm-link{{.*}} {{.*}}.amd.devicelib.bc

/// Test --bitcode-library with multi-target bc libraries
// RUN: %clang++ -fsycl -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
// RUN: --offload-new-driver -c %s -o %t.multi.o -nocudalib -nogpulib
// RUN: clang-linker-wrapper --bitcode-library=amdgcn-amd-amdhsa=%t.amd.devicelib.bc --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.devicelib.bc --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.libspirv.bc \
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld %t.multi.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-MULTI %s

// CHECK-WRAPPER-MULTI: llvm-link{{.*}} {{.*}}.amd.devicelib.bc
// CHECK-WRAPPER-MULTI: llvm-link{{.*}} {{.*}}.nvptx.devicelib.bc {{.*}}.nvptx.libspirv.bc
36 changes: 11 additions & 25 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1432,24 +1432,17 @@ static Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
<< "Compatible SYCL device library binary not found\n";
}

// For NVPTX backend we need to also link libclc and CUDA libdevice.
if (Triple.isNVPTX()) {
if (Arg *A = Args.getLastArg(OPT_sycl_nvptx_device_lib_EQ)) {
if (A->getValues().size() == 0)
return createStringError(
inconvertibleErrorCode(),
"Number of device library files cannot be zero.");
for (StringRef Val : A->getValues()) {
SmallString<128> LibName(Val);
if (llvm::sys::fs::exists(LibName))
ExtractedDeviceLibFiles.emplace_back(std::string(LibName));
else
return createStringError(
inconvertibleErrorCode(),
std::string(LibName) +
" SYCL device library file for NVPTX is not found.");
}
}
for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
auto [LibraryTriple, LibraryPath] = Library.split('=');
if (llvm::Triple(LibraryTriple) != Triple)
continue;

if (!llvm::sys::fs::exists(LibraryPath))
return createStringError(inconvertibleErrorCode(),
"The specified device library " + LibraryPath +
" does not exist.");

ExtractedDeviceLibFiles.emplace_back(LibraryPath.str());
}

// Make sure that SYCL device library files are available.
Expand Down Expand Up @@ -2515,13 +2508,6 @@ getDeviceInput(const ArgList &Args) {
}
}

for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
auto FileOrErr = getInputBitcodeLibrary(Library);
if (!FileOrErr)
return FileOrErr.takeError();
InputFiles[*FileOrErr].push_back(std::move(*FileOrErr));
}

Copy link
Contributor Author

@jzc jzc Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functionality is not used nor tested - searching for --bitcode-library, nothing comes up. The --bitcode-library seems to original came from upstream, but then was removed upstream, and never removed downstream. I deleted the old functionality and made --bitcode-library more SYCL specific (see linkDevice. The old functionality of --bitcode-library linked the user objects with the bitcode libraries in one link job. For SYCL, we need to link the bitcode libraries in a separated job with the --only-needed option.

SmallVector<SmallVector<OffloadFile>> InputsForTarget;
for (auto &[ID, Input] : InputFiles)
InputsForTarget.emplace_back(std::move(Input));
Expand Down
8 changes: 5 additions & 3 deletions clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,11 @@ def sycl_device_lib_EQ : CommaJoined<["--", "-"], "sycl-device-libraries=">,
def sycl_device_library_location_EQ : Joined<["--", "-"],
"sycl-device-library-location=">, Flags<[WrapperOnlyOption]>,
HelpText<"Location of SYCL device library files">;
def sycl_nvptx_device_lib_EQ : CommaJoined<["--", "-"], "sycl-nvptx-device-libraries=">,
Flags<[WrapperOnlyOption]>,
HelpText<"A comma separated list of nvptx-specific device libraries that are linked during the device link.">;
def sycl_bc_device_lib_EQ
: CommaJoined<["--", "-"], "sycl-bc-device-libraries=">,
Flags<[WrapperOnlyOption]>,
HelpText<"A comma separated list of bitcode device libraries that are "
"linked during SYCL device link.">;

// Options for SYCL backends and linker options for shared libraries.
def sycl_backend_compile_options_EQ :
Expand Down
2 changes: 2 additions & 0 deletions sycl/test-e2e/DeviceLib/rand_test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out
// RUN: %{build} -o %t.out --offload-new-driver
// RUN: %{run} %t.out

// XFAIL: target-native_cpu
// XFAIL-TRACKER: https://github.com/intel/llvm/issues/20142
Expand Down
Loading