Skip to content

Commit 703d57e

Browse files
authored
[SYCL][clang-linker-wrapper] Update --bitcode-library option for SYCL (#20331)
This PR updates the `--bitcode-library` option in `clang-linker-wrapper` to link bitcode device libraries that are used in NVIDIA and AMD GPU targets in SYCL offloading. This option had some previous behavior, but it was unused, so I deleted it and repurposed it for SYCL. `SYCL::getDeviceLibraries()` returns both fat objects and bitcode device libraries mixed together, while the `-sycl-device-libraries` option only handles fat objects. This was causing `clang-linker-wrapper` to not link the `libdevice` for nvptx/AMD targets. This PR also removes the `-sycl-nvptx-device-libraries` option, which seemed to be doing the same thing but only for nvptx targets.
1 parent 2b2f68c commit 703d57e

File tree

4 files changed

+152
-65
lines changed

4 files changed

+152
-65
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11222,43 +11222,6 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
1122211222
if (Args.hasArg(options::OPT_fsycl_link_EQ))
1122311223
CmdArgs.push_back(Args.MakeArgString("--sycl-device-link"));
1122411224

11225-
// -sycl-device-libraries=<comma separated list> contains all of the SYCL
11226-
// device specific libraries that are needed. This generic list will be
11227-
// populated with device binaries for all target triples in the current
11228-
// compilation flow.
11229-
11230-
// Create a comma separated list to pass along to the linker wrapper.
11231-
SmallString<256> LibList;
11232-
llvm::Triple TargetTriple;
11233-
auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
11234-
for (auto &I :
11235-
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
11236-
const ToolChain *TC = I.second;
11237-
// Note: For AMD targets, we do not pass any SYCL device libraries.
11238-
if (TC->getTriple().isSPIROrSPIRV() || TC->getTriple().isNVPTX()) {
11239-
TargetTriple = TC->getTriple();
11240-
SmallVector<std::string, 8> SYCLDeviceLibs;
11241-
bool IsSPIR = TargetTriple.isSPIROrSPIRV();
11242-
bool IsSpirvAOT = TargetTriple.isSPIRAOT();
11243-
bool UseJitLink =
11244-
IsSPIR &&
11245-
Args.hasFlag(options::OPT_fsycl_device_lib_jit_link,
11246-
options::OPT_fno_sycl_device_lib_jit_link, false);
11247-
bool UseAOTLink = IsSPIR && (IsSpirvAOT || !UseJitLink);
11248-
SYCLDeviceLibs = SYCL::getDeviceLibraries(C, TargetTriple, UseAOTLink);
11249-
for (const auto &AddLib : SYCLDeviceLibs) {
11250-
if (LibList.size() > 0)
11251-
LibList += ",";
11252-
LibList += AddLib;
11253-
}
11254-
}
11255-
}
11256-
// -sycl-device-libraries=<libs> provides a comma separate list of
11257-
// libraries to add to the device linking step.
11258-
if (LibList.size())
11259-
CmdArgs.push_back(
11260-
Args.MakeArgString(Twine("-sycl-device-libraries=") + LibList));
11261-
1126211225
// -sycl-device-library-location=<dir> provides the location in which the
1126311226
// SYCL device libraries can be found.
1126411227
SmallString<128> DeviceLibDir(D.Dir);
@@ -11283,6 +11246,68 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
1128311246
break;
1128411247
}
1128511248
}
11249+
11250+
// -sycl-device-libraries=<comma separated list> contains a list of
11251+
// file names for fat object files that contain SYCL device library bitcode
11252+
// necessary for SYCL offloading that will be linked to the user's device
11253+
// code. clang-linker-wrapper uses the value provided to
11254+
// -sycl-device-library-location=<dir> to construct the full paths of the
11255+
// device libraries.
11256+
11257+
// On the other hand, --bitcode-library=<triple>=<path to bc file> specifies
11258+
// one bitcode library to link in for a specific triple. Additionally, the
11259+
// path is *not* relative to the -sycl-device-library-location - the full
11260+
// path must be provided.
11261+
SmallString<256> LibList;
11262+
SmallVector<std::string, 4> BCLibList;
11263+
11264+
auto appendToList = [](SmallString<256> &List, const Twine &Arg) {
11265+
if (List.size() > 0)
11266+
List += ",";
11267+
List += Arg.str();
11268+
};
11269+
11270+
auto ToolChainRange = C.getOffloadToolChains<Action::OFK_SYCL>();
11271+
for (const auto &[Kind, TC] :
11272+
llvm::make_range(ToolChainRange.first, ToolChainRange.second)) {
11273+
llvm::Triple TargetTriple = TC->getTriple();
11274+
bool IsSPIR = TargetTriple.isSPIROrSPIRV();
11275+
bool IsSpirAOT = TargetTriple.isSPIRAOT();
11276+
bool UseJitLink =
11277+
IsSPIR &&
11278+
Args.hasFlag(options::OPT_fsycl_device_lib_jit_link,
11279+
options::OPT_fno_sycl_device_lib_jit_link, false);
11280+
bool UseAOTLink = IsSPIR && (IsSpirAOT || !UseJitLink);
11281+
SmallVector<std::string, 8> SYCLDeviceLibs =
11282+
SYCL::getDeviceLibraries(C, TargetTriple, UseAOTLink);
11283+
for (const auto &AddLib : SYCLDeviceLibs) {
11284+
if (llvm::sys::path::extension(AddLib) == ".bc") {
11285+
SmallString<256> LibPath(DeviceLibDir);
11286+
llvm::sys::path::append(LibPath, AddLib);
11287+
BCLibList.push_back(
11288+
(Twine(TC->getTriple().str()) + "=" + LibPath).str());
11289+
continue;
11290+
}
11291+
11292+
appendToList(LibList, AddLib);
11293+
}
11294+
11295+
if (TC->getTriple().isNVPTX())
11296+
if (const char *LibSpirvFile = SYCLInstallation.findLibspirvPath(
11297+
TC->getTriple(), Args, *TC->getAuxTriple()))
11298+
BCLibList.push_back(
11299+
(Twine(TC->getTriple().str()) + "=" + LibSpirvFile).str());
11300+
}
11301+
11302+
if (LibList.size())
11303+
CmdArgs.push_back(
11304+
Args.MakeArgString(Twine("-sycl-device-libraries=") + LibList));
11305+
11306+
if (BCLibList.size())
11307+
for (const std::string &Lib : BCLibList)
11308+
CmdArgs.push_back(
11309+
Args.MakeArgString(Twine("--bitcode-library=") + Lib));
11310+
1128611311
CmdArgs.push_back(Args.MakeArgString(
1128711312
Twine("-sycl-device-library-location=") + DeviceLibDir));
1128811313

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/// Test that SYCL bitcode device libraries are properly separated for NVIDIA and AMD targets.
2+
3+
/// Check devicelib and libspirv are linked for nvptx.
4+
// RUN: %clang -### -fsycl --offload-new-driver \
5+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda \
6+
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
7+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-NVPTX-BC %s
8+
9+
// RUN: %clang_cl -### -fsycl --offload-new-driver \
10+
// RUN: -fsycl-targets=nvptx64-nvidia-cuda \
11+
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
12+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-NVPTX-BC %s
13+
14+
// CHECK-NVPTX-BC: clang-linker-wrapper
15+
// CHECK-NVPTX-BC-SAME: "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc" "--bitcode-library=nvptx64-nvidia-cuda={{.*}}libspirv-nvptx64-nvidia-cuda.bc"
16+
17+
/// Check devicelib is linked for amdgcn.
18+
// RUN: %clang -### -fsycl --offload-new-driver \
19+
// RUN: -fsycl-targets=amdgcn-amd-amdhsa \
20+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
21+
// RUN: --rocm-path=%S/Inputs/rocm \
22+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-AMD-BC %s
23+
24+
// RUN: %clang_cl -### -fsycl --offload-new-driver \
25+
// RUN: -fsycl-targets=amdgcn-amd-amdhsa \
26+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
27+
// RUN: --rocm-path=%S/Inputs/rocm \
28+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-AMD-BC %s
29+
30+
// CHECK-AMD-BC: clang-linker-wrapper
31+
// CHECK-AMD-BC-SAME: "--bitcode-library=amdgcn-amd-amdhsa={{.*}}devicelib-amdgcn-amd-amdhsa.bc"
32+
33+
/// Check linking with multiple targets.
34+
// RUN: %clang -### -fsycl --offload-new-driver \
35+
// RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
36+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
37+
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
38+
// RUN: --rocm-path=%S/Inputs/rocm \
39+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-MULTI-TARGET %s
40+
41+
// RUN: %clang_cl -### -fsycl --offload-new-driver \
42+
// RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
43+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
44+
// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
45+
// RUN: --rocm-path=%S/Inputs/rocm \
46+
// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-MULTI-TARGET %s
47+
48+
// CHECK-MULTI-TARGET: clang-linker-wrapper
49+
// 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"
50+
51+
/// Test --bitcode-library with nvptx dummy libraries.
52+
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.nvptx.devicelib.bc
53+
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.nvptx.libspirv.bc
54+
// RUN: %clangxx -fsycl -fsycl-targets=nvptx64-nvidia-cuda --offload-new-driver -c %s -o %t.nvptx.o -nocudalib
55+
// RUN: clang-linker-wrapper --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.devicelib.bc --bitcode-library=nvptx64-nvidia-cuda=%t.nvptx.libspirv.bc \
56+
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
57+
// RUN: --linker-path=/usr/bin/ld %t.nvptx.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-NVPTX %s
58+
59+
// CHECK-WRAPPER-NVPTX: llvm-link{{.*}} {{.*}}.nvptx.devicelib.bc {{.*}}.nvptx.libspirv.bc
60+
61+
/// Test --bitcode-library with amdgcn dummy library.
62+
// RUN: %clang -cc1 %s -triple amdgcn-amd-amdhsa -emit-llvm-bc -o %t.amd.devicelib.bc
63+
// RUN: %clangxx -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
64+
// RUN: clang-linker-wrapper --bitcode-library=amdgcn-amd-amdhsa=%t.amd.devicelib.bc \
65+
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
66+
// RUN: --linker-path=/usr/bin/ld %t.amd.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-AMD %s
67+
68+
// CHECK-WRAPPER-AMD: llvm-link{{.*}} {{.*}}.amd.devicelib.bc
69+
70+
/// Test --bitcode-library with multi-target bc libraries.
71+
// RUN: %clangxx -fsycl -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \
72+
// RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \
73+
// RUN: --offload-new-driver -c %s -o %t.multi.o -nocudalib -nogpulib
74+
// 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 \
75+
// RUN: --host-triple=x86_64-unknown-linux-gnu --dry-run \
76+
// RUN: --linker-path=/usr/bin/ld %t.multi.o -o a.out 2>&1 | FileCheck -check-prefix=CHECK-WRAPPER-MULTI %s
77+
78+
// CHECK-WRAPPER-MULTI: llvm-link{{.*}} {{.*}}.amd.devicelib.bc
79+
// CHECK-WRAPPER-MULTI: llvm-link{{.*}} {{.*}}.nvptx.devicelib.bc {{.*}}.nvptx.libspirv.bc

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,24 +1432,17 @@ static Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
14321432
<< "Compatible SYCL device library binary not found\n";
14331433
}
14341434

