Skip to content

Commit cd19f3f

Browse files
authored
[Driver][clang-linker-wrapper] Add initial support for OpenMP offloading to generic SPIR-V (#120145)
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 (and eventually the SPIR-V backend) as well as add the corresponding device RTL as an argument to the linker. We can't get through the front end consistently yet, so it's difficult to add any LIT tests that execute any tools, but front end changes are planned very shortly, and then we can add those tests. --------- Signed-off-by: Sarnie, Nick <[email protected]>
1 parent 3a423a1 commit cd19f3f

File tree

11 files changed

+149
-10
lines changed

11 files changed

+149
-10
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: 8 additions & 4 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"
@@ -890,9 +891,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
890891
HostTC->getTriple());
891892

892893
// 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.
894+
// We can only correctly deduce NVPTX / AMDGPU triples currently.
895+
// We need to temporarily create these toolchains so that we can access
896+
// tools for inferring architectures.
896897
llvm::DenseSet<StringRef> Archs;
897898
if (NVPTXTriple) {
898899
auto TempTC = std::make_unique<toolchains::CudaToolChain>(
@@ -962,7 +963,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
962963
const ToolChain *TC;
963964
// Device toolchains have to be selected differently. They pair host
964965
// and device in their implementation.
965-
if (TT.isNVPTX() || TT.isAMDGCN()) {
966+
if (TT.isNVPTX() || TT.isAMDGCN() || TT.isSPIRV()) {
966967
const ToolChain *HostTC =
967968
C.getSingleOffloadToolChain<Action::OFK_Host>();
968969
assert(HostTC && "Host toolchain should be always defined.");
@@ -975,6 +976,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
975976
else if (TT.isAMDGCN())
976977
DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
977978
*this, TT, *HostTC, C.getInputArgs());
979+
else if (TT.isSPIRV())
980+
DeviceTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>(
981+
*this, TT, *HostTC, C.getInputArgs());
978982
else
979983
assert(DeviceTC && "Device toolchain not defined.");
980984
}

clang/lib/Driver/ToolChains/CommonArgs.cpp

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

28412841
OptSpecifier LibomptargetBCPathOpt =
2842-
Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
2843-
: options::OPT_libomptarget_nvptx_bc_path_EQ;
2842+
Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ
2843+
: Triple.isNVPTX() ? options::OPT_libomptarget_nvptx_bc_path_EQ
2844+
: options::OPT_libomptarget_spirv_bc_path_EQ;
28442845

2845-
StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx";
2846+
StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu"
2847+
: Triple.isNVPTX() ? "nvptx"
2848+
: "spirv64";
28462849
std::string LibOmpTargetName = ("libomptarget-" + ArchPrefix + ".bc").str();
28472850

28482851
// First check whether user specifies bc library

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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, "", getTriple(), HostTC);
33+
}
34+
} // 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
@@ -4263,6 +4263,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
42634263

