Skip to content

[SYCL] Link SYCL device libraries by default. #2400

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 18 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
9 changes: 9 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3561,6 +3561,15 @@ def fsycl_dead_args_optimization : Flag<["-"], "fsycl-dead-args-optimization">,
def fno_sycl_dead_args_optimization : Flag<["-"], "fno-sycl-dead-args-optimization">,
Group<sycl_Group>, Flags<[NoArgumentUnused, CoreOption]>, HelpText<"Disables "
"elimination of DPC++ dead kernel arguments">;
def fsycl_device_lib_EQ : CommaJoined<["-"], "fsycl-device-lib=">, Group<sycl_Group>, Flags<[DriverOption, CoreOption]>,
Values<"libc, libm-fp32, libm-fp64, all">, HelpText<"Control inclusion of "
"device libraries into device binary linkage. Valid arguments "
"are libc, libm-fp32, libm-fp64, all">;
def fno_sycl_device_lib_EQ : CommaJoined<["-"], "fno-sycl-device-lib=">, Group<sycl_Group>, Flags<[DriverOption, CoreOption]>,
Values<"libc, libm-fp32, libm-fp64, all">, HelpText<"Control exclusion of "
"device libraries from device binary linkage. Valid arguments "
"are libc, libm-fp32, libm-fp64, all">;

//===----------------------------------------------------------------------===//
// CC1 Options
//===----------------------------------------------------------------------===//
Expand Down
124 changes: 117 additions & 7 deletions clang/lib/Driver/Driver.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 "clang/Driver/Driver.h"
#include "InputInfo.h"
#include "ToolChains/AIX.h"
Expand Down Expand Up @@ -2715,6 +2714,16 @@ static SmallVector<const char *, 16> getLinkerArgs(Compilation &C,
return LibArgs;
}

static bool IsSYCLDeviceLibObj(std::string ObjFilePath, bool isMSVCEnv) {
StringRef ObjFileName = llvm::sys::path::filename(ObjFilePath);
StringRef ObjSuffix = isMSVCEnv ? ".obj" : ".o";
bool Ret =
(ObjFileName.startswith("libsycl-") && ObjFileName.endswith(ObjSuffix))
? true
: false;
return Ret;
}