1435-
// For NVPTX backend we need to also link libclc and CUDA libdevice.
1436-
if (Triple.isNVPTX()) {
1437-
if (Arg *A = Args.getLastArg(OPT_sycl_nvptx_device_lib_EQ)) {
1438-
if (A->getValues().size() == 0)
1439-
return createStringError(
1440-
inconvertibleErrorCode(),
1441-
"Number of device library files cannot be zero.");
1442-
for (StringRef Val : A->getValues()) {
1443-
SmallString<128> LibName(Val);
1444-
if (llvm::sys::fs::exists(LibName))
1445-
ExtractedDeviceLibFiles.emplace_back(std::string(LibName));
1446-
else
1447-
return createStringError(
1448-
inconvertibleErrorCode(),
1449-
std::string(LibName) +
1450-
" SYCL device library file for NVPTX is not found.");
1451-
}
1452-
}
1435+
for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
1436+
auto [LibraryTriple, LibraryPath] = Library.split('=');
1437+
if (llvm::Triple(LibraryTriple) != Triple)
1438+
continue;
1439+
1440+
if (!llvm::sys::fs::exists(LibraryPath))
1441+
return createStringError(inconvertibleErrorCode(),
1442+
"The specified device library " + LibraryPath +
1443+
" does not exist.");
1444+
1445+
ExtractedDeviceLibFiles.emplace_back(LibraryPath.str());
14531446
}
14541447