42644264
if (TT.getArch() == llvm::Triple::UnknownArch ||
42654265
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
4266+
TT.getArch() == llvm::Triple::spirv64 ||
42664267
TT.getArch() == llvm::Triple::systemz ||
42674268
TT.getArch() == llvm::Triple::loongarch64 ||
42684269
TT.getArch() == llvm::Triple::nvptx ||

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

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=spirv64-intel \
2+
// RUN: --libomptarget-spirv-bc-path=%t/ -nogpulib %s 2>&1 \
3+
// RUN: | FileCheck %s
4+
5+
// verify the tools invocations
6+
// CHECK: "-cc1" "-triple" "x86_64-unknown-linux-gnu"{{.*}}"-emit-llvm-bc"{{.*}}"-x" "c"
7+
// CHECK: "-cc1" "-triple" "spirv64-intel" "-aux-triple" "x86_64-unknown-linux-gnu"
8+
// CHECK: llvm-spirv{{.*}}
9+
// CHECK: "-cc1" "-triple" "x86_64-unknown-linux-gnu"{{.*}}"-emit-obj"
10+
// CHECK: clang-linker-wrapper{{.*}} "-o" "a.out"
11+
12+
// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=spirv64-intel %s 2>&1 \
13+
// RUN: | FileCheck --check-prefix=CHECK-PHASES %s
14+
15+
// CHECK-PHASES: 0: input, "[[INPUT:.+]]", c, (host-openmp)
16+
// CHECK-PHASES: 1: preprocessor, {0}, cpp-output, (host-openmp)
17+
// CHECK-PHASES: 2: compiler, {1}, ir, (host-openmp)
18+
// CHECK-PHASES: 3: input, "[[INPUT]]", c, (device-openmp)
19+
// CHECK-PHASES: 4: preprocessor, {3}, cpp-output, (device-openmp)
20+
// CHECK-PHASES: 5: compiler, {4}, ir, (device-openmp)
21+
// CHECK-PHASES: 6: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (spirv64-intel)" {5}, ir
22+
// CHECK-PHASES: 7: backend, {6}, assembler, (device-openmp)
23+
// CHECK-PHASES: 8: assembler, {7}, object, (device-openmp)
24+
// CHECK-PHASES: 9: offload, "device-openmp (spirv64-intel)" {8}, object
25+
// CHECK-PHASES: 10: clang-offload-packager, {9}, image, (device-openmp)
26+
// CHECK-PHASES: 11: offload, "host-openmp (x86_64-unknown-linux-gnu)" {2}, "device-openmp (x86_64-unknown-linux-gnu)" {10}, ir
27+
// CHECK-PHASES: 12: backend, {11}, assembler, (host-openmp)
28+
// CHECK-PHASES: 13: assembler, {12}, object, (host-openmp)
29+
// CHECK-PHASES: 14: clang-linker-wrapper, {13}, image, (host-openmp)
30+
31+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=spirv64-intel -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS
32+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -fopenmp -fopenmp-targets=spirv64-intel -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS
33+
34+
// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[HOST_BC:.+]]"
35+
// CHECK-BINDINGS: "spirv64-intel" - "clang", inputs: ["[[INPUT]]", "[[HOST_BC]]"], output: "[[DEVICE_TEMP_BC:.+]]"
36+
// CHECK-BINDINGS: "spirv64-intel" - "SPIR-V::Translator", inputs: ["[[DEVICE_TEMP_BC]]"], output: "[[DEVICE_SPV:.+]]"
37+
// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Packager", inputs: ["[[DEVICE_SPV]]"], output: "[[DEVICE_IMAGE:.+]]"
38+
// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_IMAGE]]"], output: "[[HOST_OBJ:.+]]"
39+
// CHECK-BINDINGS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out"
40+
41+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -save-temps -fopenmp -fopenmp-targets=spirv64-intel -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS-TEMPS
42+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -ccc-print-bindings -save-temps -fopenmp -fopenmp-targets=spirv64-intel %s 2>&1 | FileCheck %s --check-prefix=CHECK-BINDINGS-TEMPS
43+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[HOST_PP:.+]]"
44+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_PP]]"], output: "[[HOST_BC:.+]]"
45+
// CHECK-BINDINGS-TEMPS: "spirv64-intel" - "clang", inputs: ["[[INPUT]]"], output: "[[DEVICE_PP:.+]]"
46+
// CHECK-BINDINGS-TEMPS: "spirv64-intel" - "clang", inputs: ["[[DEVICE_PP]]", "[[HOST_BC]]"], output: "[[DEVICE_TEMP_BC:.+]]"
47+
// CHECK-BINDINGS-TEMPS: "spirv64-intel" - "SPIR-V::Translator", inputs: ["[[DEVICE_TEMP_BC]]"], output: "[[DEVICE_ASM:.+]]"
48+
// CHECK-BINDINGS-TEMPS: "spirv64-intel" - "SPIR-V::Translator", inputs: ["[[DEVICE_ASM]]"], output: "[[DEVICE_SPV:.+]]"
49+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "Offload::Packager", inputs: ["[[DEVICE_SPV]]"], output: "[[DEVICE_IMAGE:.+]]"
50+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HOST_BC]]", "[[DEVICE_IMAGE]]"], output: "[[HOST_ASM:.+]]"
51+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "clang::as", inputs: ["[[HOST_ASM]]"], output: "[[HOST_OBJ:.+]]"
52+
// CHECK-BINDINGS-TEMPS: "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["[[HOST_OBJ]]"], output: "a.out"
53+
54+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -emit-llvm -S -fopenmp -fopenmp-targets=spirv64-intel -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-EMIT-LLVM-IR
55+
// CHECK-EMIT-LLVM-IR: "-cc1" "-triple" "spirv64-intel"{{.*}}"-emit-llvm-bc"
56+
57+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=spirv64-intel \
58+
// RUN: --sysroot=%S/Inputs/spirv-openmp/ %s 2>&1 | FileCheck --check-prefix=CHECK-GPULIB %s
59+
// CHECK-GPULIB: "-cc1" "-triple" "spirv64-intel"{{.*}}"-mlink-builtin-bitcode" "{{.*}}libomptarget-spirv64.bc"
60+
61+
// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fopenmp --offload-arch=spirv64-intel \
62+
// RUN: --libomptarget-spirv-bc-path=%t/ -nogpulib %s 2>&1 \
63+
// RUN: | FileCheck %s --check-prefix=CHECK-OFFLOAD-ARCH-ERROR
64+
// CHECK-OFFLOAD-ARCH-ERROR: error: failed to deduce triple for target architecture 'spirv64-intel'; specify the triple using '-fopenmp-targets' and '-Xopenmp-target' instead

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,14 +504,14 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
504504
{"-Xlinker",
505505
Args.MakeArgString("--plugin-opt=" + StringRef(Arg->getValue()))});
506506

507-
if (!Triple.isNVPTX())
507+
if (!Triple.isNVPTX() && !Triple.isSPIRV())
508508
CmdArgs.push_back("-Wl,--no-undefined");
509509

510510
for (StringRef InputFile : InputFiles)
511511
CmdArgs.push_back(InputFile);
512512

513513
// If this is CPU offloading we copy the input libraries.
514-
if (!Triple.isAMDGPU() && !Triple.isNVPTX()) {
514+
if (!Triple.isAMDGPU() && !Triple.isNVPTX() && !Triple.isSPIRV()) {
515515
CmdArgs.push_back("-Wl,-Bsymbolic");
516516
CmdArgs.push_back("-shared");
517517
ArgStringList LinkerArgs;
@@ -595,6 +595,7 @@ Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
595595
case Triple::aarch64_be:
596596
case Triple::ppc64:
597597
case Triple::ppc64le:
598+
case Triple::spirv64:
598599
case Triple::systemz:
599600
case Triple::loongarch64:
600601
return generic::clang(InputFiles, Args);

0 commit comments

Comments
 (0)