Skip to content

Commit e1b9b50

Browse files
committed
[Driver][clang-linker-wrapper] Add initial support for OpenMP offloading to generic SPIR-V
This is the first of a series of patches to add support for OpenMP offloading to SPIR-V through liboffload with the first intended target being Intel GPUs. This patch implements the basic driver and `clang-linker-wrapper` work for JIT mode. There are still many missing pieces, so this is not yet usable. We introduce `spirv64-intel-unknown` as the only currently supported triple. The user-facing argument to enable offloading will be `-fopenmp -fopenmp-targets=spirv64-intel` Add a new `SPIRVOpenMPToolChain` toolchain based on the existing general SPIR-V toolchain which will call all the required SPIR-V tools as well as add the device RTL as an argument to the linker. As there is no production quality SPIR-V linker available, manually create an ELF binary containing the offloading image in a way that fits into the existing `liboffload` infrastructure. This ELF will eventually be passed to a runtime plugin that interacts with the Intel GPU runtime. There is also a small fix to an issue I found when trying to assemble SPIR-V when in text format. Signed-off-by: Sarnie, Nick <[email protected]>
1 parent a9237b1 commit e1b9b50

File tree

18 files changed

+296
-20
lines changed

18 files changed

+296
-20
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,8 @@ def libomptarget_amdgcn_bc_path_EQ : Joined<["--"], "libomptarget-amdgcn-bc-path
14931493
HelpText<"Path to libomptarget-amdgcn bitcode library">, Alias<libomptarget_amdgpu_bc_path_EQ>;
14941494
def libomptarget_nvptx_bc_path_EQ : Joined<["--"], "libomptarget-nvptx-bc-path=">, Group<i_Group>,
14951495
HelpText<"Path to libomptarget-nvptx bitcode library">;
1496+
def libomptarget_spirv_bc_path_EQ : Joined<["--"], "libomptarget-spirv-bc-path=">, Group<i_Group>,
1497+
HelpText<"Path to libomptarget-spirv bitcode library">;
14961498
def dD : Flag<["-"], "dD">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>,
14971499
HelpText<"Print macro definitions in -E mode in addition to normal output">;
14981500
def dI : Flag<["-"], "dI">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>,

clang/lib/Driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ add_clang_library(clangDriver
7777
ToolChains/RISCVToolchain.cpp
7878
ToolChains/Solaris.cpp
7979
ToolChains/SPIRV.cpp
80+
ToolChains/SPIRVOpenMP.cpp
8081
ToolChains/TCE.cpp
8182
ToolChains/UEFI.cpp
8283
ToolChains/VEToolchain.cpp

clang/lib/Driver/Driver.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "ToolChains/PS4CPU.h"
4444
#include "ToolChains/RISCVToolchain.h"
4545
#include "ToolChains/SPIRV.h"
46+
#include "ToolChains/SPIRVOpenMP.h"
4647
#include "ToolChains/Solaris.h"
4748
#include "ToolChains/TCE.h"
4849
#include "ToolChains/UEFI.h"
@@ -166,6 +167,20 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
166167
return std::nullopt;
167168
}
168169

