Skip to content

[SYCL]Use llvm-link's only-needed option to link device libs #2783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 10, 2020
Merged
69 changes: 47 additions & 22 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3772,16 +3772,6 @@ class OffloadingActionBuilder final {
for (auto SDA : SYCLDeviceActions)
SYCLLinkBinaryList.push_back(SDA);
if (WrapDeviceOnlyBinary) {
// If used without -fintelfpga, -fsycl-link is used to wrap device
// objects for future host link. Device libraries should be linked
// by default to resolve any undefined reference.
if (!Args.hasArg(options::OPT_fintelfpga)) {
const auto *TC = ToolChains.front();
addSYCLDeviceLibs(TC, SYCLLinkBinaryList, true,
C.getDefaultToolChain()
.getTriple()
.isWindowsMSVCEnvironment());
}
// -fsycl-link behavior does the following to the unbundled device
// binaries:
// 1) Link them together using llvm-link
Expand All @@ -3791,8 +3781,29 @@ class OffloadingActionBuilder final {
// by any compilation link step.
auto *DeviceLinkAction = C.MakeAction<LinkJobAction>(
SYCLLinkBinaryList, types::TY_Image);
ActionList FullSYCLLinkBinaryList;
bool SYCLDeviceLibLinked = false;
FullSYCLLinkBinaryList.push_back(DeviceLinkAction);
// If used without -fintelfpga, -fsycl-link is used to wrap device
// objects for future host link. Device libraries should be linked
// by default to resolve any undefined reference.
if (!Args.hasArg(options::OPT_fintelfpga)) {
const auto *TC = ToolChains.front();
SYCLDeviceLibLinked =
addSYCLDeviceLibs(TC, FullSYCLLinkBinaryList, true,
C.getDefaultToolChain()
.getTriple()
.isWindowsMSVCEnvironment());
}

Action *FullDeviceLinkAction = nullptr;
if (SYCLDeviceLibLinked)
FullDeviceLinkAction = C.MakeAction<LinkJobAction>(
FullSYCLLinkBinaryList, types::TY_LLVM_BC);
else
FullDeviceLinkAction = DeviceLinkAction;
auto *PostLinkAction = C.MakeAction<SYCLPostLinkJobAction>(
DeviceLinkAction, types::TY_LLVM_BC);
FullDeviceLinkAction, types::TY_LLVM_BC);
auto *TranslateAction = C.MakeAction<SPIRVTranslatorJobAction>(
PostLinkAction, types::TY_Image);
SYCLLinkBinary = C.MakeAction<OffloadWrapperJobAction>(
Expand Down Expand Up @@ -3948,7 +3959,7 @@ class OffloadingActionBuilder final {
SYCLDeviceActions.clear();
}

void addSYCLDeviceLibs(const ToolChain *TC, ActionList &DeviceLinkObjects,
bool addSYCLDeviceLibs(const ToolChain *TC, ActionList &DeviceLinkObjects,
bool isSpirvAOT, bool isMSVCEnv) {
enum SYCLDeviceLibType {
sycl_devicelib_wrapper,
Expand All @@ -3960,6 +3971,7 @@ class OffloadingActionBuilder final {
};

bool NoDeviceLibs = false;
int NumOfDeviceLibLinked = 0;
// Currently, libc, libm-fp32 will be linked in by default. In order
// to use libm-fp64, -fsycl-device-lib=libm-fp64/all should be used.
llvm::StringMap<bool> devicelib_link_info = {
Expand Down Expand Up @@ -4017,6 +4029,7 @@ class OffloadingActionBuilder final {
llvm::sys::path::append(LibName, Lib.devicelib_name);
llvm::sys::path::replace_extension(LibName, LibSuffix);
if (llvm::sys::fs::exists(LibName)) {
++NumOfDeviceLibLinked;
Arg *InputArg = MakeInputArg(Args, C.getDriver().getOpts(),
Args.MakeArgString(LibName));
auto *SYCLDeviceLibsInputAction =
Expand All @@ -4032,6 +4045,7 @@ class OffloadingActionBuilder final {
addInputs(sycl_devicelib_wrapper);
if (isSpirvAOT)
addInputs(sycl_devicelib_fallback);
return NumOfDeviceLibLinked != 0;
}

void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
Expand Down Expand Up @@ -4125,15 +4139,6 @@ class OffloadingActionBuilder final {
else
LinkObjects.push_back(Input);
}
// FIXME: Link all wrapper and fallback device libraries as default,
// When spv online link is supported by all backends, the fallback
// device libraries are only needed when current toolchain is using
// AOT compilation.
if (!isNVPTX) {
addSYCLDeviceLibs(
*TC, LinkObjects, true,
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment());
}
// The linkage actions subgraph leading to the offload wrapper.
// [cond] Means incoming/outgoing dependence is created only when cond
// is true. A function of:
Expand Down Expand Up @@ -4187,6 +4192,26 @@ class OffloadingActionBuilder final {
//
Action *DeviceLinkAction =
C.MakeAction<LinkJobAction>(LinkObjects, types::TY_LLVM_BC);
ActionList FullLinkObjects;
bool SYCLDeviceLibLinked = false;
FullLinkObjects.push_back(DeviceLinkAction);

// FIXME: Link all wrapper and fallback device libraries as default,
// When spv online link is supported by all backends, the fallback
// device libraries are only needed when current toolchain is using
// AOT compilation.
if (!isNVPTX) {
SYCLDeviceLibLinked = addSYCLDeviceLibs(
*TC, FullLinkObjects, true,
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment());
}

Action *FullDeviceLinkAction = nullptr;
if (SYCLDeviceLibLinked)
FullDeviceLinkAction =
C.MakeAction<LinkJobAction>(FullLinkObjects, types::TY_LLVM_BC);
else
FullDeviceLinkAction = DeviceLinkAction;
// setup some flags upfront

if (isNVPTX && DeviceCodeSplit) {
Expand All @@ -4212,7 +4237,7 @@ class OffloadingActionBuilder final {
? types::TY_LLVM_BC
: types::TY_Tempfiletable;
auto *PostLinkAction = C.MakeAction<SYCLPostLinkJobAction>(
DeviceLinkAction, PostLinkOutType);
FullDeviceLinkAction, PostLinkOutType);
PostLinkAction->setRTSetsSpecConstants(!isAOT);

if (isNVPTX) {
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "SYCL.h"
#include "CommonArgs.h"
#include "InputInfo.h"
Expand Down Expand Up @@ -107,8 +106,20 @@ const char *SYCL::Linker::constructLLVMLinkCommand(Compilation &C,
// an actual object/archive. Take that list and pass those to the linker
// instead of the original object.
if (JA.isDeviceOffloading(Action::OFK_SYCL)) {
auto SYCLDeviceLibIter =
std::find_if(InputFiles.begin(), InputFiles.end(), [](const auto &II) {
StringRef InputFilename =
llvm::sys::path::filename(StringRef(II.getFilename()));
if (InputFilename.startswith("libsycl-") &&
InputFilename.endswith(".o"))
return true;
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Using file name for deciding if --only-needed option is required looks very fragile.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi, @sndmitriev
I agree, we need some enhancement here .

});
bool LinkSYCLDeviceLibs = (SYCLDeviceLibIter != InputFiles.end());
// Go through the Inputs to the link. When a listfile is encountered, we
// know it is an unbundled generated list.
if (LinkSYCLDeviceLibs)
CmdArgs.push_back("-only-needed");
for (const auto &II : InputFiles) {
if (II.getType() == types::TY_Tempfilelist) {
// Pass the unbundled list with '@' to be processed.
Expand Down
Loading