Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
92 changes: 55 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,61 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
}

// Create a comma separated list to pass along to the linker wrapper.
Comment thread
srividya-sundaram marked this conversation as resolved.
Outdated
SmallString<256> LibList;
SmallVector<std::string, 4> BCLibList;

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

auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
for (auto &I :
Comment thread
jzc marked this conversation as resolved.
Outdated
Comment thread
srividya-sundaram marked this conversation as resolved.
Outdated
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
const ToolChain *TC = I.second;
llvm::Triple TargetTriple = TC->getTriple();
bool IsSPIR = TargetTriple.isSPIROrSPIRV();
Comment thread
jzc marked this conversation as resolved.
bool IsSpirvAOT = TargetTriple.isSPIRAOT();
Comment thread
jzc marked this conversation as resolved.
Outdated
bool UseJitLink =
IsSPIR &&
Args.hasFlag(options::OPT_fsycl_device_lib_jit_link,
options::OPT_fno_sycl_device_lib_jit_link, false);
Comment thread
jzc marked this conversation as resolved.
bool UseAOTLink = IsSPIR && (IsSpirvAOT || !UseJitLink);
SmallVector<std::string, 8> 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
Comment thread
jzc marked this conversation as resolved.
Outdated
// 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
Comment thread
jzc marked this conversation as resolved.
Outdated
// RUN: %clang -### -fsycl --offload-new-driver \
Comment thread
jzc marked this conversation as resolved.
// 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"
Comment thread
jzc marked this conversation as resolved.

/// 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
Comment thread
maarquitos14 marked this conversation as resolved.

/// 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));
}

@jzc jzc Nov 4, 2025

Copy link
Copy Markdown
Contributor Author

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
3 changes: 0 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,6 @@ 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.">;

// Options for SYCL backends and linker options for shared libraries.
def sycl_backend_compile_options_EQ :
Expand Down
Loading