// Goes through all of the arguments, including inputs expected for the
// linker directly, to determine if we need to perform additional work for
// static offload libraries.
Expand Down Expand Up @@ -3790,7 +3799,13 @@ class OffloadingActionBuilder final {
if (IA->getType() == types::TY_Object) {
if (!isObjectFile(FileName))
return ABRT_Inactive;
if (Args.hasArg(options::OPT_fintelfpga))
// For SYCL device libraries, don't need to add them to
// FPGAObjectInputs as there is no FPGA dep files inside.

if (Args.hasArg(options::OPT_fintelfpga) &&
!IsSYCLDeviceLibObj(FileName, C.getDefaultToolChain()
.getTriple()
.isWindowsMSVCEnvironment()))
FPGAObjectInputs.push_back(IA);
}
// When creating FPGA device fat objects, all host objects are
Expand Down Expand Up @@ -3854,6 +3869,92 @@ class OffloadingActionBuilder final {
SYCLDeviceActions.clear();
}

void addSYCLDeviceLibs(const ToolChain *TC, ActionList &DeviceLinkObjects,
bool isSpirvAOT, bool isMSVCEnv) {
enum SYCLDeviceLibType {
sycl_devicelib_wrapper,
sycl_devicelib_fallback
};
struct DeviceLibOptInfo {
StringRef devicelib_name;
StringRef devicelib_option;
};

bool NoDeviceLibs = false;
// 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 = {
{"libc", true}, {"libm-fp32", true}, {"libm-fp64", false}};
if (Arg *A = Args.getLastArg(options::OPT_fsycl_device_lib_EQ,
options::OPT_fno_sycl_device_lib_EQ)) {
if (A->getValues().size() == 0)
C.getDriver().Diag(diag::warn_drv_empty_joined_argument)
<< A->getAsString(Args);
else {
if (A->getOption().matches(options::OPT_fno_sycl_device_lib_EQ))
NoDeviceLibs = true;

for (StringRef Val : A->getValues()) {
if (Val == "all") {
for (auto &K : devicelib_link_info.keys())
devicelib_link_info[K] = true && !NoDeviceLibs;
break;
}
auto LinkInfoIter = devicelib_link_info.find(Val);
if (LinkInfoIter == devicelib_link_info.end()) {
C.getDriver().Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
}
devicelib_link_info[Val] = true && !NoDeviceLibs;
}
}
}

SmallString<128> LibLoc(TC->getDriver().Dir);
llvm::sys::path::append(LibLoc, "/../lib");
StringRef LibSuffix = isMSVCEnv ? ".obj" : ".o";
SmallVector<DeviceLibOptInfo, 5> sycl_device_wrapper_libs = {
{"libsycl-crt", "libc"},
{"libsycl-complex", "libm-fp32"},
{"libsycl-complex-fp64", "libm-fp64"},
{"libsycl-cmath", "libm-fp32"},
{"libsycl-cmath-fp64", "libm-fp64"}};
// For AOT compilation, we need to link sycl_device_fallback_libs as
// default too.
SmallVector<DeviceLibOptInfo, 5> sycl_device_fallback_libs = {
{"libsycl-fallback-cassert", "libc"},
{"libsycl-fallback-complex", "libm-fp32"},
{"libsycl-fallback-complex-fp64", "libm-fp64"},
{"libsycl-fallback-cmath", "libm-fp32"},
{"libsycl-fallback-cmath-fp64", "libm-fp64"}};
auto addInputs = [&](SYCLDeviceLibType t) {
auto sycl_libs = (t == sycl_devicelib_wrapper)
? sycl_device_wrapper_libs
: sycl_device_fallback_libs;
for (const DeviceLibOptInfo &Lib : sycl_libs) {
if (!devicelib_link_info[Lib.devicelib_option])
continue;
SmallString<128> LibName(LibLoc);
llvm::sys::path::append(LibName, Lib.devicelib_name);
llvm::sys::path::replace_extension(LibName, LibSuffix);
if (llvm::sys::fs::exists(LibName)) {
Arg *InputArg = MakeInputArg(Args, C.getDriver().getOpts(),
Args.MakeArgString(LibName));
auto *SYCLDeviceLibsInputAction =
C.MakeAction<InputAction>(*InputArg, types::TY_Object);
auto *SYCLDeviceLibsUnbundleAction =
C.MakeAction<OffloadUnbundlingJobAction>(
SYCLDeviceLibsInputAction);
addDeviceDepences(SYCLDeviceLibsUnbundleAction);
DeviceLinkObjects.push_back(SYCLDeviceLibsUnbundleAction);
}
}
};
addInputs(sycl_devicelib_wrapper);
if (isSpirvAOT)
addInputs(sycl_devicelib_fallback);
}

