Skip to content

Commit 7054619

Browse files
authored
[SYCL][Driver] Deduplicate libspirv logic (#19131)
<!-- start git-machete generated --> # Based on PR #19130 ## Chain of upstream PRs & tree of downstream PRs as of 2025-06-25 * PR #19130 * **PR #19131 (THIS ONE)** * PR #19134 * PR #19135 * PR #19136 <!-- end git-machete generated --> Move the logic for finding and linking libspirv into SYCLInstallationDetector. This code was basically duplicated between the CUDA and HIP toolchains, and was also present in the Driver sources. This is NFC, aside from the fact that the code in the HIP toolchain lacked the special handling for the `-###` driver option present in the other two places.
1 parent 156429e commit 7054619

File tree

6 files changed

+106
-153
lines changed

6 files changed

+106
-153
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
#include "ToolChains/PS4CPU.h"
4444
#include "ToolChains/RISCVToolchain.h"
4545
#include "ToolChains/SPIRV.h"
46-
#include "ToolChains/SYCL.h"
4746
#include "ToolChains/SPIRVOpenMP.h"
4847
#include "ToolChains/SYCL.h"
4948
#include "ToolChains/Solaris.h"
@@ -5993,46 +5992,10 @@ class OffloadingActionBuilder final {
59935992
// For NVPTX and NativeCPU we need to also link libclc at the same stage
59945993
// that we link all of the unbundled SYCL libdevice objects together.
59955994
if (TC->getTriple().isNVPTX() || isNativeCPU) {
5996-
std::string LibSpirvFile;
5997-
if (Args.hasArg(options::OPT_fsycl_libspirv_path_EQ)) {
5998-
auto ProvidedPath =
5999-
Args.getLastArgValue(options::OPT_fsycl_libspirv_path_EQ).str();
6000-
if (llvm::sys::fs::exists(ProvidedPath))
6001-
LibSpirvFile = ProvidedPath;
6002-
} else {
6003-
SmallVector<StringRef, 2> LibraryPaths;
6004-
6005-
// Expected path w/out install.
6006-
SmallString<256> WithoutInstallPath(C.getDriver().ResourceDir);
6007-
llvm::sys::path::append(WithoutInstallPath, Twine("../../clc"));
6008-
LibraryPaths.emplace_back(WithoutInstallPath.c_str());
6009-
6010-
// Expected path w/ install.
6011-
SmallString<256> WithInstallPath(C.getDriver().ResourceDir);
6012-
llvm::sys::path::append(WithInstallPath, Twine("../../../share/clc"));
6013-
LibraryPaths.emplace_back(WithInstallPath.c_str());
6014-
6015-
// Select remangled libclc variant
6016-
StringRef LibSpirvTargetNamePref =
6017-
TC->getAuxTriple()->isOSWindows()
6018-
? "remangled-l32-signed_char.libspirv-"
6019-
: "remangled-l64-signed_char.libspirv-";
6020-
6021-
for (StringRef LibraryPath : LibraryPaths) {
6022-
SmallString<128> LibSpirvTargetFile(LibraryPath);
6023-
llvm::sys::path::append(LibSpirvTargetFile,
6024-
LibSpirvTargetNamePref +
6025-
TC->getTripleString() + ".bc");
6026-
if (llvm::sys::fs::exists(LibSpirvTargetFile) ||
6027-
Args.hasArg(options::OPT__HASH_HASH_HASH)) {
6028-
LibSpirvFile = std::string(LibSpirvTargetFile.str());
6029-
break;
6030-
}
6031-
}
6032-
}
6033-
if (!LibSpirvFile.empty()) {
6034-
Arg *LibClcInputArg = MakeInputArg(Args, C.getDriver().getOpts(),
6035-
Args.MakeArgString(LibSpirvFile));
5995+
if (const char *LibSpirvFile = SYCLInstallation.findLibspirvPath(
5996+
TC->getTriple(), Args, *TC->getAuxTriple())) {
5997+
Arg *LibClcInputArg =
5998+
MakeInputArg(Args, C.getDriver().getOpts(), LibSpirvFile);
60365999
auto *SYCLLibClcInputAction =
60376000
C.MakeAction<InputAction>(*LibClcInputArg, types::TY_LLVM_BC);
60386001
DeviceLinkObjects.push_back(SYCLLibClcInputAction);

clang/lib/Driver/ToolChains/Cuda.cpp

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -861,14 +861,6 @@ NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
861861
return DAL;
862862
}
863863

864-
// Select remangled libclc variant. 64-bit longs default, 32-bit longs on
865-
// Windows
866-
static const char *getLibSpirvTargetName(const ToolChain &HostTC) {
867-
if (HostTC.getTriple().isOSWindows())
868-
return "remangled-l32-signed_char.libspirv-nvptx64-nvidia-cuda.bc";
869-
return "remangled-l64-signed_char.libspirv-nvptx64-nvidia-cuda.bc";
870-
}
871-
872864
void NVPTXToolChain::addClangTargetOptions(
873865
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
874866
Action::OffloadKind DeviceOffloadingKind) const {}
@@ -970,6 +962,9 @@ void CudaToolChain::addClangTargetOptions(
970962
options::OPT_fno_sycl_id_queries_fit_in_int, false))
971963
CC1Args.append(
972964
{"-mllvm", "-nvvm-reflect-add=__CUDA_ID_QUERIES_FIT_IN_INT=1"});
965+
966+
SYCLInstallation.addLibspirvLinkArgs(getEffectiveTriple(), DriverArgs,
967+
HostTC.getTriple(), CC1Args);
973968
} else {
974969
CC1Args.append({"-fcuda-is-device", "-mllvm",
975970
"-enable-memcpyopt-without-libcalls",
@@ -988,53 +983,6 @@ void CudaToolChain::addClangTargetOptions(
988983
CC1Args.append({"-std=c++17", "-fsycl-is-host"});
989984
}
990985

991-
auto NoLibSpirv = DriverArgs.hasArg(options::OPT_fno_sycl_libspirv) ||
992-
getDriver().offloadDeviceOnly();
993-
if (DeviceOffloadingKind == Action::OFK_SYCL && !NoLibSpirv) {
994-
std::string LibSpirvFile;
995-
996-
if (DriverArgs.hasArg(clang::driver::options::OPT_fsycl_libspirv_path_EQ)) {
997-
auto ProvidedPath =
998-
DriverArgs.getLastArgValue(clang::driver::options::OPT_fsycl_libspirv_path_EQ).str();
999-
if (llvm::sys::fs::exists(ProvidedPath))
1000-
LibSpirvFile = ProvidedPath;
1001-
} else {
1002-
SmallVector<StringRef, 8> LibraryPaths;
1003-
1004-
// Expected path w/out install.
1005-
SmallString<256> WithoutInstallPath(getDriver().ResourceDir);
1006-
llvm::sys::path::append(WithoutInstallPath, Twine("../../clc"));
1007-
LibraryPaths.emplace_back(WithoutInstallPath.c_str());
1008-
1009-
// Expected path w/ install.
1010-
SmallString<256> WithInstallPath(getDriver().ResourceDir);
1011-
llvm::sys::path::append(WithInstallPath, Twine("../../../share/clc"));
1012-
LibraryPaths.emplace_back(WithInstallPath.c_str());
1013-
1014-
// Select remangled libclc variant
1015-
std::string LibSpirvTargetName = getLibSpirvTargetName(HostTC);
1016-
1017-
for (StringRef LibraryPath : LibraryPaths) {
1018-
SmallString<128> LibSpirvTargetFile(LibraryPath);
1019-
llvm::sys::path::append(LibSpirvTargetFile, LibSpirvTargetName);
1020-
if (llvm::sys::fs::exists(LibSpirvTargetFile) ||
1021-
DriverArgs.hasArg(options::OPT__HASH_HASH_HASH)) {
1022-
LibSpirvFile = std::string(LibSpirvTargetFile.str());
1023-
break;
1024-
}
1025-
}
1026-
}
1027-
1028-
if (LibSpirvFile.empty()) {
1029-
getDriver().Diag(diag::err_drv_no_sycl_libspirv)
1030-
<< getLibSpirvTargetName(HostTC);
1031-
return;
1032-
}
1033-
1034-
CC1Args.push_back("-mlink-builtin-bitcode");
1035-
CC1Args.push_back(DriverArgs.MakeArgString(LibSpirvFile));
1036-
}
1037-
1038986
if (DriverArgs.hasFlag(options::OPT_fcuda_short_ptr,
1039987
options::OPT_fno_cuda_short_ptr, false))
1040988
CC1Args.append({"-mllvm", "--nvptx-short-ptr"});

clang/lib/Driver/ToolChains/HIPAMD.cpp

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,6 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
222222
diagnoseUnsupportedSanitizers(Args);
223223
}
224224

225-
static const char *getLibSpirvTargetName(const ToolChain &HostTC) {
226-
return "remangled-l64-signed_char.libspirv-amdgcn-amd-amdhsa.bc";
227-
}
228-
229225
void HIPAMDToolChain::addClangTargetOptions(
230226
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
231227
Action::OffloadKind DeviceOffloadingKind) const {
@@ -274,53 +270,8 @@ void HIPAMDToolChain::addClangTargetOptions(
274270

275271
if (DeviceOffloadingKind == Action::OFK_SYCL) {
276272
SYCLInstallation.addSYCLIncludeArgs(DriverArgs, CC1Args);
277-
}
278-
279-
auto NoLibSpirv = DriverArgs.hasArg(options::OPT_fno_sycl_libspirv) ||
280-
getDriver().offloadDeviceOnly();
281-
if (DeviceOffloadingKind == Action::OFK_SYCL && !NoLibSpirv) {
282-
std::string LibSpirvFile;
283-
284-
if (DriverArgs.hasArg(clang::driver::options::OPT_fsycl_libspirv_path_EQ)) {
285-
auto ProvidedPath =
286-
DriverArgs
287-
.getLastArgValue(
288-
clang::driver::options::OPT_fsycl_libspirv_path_EQ)
289-
.str();
290-
if (llvm::sys::fs::exists(ProvidedPath))
291-
LibSpirvFile = ProvidedPath;
292-
} else {
293-
SmallVector<StringRef, 8> LibraryPaths;
294-
295-
// Expected path w/out install.
296-
SmallString<256> WithoutInstallPath(getDriver().ResourceDir);
297-
llvm::sys::path::append(WithoutInstallPath, Twine("../../clc"));
298-
LibraryPaths.emplace_back(WithoutInstallPath.c_str());
299-
300-
// Expected path w/ install.
301-
SmallString<256> WithInstallPath(getDriver().ResourceDir);
302-
llvm::sys::path::append(WithInstallPath, Twine("../../../share/clc"));
303-
LibraryPaths.emplace_back(WithInstallPath.c_str());
304-
305-
std::string LibSpirvTargetName = getLibSpirvTargetName(HostTC);
306-
for (StringRef LibraryPath : LibraryPaths) {
307-
SmallString<128> LibSpirvTargetFile(LibraryPath);
308-
llvm::sys::path::append(LibSpirvTargetFile, LibSpirvTargetName);
309-
if (llvm::sys::fs::exists(LibSpirvTargetFile)) {
310-
LibSpirvFile = std::string(LibSpirvTargetFile.str());
311-
break;
312-
}
313-
}
314-
}
315-
316-
if (LibSpirvFile.empty()) {
317-
getDriver().Diag(diag::err_drv_no_sycl_libspirv)
318-
<< getLibSpirvTargetName(HostTC);
319-
return;
320-
}
321-
322-
CC1Args.push_back("-mlink-builtin-bitcode");
323-
CC1Args.push_back(DriverArgs.MakeArgString(LibSpirvFile));
273+
SYCLInstallation.addLibspirvLinkArgs(getEffectiveTriple(), DriverArgs,
274+
HostTC.getTriple(), CC1Args);
324275
}
325276

326277
for (auto BCFile : getDeviceLibs(DriverArgs, DeviceOffloadingKind)) {

clang/lib/Driver/ToolChains/SYCL.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,82 @@ SYCLInstallationDetector::SYCLInstallationDetector(
149149
const llvm::opt::ArgList &Args)
150150
: D(D) {}
151151

152+
static llvm::SmallString<64>
153+
getLibSpirvBasename(const llvm::Triple &DeviceTriple,
154+
const llvm::Triple &HostTriple) {
155+
// Select remangled libclc variant.
156+
// Decide long size based on host triple, because offloading targets are going
157+
// to match that.
158+
// All known windows environments except Cygwin use 32-bit long.
159+
llvm::SmallString<64> Result(HostTriple.isOSWindows() &&
160+
!HostTriple.isWindowsCygwinEnvironment()
161+
? "remangled-l32-signed_char.libspirv-"
162+
: "remangled-l64-signed_char.libspirv-");
163+
164+
Result.append(DeviceTriple.getTriple());
165+
Result.append(".bc");
166+
167+
return Result;
168+
}
169+
170+
const char *SYCLInstallationDetector::findLibspirvPath(
171+
const llvm::Triple &DeviceTriple, const llvm::opt::ArgList &Args,
172+
const llvm::Triple &HostTriple) const {
173+
174+
// If -fsycl-libspirv-path= is specified, try to use that path directly.
175+
if (Arg *A = Args.getLastArg(options::OPT_fsycl_libspirv_path_EQ)) {
176+
if (llvm::sys::fs::exists(A->getValue()))
177+
return A->getValue();
178+
179+
return nullptr;
180+
}
181+
182+
const SmallString<64> Basename =
183+
getLibSpirvBasename(DeviceTriple, HostTriple);
184+
auto searchAt = [&](StringRef Path, const Twine &a = "", const Twine &b = "",
185+
const Twine &c = "", const Twine &d = "",
186+
const Twine &e = "") -> const char * {
187+
SmallString<128> LibraryPath(Path);
188+
llvm::sys::path::append(LibraryPath, a, b, c, d);
189+
llvm::sys::path::append(LibraryPath, e, Basename);
190+
191+
if (Args.hasArgNoClaim(options::OPT__HASH_HASH_HASH) ||
192+
llvm::sys::fs::exists(LibraryPath))
193+
return Args.MakeArgString(LibraryPath);
194+
195+
return nullptr;
196+
};
197+
198+
// Otherwise, assume libclc is installed at the same prefix as clang
199+
// Expected path w/out install.
200+
if (const char *R = searchAt(D.ResourceDir, "..", "..", "clc"))
201+
return R;
202+
203+
// Expected path w/ install.
204+
if (const char *R = searchAt(D.ResourceDir, "..", "..", "..", "share", "clc"))
205+
return R;
206+
207+
return nullptr;
208+
}
209+
210+
void SYCLInstallationDetector::addLibspirvLinkArgs(
211+
const llvm::Triple &DeviceTriple, const llvm::opt::ArgList &DriverArgs,
212+
const llvm::Triple &HostTriple, llvm::opt::ArgStringList &CC1Args) const {
213+
if (DriverArgs.hasArg(options::OPT_fno_sycl_libspirv) ||
214+
D.offloadDeviceOnly())
215+
return;
216+
217+
if (const char *LibSpirvFile =
218+
findLibspirvPath(DeviceTriple, DriverArgs, HostTriple)) {
219+
CC1Args.push_back("-mlink-builtin-bitcode");
220+
CC1Args.push_back(LibSpirvFile);
221+
return;
222+
}
223+
224+
D.Diag(diag::err_drv_no_sycl_libspirv)
225+
<< getLibSpirvBasename(DeviceTriple, HostTriple);
226+
}
227+
152228
void SYCLInstallationDetector::getSYCLDeviceLibPath(
153229
llvm::SmallVector<llvm::SmallString<128>, 4> &DeviceLibPaths) const {
154230
for (const auto &IC : InstallationCandidates) {

clang/lib/Driver/ToolChains/SYCL.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ class SYCLInstallationDetector {
130130
SYCLInstallationDetector(const Driver &D);
131131
SYCLInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
132132
const llvm::opt::ArgList &Args);
133+
134+
/// \brief Find and return the path to the libspirv library for the target
135+
/// \return The path to the libspirv library if found, otherwise nullptr.
136+
/// The lifetime of the returned string is managed by \p Args.
137+
const char *findLibspirvPath(const llvm::Triple &DeviceTriple,
138+
const llvm::opt::ArgList &Args,
139+
const llvm::Triple &HostTriple) const;
140+
141+
void addLibspirvLinkArgs(const llvm::Triple &DeviceTriple,
142+
const llvm::opt::ArgList &DriverArgs,
143+
const llvm::Triple &HostTriple,
144+
llvm::opt::ArgStringList &CC1Args) const;
145+
133146
void getSYCLDeviceLibPath(
134147
llvm::SmallVector<llvm::SmallString<128>, 4> &DeviceLibPaths) const;
135148
void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs,

clang/test/Driver/sycl-libspirv-toolchain.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55

66
// RUN: %clang -### -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-windows-msvc %s 2>&1 \
77
// RUN: | FileCheck %s --check-prefixes=CHECK-WINDOWS
8+
// RUN: %clang -### -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-windows-gnu %s 2>&1 \
9+
// RUN: | FileCheck %s --check-prefixes=CHECK-WINDOWS
810
// CHECK-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l32-signed_char.libspirv-nvptx64-nvidia-cuda.bc"
911
//
1012
// RUN: %clang -### -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-linux-gnu %s 2>&1 \
1113
// RUN: | FileCheck %s --check-prefixes=CHECK-LINUX
14+
// RUN: %clang -### -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-windows-cygnus %s 2>&1 \
15+
// RUN: | FileCheck %s --check-prefixes=CHECK-LINUX
1216
// CHECK-LINUX: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l64-signed_char.libspirv-nvptx64-nvidia-cuda.bc"
1317
//
14-
// AMDGCN wrongly uses 32-bit longs on Windows
1518
// RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 -nogpulib -target x86_64-unknown-windows-msvc %s 2>&1 \
1619
// RUN: | FileCheck %s --check-prefixes=CHECK-AMDGCN-WINDOWS
17-
// CHECK-AMDGCN-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l64-signed_char.libspirv-amdgcn-amd-amdhsa.bc"
20+
// CHECK-AMDGCN-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l32-signed_char.libspirv-amdgcn-amd-amdhsa.bc"
1821
//
1922
// RUN: %clang -### -fsycl -fsycl-device-only -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \
2023
// RUN: | FileCheck %s --check-prefixes=CHECK-DEVICE-ONLY
@@ -38,10 +41,9 @@
3841
// RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-HHH-NONEXISTENT
3942
// CHECK-HHH-NONEXISTENT: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "[[DIR]]{{.*[\\/]}}remangled-{{.*}}.libspirv-nvptx64-nvidia-cuda.bc"
4043
//
41-
// But not for AMDGCN :^)
42-
// RUN: not %clang -### -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 -nogpulib %s 2>&1 \
43-
// RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-AMDGCN-HHH-NONEXISTENT
44-
// CHECK-AMDGCN-HHH-NONEXISTENT: error: cannot find 'remangled-{{.*}}.libspirv-amdgcn-amd-amdhsa.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv
44+
// RUN: %clang -### -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 -nogpulib %s 2>&1 \
45+
// RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-AMDGCN-HHH-NONEXISTENT
46+
// CHECK-AMDGCN-HHH-NONEXISTENT: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "[[DIR]]{{.*[\\/]}}remangled-{{.*}}.libspirv-amdgcn-amd-amdhsa.bc"
4547
//
4648
// `-fdriver-only` has no such special handling, so it will not find the file
4749
// RUN: not %clang -fdriver-only -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \

0 commit comments

Comments
 (0)