Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/SyclInstallationDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class SYCLInstallationDetector {

void getSYCLDeviceLibPath(
llvm::SmallVector<llvm::SmallString<128>, 4> &DeviceLibPaths) const;

/// \brief Search the SYCL device library locations for \p LibName.
/// \return The full path to the library if found, otherwise std::nullopt.
std::optional<llvm::SmallString<128>>
findSYCLDeviceLib(llvm::StringRef LibName) const;

void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;

Expand Down
77 changes: 29 additions & 48 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11556,18 +11556,11 @@ static void getNonTripleBasedSYCLPostLinkOpts(const ToolChain &TC,
if (TC.getTriple().isSPIROrSPIRV() && !TC.getTriple().isSPIRAOT()) {
SYCLInstallationDetector SYCLInstall(TC.getDriver(), TC.getTriple(),
TCArgs);
SmallVector<SmallString<128>, 4> DeviceLibLocCandidates;
SmallString<128> NativeBfloat16Name("libsycl-native-bfloat16.bc");
SYCLInstall.getSYCLDeviceLibPath(DeviceLibLocCandidates);
for (const auto &DeviceLibLoc : DeviceLibLocCandidates) {
SmallString<128> FullLibName(DeviceLibLoc);
llvm::sys::path::append(FullLibName, NativeBfloat16Name);
if (llvm::sys::fs::exists(FullLibName)) {
SmallString<128> SYCLDeviceLibDir("--device-lib-dir=");
SYCLDeviceLibDir += DeviceLibLoc.str();
addArgs(PostLinkArgs, TCArgs, {SYCLDeviceLibDir.str()});
break;
}
if (auto FullLibName =
SYCLInstall.findSYCLDeviceLib("libsycl-native-bfloat16.bc")) {
SmallString<128> SYCLDeviceLibDir("--device-lib-dir=");
SYCLDeviceLibDir += llvm::sys::path::parent_path(*FullLibName);
addArgs(PostLinkArgs, TCArgs, {SYCLDeviceLibDir.str()});
}
}
}
Expand Down Expand Up @@ -12256,74 +12249,62 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
/*default=*/true))
CmdArgs.push_back("--no-sycl-rdc");

// -sycl-device-library-location=<dir> provides the location in which the
// SYCL device libraries can be found.
SmallString<128> DeviceLibDir(D.Dir);
llvm::sys::path::append(DeviceLibDir, "..", "lib");
// Check the library location candidates for the the libsycl-crt library
// and use that location. Base the location on relative to driver if this
// is not resolved.
SmallVector<SmallString<128>, 4> LibLocCandidates;
SYCLInstallationDetector SYCLInstallation(D, getToolChain().getTriple(),
Args);
SYCLInstallation.getSYCLDeviceLibPath(LibLocCandidates);
SmallString<128> LibName("libsycl-crt.bc");
for (const auto &LibLoc : LibLocCandidates) {
SmallString<128> FullLibName(LibLoc);
llvm::sys::path::append(FullLibName, LibName);
if (llvm::sys::fs::exists(FullLibName)) {
DeviceLibDir = LibLoc;
break;
}
}

// Device libraries for SYCL offloading are specified using
// --bitcode-library=<triple>=<path to bc file> for each library.
// The full path must be provided (not relative to
// -sycl-device-library-location).
//
// Note: SPIR/SPIRV device libraries are linked at compile time using
// -mlink-builtin-bitcode, so they are not passed here. Only non-SPIR
// targets (NVPTX, AMD) pass device libraries to clang-linker-wrapper.
// targets (NVPTX, AMD, NativeCPU) pass device libraries to
// clang-linker-wrapper.
SmallVector<std::string, 4> BCLibList;
bool HasNativeCPU = false;

auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
for (const auto &[Kind, TC] :
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
llvm::Triple TargetTriple = TC->getTriple();
SmallVector<ToolChain::BitCodeLibraryInfo, 8> SYCLDeviceLibs;
HasNativeCPU |= TargetTriple.isNativeCPU();
// SPIR or SPIR-V device libraries are compiled into the device compile
// step. Non-SPIR here means NVPTX/AMDGCN (CudaToolChain/AMDGPUToolChain).
// step. Non-SPIR here means NVPTX/AMDGCN (CudaToolChain/AMDGPUToolChain)
// or NativeCPU.
if (!TargetTriple.isSPIROrSPIRV()) {
const ToolChain *HostTC =
C.getSingleOffloadToolChain<Action::OFK_Host>();
std::unique_ptr<toolchains::SYCLToolChain> ScratchTC;
const toolchains::SYCLToolChain &SYCLTC =
toolchains::getSYCLToolChain(D, *TC, *HostTC, Args, ScratchTC);
SYCLDeviceLibs.append(SYCLTC.getDeviceLibNames(D, Args, TargetTriple));
}
for (const auto &AddLib : SYCLDeviceLibs) {
if (llvm::sys::path::extension(AddLib.Path) == ".bc") {
SmallString<256> LibPath(DeviceLibDir);
llvm::sys::path::append(LibPath, AddLib.Path);
BCLibList.push_back(
(Twine(TC->getTriple().str()) + "=" + LibPath).str());
continue;
}
// getDeviceLibs resolves the full path of each library and diagnoses
// any that are not found.
for (const auto &AddLib :
SYCLTC.getDeviceLibs(Args, /*BA=*/{}, Action::OFK_SYCL))
if (llvm::sys::path::extension(AddLib.Path) == ".bc")
BCLibList.push_back(
(Twine(TargetTriple.str()) + "=" + AddLib.Path).str());
}

if (TC->getTriple().isNVPTX())
if (TargetTriple.isNVPTX())
if (const char *LibSpirvFile = SYCLInstallation.findLibspirvPath(
TC->getTriple(), Args, *TC->getAuxTriple()))
TargetTriple, Args, *TC->getAuxTriple()))
BCLibList.push_back(
(Twine(TC->getTriple().str()) + "=" + LibSpirvFile).str());
(Twine(TargetTriple.str()) + "=" + LibSpirvFile).str());
}

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

// -sycl-device-library-location=<dir> provides the location of the
// native CPU/bfloat16 device libraries. Falls back to <Driver>/../lib.
SmallString<128> DeviceLibDir(D.Dir);
llvm::sys::path::append(DeviceLibDir, "..", "lib");
if (auto FullLibName = SYCLInstallation.findSYCLDeviceLib(
HasNativeCPU ? "libsycl-nativecpu_utils.bc"
: "libsycl-native-bfloat16.bc"))
DeviceLibDir = llvm::sys::path::parent_path(*FullLibName);
CmdArgs.push_back(Args.MakeArgString(
Twine("-sycl-device-library-location=") + DeviceLibDir));
Comment thread
mdtoguchi marked this conversation as resolved.

Expand Down
33 changes: 17 additions & 16 deletions clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,19 @@ void SYCLInstallationDetector::getSYCLDeviceLibPath(
DeviceLibPaths.emplace_back(Path.str());
}

std::optional<SmallString<128>>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔵 Suggestion: findSYCLDeviceLib now uses D.getVFS().exists(). The code it replaces used llvm::sys::fs::exists. This is arguably better, since it honors -ivfsoverlay. It is still a behavior change for all callers, so it is worth mentioning in the PR description. The header also uses std::optional and should include <optional> explicitly, to avoid relying on transitive includes.

SYCLInstallationDetector::findSYCLDeviceLib(StringRef LibName) const {
SmallVector<SmallString<128>, 4> DeviceLibPaths;
getSYCLDeviceLibPath(DeviceLibPaths);
for (const auto &LibPath : DeviceLibPaths) {
SmallString<128> FullLibName(LibPath);
llvm::sys::path::append(FullLibName, LibName);
if (D.getVFS().exists(FullLibName))
return FullLibName;
}
return std::nullopt;
}