void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
assert(ToolChains.size() == DeviceLinkerInputs.size() &&
"Toolchains and linker inputs sizes do not match.");
Expand Down Expand Up @@ -3933,13 +4034,27 @@ class OffloadingActionBuilder final {
}
ActionList DeviceLibObjects;
ActionList LinkObjects;
auto TT = SYCLTripleList[I];
auto isNVPTX = (*TC)->getTriple().isNVPTX();
bool isSpirvAOT = TT.getSubArch() == llvm::Triple::SPIRSubArch_fpga ||
TT.getSubArch() == llvm::Triple::SPIRSubArch_gen ||
TT.getSubArch() == llvm::Triple::SPIRSubArch_x86_64;
for (const auto &Input : LI) {
// FPGA aoco does not go through the link, everything else does.
if (Input->getType() == types::TY_FPGA_AOCO)
DeviceLibObjects.push_back(Input);
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 @@ -3994,7 +4109,6 @@ class OffloadingActionBuilder final {
Action *DeviceLinkAction =
C.MakeAction<LinkJobAction>(LinkObjects, types::TY_LLVM_BC);
// setup some flags upfront
auto isNVPTX = (*TC)->getTriple().isNVPTX();

if (isNVPTX && DeviceCodeSplit) {
// TODO Temporary limitation, need to support code splitting for PTX
Expand All @@ -4006,10 +4120,6 @@ class OffloadingActionBuilder final {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< OptName << (*TC)->getTriple().str();
}
auto TT = SYCLTripleList[I];
bool isSpirvAOT = TT.getSubArch() == llvm::Triple::SPIRSubArch_fpga ||
TT.getSubArch() == llvm::Triple::SPIRSubArch_gen ||
TT.getSubArch() == llvm::Triple::SPIRSubArch_x86_64;
// reflects whether current target is ahead-of-time and can't support
// runtime setting of specialization constants
bool isAOT = isNVPTX || isSpirvAOT;
Expand Down
93 changes: 93 additions & 0 deletions clang/test/Driver/sycl-device-lib-win.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
///
/// Perform several driver tests for SYCL device libraries on Windows
///
// REQUIRES: clang-driver, windows

/// ###########################################################################

/// test behavior of device library default link
// RUN: %clangxx -fsycl %s -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc,libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libm-fp64 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-msvc.o" "-outputs={{.*}}libsycl-msvc-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-complex.o" "-outputs={{.*}}libsycl-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-cmath.o" "-outputs={{.*}}libsycl-cmath-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cassert.o" "-outputs={{.*}}libsycl-fallback-cassert-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-complex.o" "-outputs={{.*}}libsycl-fallback-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_DEFAULT-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cmath.o" "-outputs={{.*}}libsycl-fallback-cmath-{{.*}}.o" "-unbundle"

/// ###########################################################################
/// test behavior of device library link with libm-fp64
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libm-fp64 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc,libm-fp64 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64
// RUN: %clangxx -fsycl %s -fsycl-device-lib=all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc,libm-fp32,libm-fp64 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc,all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-msvc.o" "-outputs={{.*}}libsycl-msvc-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-complex.o" "-outputs={{.*}}libsycl-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-complex-fp64.o" "-outputs={{.*}}libsycl-complex-fp64-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-cmath.o" "-outputs={{.*}}libsycl-cmath-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-cmath-fp64.o" "-outputs={{.*}}libsycl-cmath-fp64-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cassert.o" "-outputs={{.*}}libsycl-fallback-cassert-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-complex.o" "-outputs={{.*}}libsycl-fallback-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-complex-fp64.o" "-outputs={{.*}}libsycl-fallback-complex-fp64-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cmath.o" "-outputs={{.*}}libsycl-fallback-cmath-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_WITH_FP64-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cmath-fp64.o" "-outputs={{.*}}libsycl-fallback-cmath-fp64-{{.*}}.o" "-unbundle"

/// ###########################################################################

/// test behavior of -fno-sycl-device-lib=libc
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libc -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBC
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBC: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-complex.o" "-outputs={{.*}}libsycl-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBC-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-cmath.o" "-outputs={{.*}}libsycl-cmath-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBC-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-complex.o" "-outputs={{.*}}libsycl-fallback-complex-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBC-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cmath.o" "-outputs={{.*}}libsycl-fallback-cmath-{{.*}}.o" "-unbundle"

/// ###########################################################################

/// test behavior of -fno-sycl-device-lib=libm-fp32
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBM_FP32
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBM_FP32: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-msvc.o" "-outputs={{.*}}libsycl-msvc-{{.*}}.o" "-unbundle"
// SYCL_DEVICE_LIB_UNBUNDLE_NO_LIBM_FP32-NEXT: clang-offload-bundler{{.*}} "-type=o" "-targets=sycl-spir64-unknown-unknown-sycldevice" "-inputs={{.*}}libsycl-fallback-cassert.o" "-outputs={{.*}}libsycl-fallback-cassert-{{.*}}.o" "-unbundle"

/// ###########################################################################

/// test behavior of disabling all device libraries
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libc,libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libc,all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libm-fp32,all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libm-fp64,all -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=libc,all,libm-fp64,libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB
// SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB: {{.*}}clang{{.*}} "-cc1" "-triple" "spir64-unknown-unknown-sycldevice"
// SYCL_DEVICE_LIB_UNBUNDLE_NO_DEVICE_LIB-NEXT: {{.*}}llvm-link{{.*}} {{.*}} "--suppress-warnings"

/// ###########################################################################

/// test invalid value for -f[no-]sycl-device-lib
// RUN: %clangxx -fsycl %s -fsycl-device-lib=libc,dummy -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_DEVICE_LIB_INVALID_VALUE
// RUN: %clangxx -fsycl %s -fno-sycl-device-lib=dummy,libm-fp32 -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=SYCL_NO_DEVICE_LIB_INVALID_VALUE
// SYCL_DEVICE_LIB_INVALID_VALUE: error: unsupported argument 'dummy' to option 'fsycl-device-lib='
// SYCL_NO_DEVICE_LIB_INVALID_VALUE: error: unsupported argument 'dummy' to option 'fno-sycl-device-lib='
Loading