170+
static std::optional<llvm::Triple>
171+
getSPIRVOffloadTargetTriple(const Driver &D, const ArgList &Args) {
172+
if (!Args.hasArg(options::OPT_offload_EQ))
173+
return llvm::Triple(
174+
"spirv64-intel"); // Only vendor "intel" is currently supported.
175+
auto TT = getOffloadTargetTriple(D, Args);
176+
if (!TT)
177+
return std::nullopt;
178+
if ((*TT).isSPIRV() && (*TT).getVendor() == llvm::Triple::Intel)
179+
return TT;
180+
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
181+
return std::nullopt;
182+
}
183+
169184
// static
170185
std::string Driver::GetResourcesPath(StringRef BinaryPath) {
171186
// Since the resource directory is embedded in the module hash, it's important
@@ -888,11 +903,12 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
888903
auto AMDTriple = getHIPOffloadTargetTriple(*this, C.getInputArgs());
889904
auto NVPTXTriple = getNVIDIAOffloadTargetTriple(*this, C.getInputArgs(),
890905
HostTC->getTriple());
906+
auto SPIRVTriple = getSPIRVOffloadTargetTriple(*this, C.getInputArgs());
891907

892908
// Attempt to deduce the offloading triple from the set of architectures.
893-
// We can only correctly deduce NVPTX / AMDGPU triples currently. We need
894-
// to temporarily create these toolchains so that we can access tools for
895-
// inferring architectures.
909+
// We can only correctly deduce NVPTX / AMDGPU / SPIR-V triples currently.
910+
// We need to temporarily create these toolchains so that we can access
911+
// tools for inferring architectures.
896912
llvm::DenseSet<StringRef> Archs;
897913
if (NVPTXTriple) {
898914
auto TempTC = std::make_unique<toolchains::CudaToolChain>(
@@ -908,7 +924,16 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
908924
C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
909925
Archs.insert(Arch);
910926
}
911-
if (!AMDTriple && !NVPTXTriple) {
927+
928+
if (SPIRVTriple) {
929+
auto TempTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>(
930+
*this, *SPIRVTriple, *HostTC, C.getInputArgs());
931+
for (StringRef Arch : getOffloadArchs(
932+
C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
933+
Archs.insert(Arch);
934+
}
935+
936+
if (!AMDTriple && !NVPTXTriple && !SPIRVTriple) {
912937
for (StringRef Arch :
913938
getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr, true))
914939
Archs.insert(Arch);
@@ -922,6 +947,8 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
922947
IsAMDOffloadArch(StringToOffloadArch(
923948
getProcessorFromTargetID(*AMDTriple, Arch)))) {
924949
DerivedArchs[AMDTriple->getTriple()].insert(Arch);
950+
} else if (SPIRVTriple && Arch == (*SPIRVTriple).str()) {
951+
DerivedArchs[Arch].insert(Arch);
925952
} else {
926953
Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch) << Arch;
927954
return;
@@ -962,7 +989,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
962989
const ToolChain *TC;
963990
// Device toolchains have to be selected differently. They pair host
964991
// and device in their implementation.
965-
if (TT.isNVPTX() || TT.isAMDGCN()) {
992+
if (TT.isNVPTX() || TT.isAMDGCN() || TT.isSPIRV()) {
966993
const ToolChain *HostTC =
967994
C.getSingleOffloadToolChain<Action::OFK_Host>();
968995
assert(HostTC && "Host toolchain should be always defined.");
@@ -975,6 +1002,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
9751002
else if (TT.isAMDGCN())
9761003
DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
9771004
*this, TT, *HostTC, C.getInputArgs());
1005+
else if (TT.isSPIRV())
1006+
DeviceTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>(
1007+
*this, TT, *HostTC, C.getInputArgs());
9781008
else
9791009
assert(DeviceTC && "Device toolchain not defined.");
9801010
}

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,10 +2829,13 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
28292829
LibraryPaths.emplace_back(LibPath);
28302830

28312831
OptSpecifier LibomptargetBCPathOpt =
2832-
Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
2833-
: options::OPT_libomptarget_nvptx_bc_path_EQ;
2832+
Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
2833+
: Triple.isNVPTX() ? options::OPT_libomptarget_nvptx_bc_path_EQ
2834+
: options::OPT_libomptarget_spirv_bc_path_EQ;
28342835

2835-
StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx";
2836+
StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu"
2837+
: Triple.isNVPTX() ? "nvptx"
2838+
: "spirv64";
28362839
std::string LibOmpTargetName =
28372840
("libomptarget-" + ArchPrefix + "-" + BitcodeSuffix + ".bc").str();
28382841

clang/lib/Driver/ToolChains/SPIRV.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T,
2828

2929
if (Input.getType() == types::TY_PP_Asm)
3030
CmdArgs.push_back("-to-binary");
31+
32+
// The text output from spirv-dis is not in the format expected
33+
// by llvm-spirv, so use the text output from llvm-spirv.
3134
if (Output.getType() == types::TY_PP_Asm)
32-
CmdArgs.push_back("--spirv-tools-dis");
35+
CmdArgs.push_back("--spirv-text");
3336

3437
CmdArgs.append({"-o", Output.getFilename()});
3538

clang/lib/Driver/ToolChains/SPIRV.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
5252

5353
namespace toolchains {
5454

55-
class LLVM_LIBRARY_VISIBILITY SPIRVToolChain final : public ToolChain {
55+
class LLVM_LIBRARY_VISIBILITY SPIRVToolChain : public ToolChain {
5656
mutable std::unique_ptr<Tool> Translator;
5757

5858
public:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//==- SPIRVOpenMP.cpp - SPIR-V OpenMP Tool Implementations --------*- C++ -*==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//==------------------------------------------------------------------------==//
8+
#include "SPIRVOpenMP.h"
9+
#include "CommonArgs.h"
10+
11+
using namespace clang::driver;
12+
using namespace clang::driver::toolchains;
13+
using namespace clang::driver::tools;
14+
using namespace llvm::opt;
15+
16+
namespace clang::driver::toolchains {
17+
SPIRVOpenMPToolChain::SPIRVOpenMPToolChain(const Driver &D,
18+
const llvm::Triple &Triple,
19+
const ToolChain &HostToolchain,
20+
const ArgList &Args)
21+
: SPIRVToolChain(D, Triple, Args), HostTC(HostToolchain) {}
22+
23+
void SPIRVOpenMPToolChain::addClangTargetOptions(
24+
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
25+
Action::OffloadKind DeviceOffloadingKind) const {
26+
27+
if (DeviceOffloadingKind != Action::OFK_OpenMP)
28+
return;
29+
30+
if (DriverArgs.hasArg(options::OPT_nogpulib))
31+
return;
32+
Twine GpuArch = getTriple().getArchName() + "-" + getTriple().getVendorName();
33+
addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GpuArch.str(),
34+
getTriple(), HostTC);
35+
}
36+
} // namespace clang::driver::toolchains
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===--- SPIRVOpenMP.h - SPIR-V OpenMP Tool Implementations ------*- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H
10+
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H
11+
12+
#include "SPIRV.h"
13+
#include "clang/Driver/Tool.h"
14+
#include "clang/Driver/ToolChain.h"
15+
16+
namespace clang::driver::toolchains {
17+
class LLVM_LIBRARY_VISIBILITY SPIRVOpenMPToolChain : public SPIRVToolChain {
18+
public:
19+
SPIRVOpenMPToolChain(const Driver &D, const llvm::Triple &Triple,
20+
const ToolChain &HostTC, const llvm::opt::ArgList &Args);
21+
22+
void addClangTargetOptions(
23+
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
24+
Action::OffloadKind DeviceOffloadingKind) const override;
25+
26+
const ToolChain &HostTC;
27+
};
28+
} // namespace clang::driver::toolchains
29+
#endif

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4256,6 +4256,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
42564256

42574257
if (TT.getArch() == llvm::Triple::UnknownArch ||
42584258
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
4259+
TT.getArch() == llvm::Triple::spirv64 ||
42594260
TT.getArch() == llvm::Triple::systemz ||
42604261
TT.getArch() == llvm::Triple::nvptx ||
42614262
TT.getArch() == llvm::Triple::nvptx64 ||

clang/test/Driver/Inputs/spirv-openmp/lib/libomptarget-spirv64-spirv64-intel.bc

Whitespace-only changes.

0 commit comments

Comments
 (0)