14551448
// Make sure that SYCL device library files are available.
@@ -2551,13 +2544,6 @@ getDeviceInput(const ArgList &Args) {
25512544
}
25522545
}
25532546

2554-
for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
2555-
auto FileOrErr = getInputBitcodeLibrary(Library);
2556-
if (!FileOrErr)
2557-
return FileOrErr.takeError();
2558-
InputFiles[*FileOrErr].push_back(std::move(*FileOrErr));
2559-
}
2560-
25612547
SmallVector<SmallVector<OffloadFile>> InputsForTarget;
25622548
for (auto &[ID, Input] : InputFiles)
25632549
InputsForTarget.emplace_back(std::move(Input));

clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,6 @@ def sycl_device_lib_EQ : CommaJoined<["--", "-"], "sycl-device-libraries=">,
156156
def sycl_device_library_location_EQ : Joined<["--", "-"],
157157
"sycl-device-library-location=">, Flags<[WrapperOnlyOption]>,
158158
HelpText<"Location of SYCL device library files">;
159-
def sycl_nvptx_device_lib_EQ : CommaJoined<["--", "-"], "sycl-nvptx-device-libraries=">,
160-
Flags<[WrapperOnlyOption]>,
161-
HelpText<"A comma separated list of nvptx-specific device libraries that are linked during the device link.">;
162159

163160
// Options for SYCL backends and linker options for shared libraries.
164161
def sycl_backend_compile_options_EQ :

0 commit comments

Comments
 (0)