void SYCLInstallationDetector::addSYCLIncludeArgs(
const ArgList &DriverArgs, ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc)) {
Expand Down Expand Up @@ -2075,31 +2088,19 @@ SYCLToolChain::getDeviceLibs(
const Action::OffloadKind DeviceOffloadingKind) const {
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;

SmallVector<SmallString<128>, 4> LibraryPaths;
SYCLInstallation.getSYCLDeviceLibPath(LibraryPaths);

// Formulate all of the device libraries needed for this compilation.
SmallVector<BitCodeLibraryInfo, 8> DeviceLibs =
getDeviceLibNames(getDriver(), DriverArgs, getTriple());

// Create full path names to each device library. If found, add to the list
// of device libraries that will be linked against.
for (const auto &DeviceLib : DeviceLibs) {
bool DeviceLibFound = false;
for (const auto &LibraryPath : LibraryPaths) {
SmallString<128> FullLibName(LibraryPath);
llvm::sys::path::append(FullLibName, DeviceLib.Path);
if (llvm::sys::fs::exists(FullLibName)) {
BitCodeLibraryInfo BitCodeLibrary(
{FullLibName, DeviceLib.ShouldInternalize});
BCLibs.emplace_back(BitCodeLibrary);
DeviceLibFound = true;
break;
}
}
// The device libraries are all known internal libraries. If any are not
// found, emit an error.
if (!DeviceLibFound)
if (auto FullLibName = SYCLInstallation.findSYCLDeviceLib(DeviceLib.Path))
BCLibs.emplace_back(
BitCodeLibraryInfo({*FullLibName, DeviceLib.ShouldInternalize}));
else
getDriver().Diag(diag::err_drv_no_sycl_device_lib) << DeviceLib.Path;
}
return BCLibs;
Expand Down
57 changes: 51 additions & 6 deletions clang/test/Driver/sycl-bc-device-libraries.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
/// Test that SYCL bitcode device libraries are properly separated for NVIDIA and AMD targets.
/// Also test the SYCL device library location passed to clang-linker-wrapper
/// (-sycl-device-library-location) and sycl-post-link (--device-lib-dir).

/// Check that a device library which cannot be found is diagnosed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIUC, the folder passed in -sycl-device-library-location= is now found by searching for libsycl-native-bfloat16.bc (or libsycl-nativecpu_utils.bc for NativeCPU) instead of libsycl-crt.bc.

In Inputs/SYCL, libsycl-crt.bc is in lib/dpcpp-7/sycl, but those two files are only in lib/.

So on a Linux host, this test's flag should change from .../bin/../lib/dpcpp-7/sycl to .../bin/../lib.
That's also the fallback value, so the test can't tell whether the search found the file or gave up.

Could you add dummy libsycl-native-bfloat16.bc and libsycl-nativecpu_utils.bc under Inputs/SYCL/lib/dpcpp-7/sycl, plus a RUN line with --target=x86_64-unknown-linux-gnu that checks the flag points there?

That would match the Linux install layout (lib/dpcpp-/sycl) and actually exercise the new search.

// RUN: not %clang -### -fsycl --offload-new-driver -ccc-install-dir %t.nonexistent/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// 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-MISSING %s
// CHECK-NVPTX-MISSING: cannot find expected SYCL device library 'devicelib-nvptx64-nvidia-cuda.bc'

/// Check devicelib are linked for nvptx.
// RUN: %clang -### -fsycl --offload-new-driver \
// RUN: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// 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

// RUN: %clang_cl -### -fsycl --offload-new-driver \
// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// RUN: -fsycl-targets=nvptx64-nvidia-cuda \
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
Expand All @@ -17,14 +27,14 @@
// CHECK-NVPTX-BC-SAME: "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc"

/// Check devicelib is linked for amdgcn.
// RUN: %clang -### -fsycl --offload-new-driver \
// RUN: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// 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

// RUN: %clang_cl -### -fsycl --offload-new-driver \
// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// RUN: -fsycl-targets=amdgcn-amd-amdhsa \
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
Expand All @@ -35,15 +45,15 @@
// 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: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// 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

// RUN: %clang_cl -### -fsycl --offload-new-driver \
// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
Expand All @@ -53,3 +63,38 @@

// 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"

/// The device library location is resolved from the library being consumed.
/// Inputs/SYCL matches the Linux install layout, with the libraries in
/// lib/dpcpp-7/sycl. Make sure that location is found, rather than the
/// <driver>/../lib fallback.
/// Non-NativeCPU targets use the location of libsycl-native-bfloat16.bc.
// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \
// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fsycl-targets=spir64 \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-BF16 %s
// CHECK-LIB-LOC-BF16: clang-linker-wrapper{{.*}} "-sycl-device-library-location={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl"

// RUN: %clang -### -fsycl --no-offload-new-driver --target=x86_64-unknown-linux-gnu \
// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fsycl-targets=spir64 \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-BF16-POSTLINK %s
// CHECK-LIB-LOC-BF16-POSTLINK: sycl-post-link{{.*}} "--device-lib-dir={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl"

/// NativeCPU uses the location of libsycl-nativecpu_utils.bc.
// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \
// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \
// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \
// RUN: -fsycl-targets=native_cpu \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-NATIVECPU %s
// CHECK-LIB-LOC-NATIVECPU: clang-linker-wrapper
// CHECK-LIB-LOC-NATIVECPU-SAME: "--bitcode-library=native_cpu={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl{{[/\\]+}}libsycl-nativecpu_utils.bc"
// CHECK-LIB-LOC-NATIVECPU-SAME: "-sycl-device-library-location={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl"

/// When the library cannot be found, fall back to <driver>/../lib.
// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \
// RUN: -ccc-install-dir %t.nonexistent/bin \
// RUN: --no-offloadlib -fno-sycl-instrument-device-code \
// RUN: -fsycl-targets=spir64 \
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-FALLBACK %s
// CHECK-LIB-LOC-FALLBACK: clang-linker-wrapper{{.*}} "-sycl-device-library-location={{.*}}.nonexistent{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib"
Loading