Skip to content

Commit e9423ff

Browse files
authored
[SYCL] Use llvm-link's only-needed option to link device libs (#2783)
This patch remove unused device library function definitions from linked program. We will do 2-step link: 1. normal llvm-link for all user LLVM bc to generate a "full" user.bc 2. llvm-link -only-needed to link "full" user.bc with device libraries. In step, we expect only functions really required by user code will be linked in. Signed-off-by: gejin <[email protected]>
1 parent f0e7606 commit e9423ff

File tree

4 files changed

+128
-49
lines changed

4 files changed

+128
-49
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,16 +3772,6 @@ class OffloadingActionBuilder final {
37723772
for (auto SDA : SYCLDeviceActions)
37733773
SYCLLinkBinaryList.push_back(SDA);
37743774
if (WrapDeviceOnlyBinary) {
3775-
// If used without -fintelfpga, -fsycl-link is used to wrap device
3776-
// objects for future host link. Device libraries should be linked
3777-
// by default to resolve any undefined reference.
3778-
if (!Args.hasArg(options::OPT_fintelfpga)) {
3779-
const auto *TC = ToolChains.front();
3780-
addSYCLDeviceLibs(TC, SYCLLinkBinaryList, true,
3781-
C.getDefaultToolChain()
3782-
.getTriple()
3783-
.isWindowsMSVCEnvironment());
3784-
}
37853775
// -fsycl-link behavior does the following to the unbundled device
37863776
// binaries:
37873777
// 1) Link them together using llvm-link
@@ -3791,8 +3781,29 @@ class OffloadingActionBuilder final {
37913781
// by any compilation link step.
37923782
auto *DeviceLinkAction = C.MakeAction<LinkJobAction>(
37933783
SYCLLinkBinaryList, types::TY_Image);
3784+
ActionList FullSYCLLinkBinaryList;
3785+
bool SYCLDeviceLibLinked = false;
3786+
FullSYCLLinkBinaryList.push_back(DeviceLinkAction);
3787+
// If used without -fintelfpga, -fsycl-link is used to wrap device
3788+
// objects for future host link. Device libraries should be linked
3789+
// by default to resolve any undefined reference.
3790+
if (!Args.hasArg(options::OPT_fintelfpga)) {
3791+
const auto *TC = ToolChains.front();
3792+
SYCLDeviceLibLinked =
3793+
addSYCLDeviceLibs(TC, FullSYCLLinkBinaryList, true,
3794+
C.getDefaultToolChain()
3795+
.getTriple()
3796+
.isWindowsMSVCEnvironment());
3797+
}
3798+
3799+
Action *FullDeviceLinkAction = nullptr;
3800+
if (SYCLDeviceLibLinked)
3801+
FullDeviceLinkAction = C.MakeAction<LinkJobAction>(
3802+
FullSYCLLinkBinaryList, types::TY_LLVM_BC);
3803+
else
3804+
FullDeviceLinkAction = DeviceLinkAction;
37943805
auto *PostLinkAction = C.MakeAction<SYCLPostLinkJobAction>(
3795-
DeviceLinkAction, types::TY_LLVM_BC);
3806+
FullDeviceLinkAction, types::TY_LLVM_BC);
37963807
auto *TranslateAction = C.MakeAction<SPIRVTranslatorJobAction>(
37973808
PostLinkAction, types::TY_Image);
37983809
SYCLLinkBinary = C.MakeAction<OffloadWrapperJobAction>(
@@ -3948,7 +3959,7 @@ class OffloadingActionBuilder final {
39483959
SYCLDeviceActions.clear();
39493960
}
39503961

3951-
void addSYCLDeviceLibs(const ToolChain *TC, ActionList &DeviceLinkObjects,
3962+
bool addSYCLDeviceLibs(const ToolChain *TC, ActionList &DeviceLinkObjects,
39523963
bool isSpirvAOT, bool isMSVCEnv) {
39533964
enum SYCLDeviceLibType {
39543965
sycl_devicelib_wrapper,
@@ -3960,6 +3971,7 @@ class OffloadingActionBuilder final {
39603971
};
39613972

39623973
bool NoDeviceLibs = false;
3974+
int NumOfDeviceLibLinked = 0;
39633975
// Currently, libc, libm-fp32 will be linked in by default. In order
39643976
// to use libm-fp64, -fsycl-device-lib=libm-fp64/all should be used.
39653977
llvm::StringMap<bool> devicelib_link_info = {
@@ -4017,6 +4029,7 @@ class OffloadingActionBuilder final {
40174029
llvm::sys::path::append(LibName, Lib.devicelib_name);
40184030
llvm::sys::path::replace_extension(LibName, LibSuffix);
40194031
if (llvm::sys::fs::exists(LibName)) {
4032+
++NumOfDeviceLibLinked;
40204033
Arg *InputArg = MakeInputArg(Args, C.getDriver().getOpts(),
40214034
Args.MakeArgString(LibName));
40224035
auto *SYCLDeviceLibsInputAction =
@@ -4032,6 +4045,7 @@ class OffloadingActionBuilder final {
40324045
addInputs(sycl_devicelib_wrapper);
40334046
if (isSpirvAOT)
40344047
addInputs(sycl_devicelib_fallback);
4048+
return NumOfDeviceLibLinked != 0;
40354049
}
40364050

40374051
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
@@ -4125,15 +4139,6 @@ class OffloadingActionBuilder final {
41254139
else
41264140
LinkObjects.push_back(Input);
41274141
}
4128-
// FIXME: Link all wrapper and fallback device libraries as default,
4129-
// When spv online link is supported by all backends, the fallback
4130-
// device libraries are only needed when current toolchain is using
4131-
// AOT compilation.
4132-
if (!isNVPTX) {
4133-
addSYCLDeviceLibs(
4134-
*TC, LinkObjects, true,
4135-
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment());
4136-
}
41374142
// The linkage actions subgraph leading to the offload wrapper.
41384143
// [cond] Means incoming/outgoing dependence is created only when cond
41394144
// is true. A function of:
@@ -4187,6 +4192,26 @@ class OffloadingActionBuilder final {
41874192
//
41884193
Action *DeviceLinkAction =
41894194
C.MakeAction<LinkJobAction>(LinkObjects, types::TY_LLVM_BC);
4195+
ActionList FullLinkObjects;
4196+
bool SYCLDeviceLibLinked = false;
4197+
FullLinkObjects.push_back(DeviceLinkAction);
4198+
4199+
// FIXME: Link all wrapper and fallback device libraries as default,
4200+
// When spv online link is supported by all backends, the fallback
4201+
// device libraries are only needed when current toolchain is using
4202+
// AOT compilation.
4203+
if (!isNVPTX) {
4204+
SYCLDeviceLibLinked = addSYCLDeviceLibs(
4205+
*TC, FullLinkObjects, true,
4206+
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment());
4207+
}
4208+
4209+
Action *FullDeviceLinkAction = nullptr;
4210+
if (SYCLDeviceLibLinked)
4211+
FullDeviceLinkAction =
4212+
C.MakeAction<LinkJobAction>(FullLinkObjects, types::TY_LLVM_BC);
4213+
else
4214+
FullDeviceLinkAction = DeviceLinkAction;
41904215
// setup some flags upfront
41914216

41924217
if (isNVPTX && DeviceCodeSplit) {
@@ -4212,7 +4237,7 @@ class OffloadingActionBuilder final {
42124237
? types::TY_LLVM_BC
42134238
: types::TY_Tempfiletable;
42144239
auto *PostLinkAction = C.MakeAction<SYCLPostLinkJobAction>(
4215-
DeviceLinkAction, PostLinkOutType);
4240+
FullDeviceLinkAction, PostLinkOutType);
42164241
PostLinkAction->setRTSetsSpecConstants(!isAOT);
42174242

42184243
if (isNVPTX) {

clang/lib/Driver/ToolChains/SYCL.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8-
98
#include "SYCL.h"
109
#include "CommonArgs.h"
1110
#include "InputInfo.h"
@@ -107,8 +106,20 @@ const char *SYCL::Linker::constructLLVMLinkCommand(Compilation &C,
107106
// an actual object/archive. Take that list and pass those to the linker
108107
// instead of the original object.
109108
if (JA.isDeviceOffloading(Action::OFK_SYCL)) {
109+
auto SYCLDeviceLibIter =
110+
std::find_if(InputFiles.begin(), InputFiles.end(), [](const auto &II) {
111+
StringRef InputFilename =
112+
llvm::sys::path::filename(StringRef(II.getFilename()));
113+
if (InputFilename.startswith("libsycl-") &&
114+
InputFilename.endswith(".o"))
115+
return true;
116+
return false;
117+
});
118+
bool LinkSYCLDeviceLibs = (SYCLDeviceLibIter != InputFiles.end());
110119
// Go through the Inputs to the link. When a listfile is encountered, we
111120
// know it is an unbundled generated list.
121+
if (LinkSYCLDeviceLibs)
122+
CmdArgs.push_back("-only-needed");
112123
for (const auto &II : InputFiles) {
113124
if (II.getType() == types::TY_Tempfilelist) {
114125
// Pass the unbundled list with '@' to be processed.

0 commit comments

Comments
 (0)