Skip to content

Commit 962c922

Browse files
[SYCL][Fusion] API for kernel fusion library
First components for the JIT compiler used for SYCL kernel fusion: * API definitions * Input translation from SPIR-V to LLVM IR * Insertion of fused kernel function stub and metadata * Supporting infrastructure such as compiler options. Co-authored-by: Lukas Sommer <lukas.sommer@codeplay.com> Co-authored-by: Victor Perez <victor.perez@codeplay.com> Signed-off-by: Lukas Sommer <lukas.sommer@codeplay.com>
1 parent 6aefd63 commit 962c922

21 files changed

+1504
-0
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,6 @@ llvm/include/llvm/SYCLLowerIR/LowerInvokeSimd.h @kbobrovs @v-klochkov @rolandsch
7070
.github/workflows/ @intel/dpcpp-devops-reviewers
7171
buildbot/ @intel/dpcpp-devops-reviewers
7272
devops/ @intel/dpcpp-devops-reviewers
73+
74+
# Kernel fusion JIT compiler
75+
sycl-fusion/ @victor-eds @Naghasan @sommerlukas

sycl-fusion/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
2+
3+
# Define a variable holding the root directory of the JIT compiler project
4+
# for use in includes etc.
5+
set(SYCL_JIT_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
6+
7+
# For some reason, the LLVMSPIRVLib does not define any public includes.
8+
# To link against the library, define the following link to its include
9+
# directories, similar to how clang/CMakeLists.txt does it.
10+
set(LLVM_SPIRV_INCLUDE_DIRS "${LLVM_MAIN_SRC_DIR}/../llvm-spirv/include")
11+
12+
add_subdirectory(jit-compiler)

sycl-fusion/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SYCL Kernel Fusion Compiler
2+
3+
Basic JIT compiler infrastructure to perform online kernel fusion of SYCL kernels at runtime.
4+
5+
The experimental SYCL extension for kernel fusion is described in
6+
[this proposal](../sycl/doc/extensions/experimental/sycl_ext_codeplay_kernel_fusion.asciidoc).
7+
8+
The design of the JIT compiler is described in this
9+
[design document](../sycl/doc/design/KernelFusionJIT.md).
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//==------- Kernel.h - Representation of a SYCL kernel for JIT compiler ----==//
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 SYCL_FUSION_COMMON_KERNEL_H
10+
#define SYCL_FUSION_COMMON_KERNEL_H
11+
12+
#include <algorithm>
13+
#include <string>
14+
#include <vector>
15+
16+
namespace jit_compiler {
17+
18+
using BinaryAddress = const unsigned char *;
19+
20+
///
21+
/// Enumerate possible kinds of parameters.
22+
/// 1:1 correspondence with the definition in kernel_desc.hpp in the DPC++ SYCL
23+
/// runtime.
24+
enum class ParameterKind : unsigned {
25+
Accessor = 0,
26+
StdLayout = 1,
27+
Sampler = 2,
28+
Pointer = 3,
29+
SpecConstBuffer = 4,
30+
Stream = 5,
31+
Invalid = 0xF,
32+
};
33+
34+
/// Different binary formats supported as input to the JIT compiler.
35+
enum class BinaryFormat { INVALID, LLVM, SPIRV };
36+
37+
/// Information about a device intermediate representation module (e.g., SPIR-V,
38+
/// LLVM IR) from DPC++.
39+
struct SYCLKernelBinaryInfo {
40+
41+
BinaryFormat Format = BinaryFormat::INVALID;
42+
43+
size_t AddressBits = 0;
44+
45+
BinaryAddress BinaryStart = nullptr;
46+
47+
size_t BinarySize = 0;
48+
};
49+
50+
///
51+
/// Describe a SYCL/OpenCL kernel attribute by its name and values.
52+
struct SYCLKernelAttribute {
53+
using AttributeValueList = std::vector<std::string>;
54+
55+
// Explicit constructor for compatibility with LLVM YAML I/O.
56+
SYCLKernelAttribute() : Values{} {};
57+
SYCLKernelAttribute(std::string Name)
58+
: AttributeName{std::move(Name)}, Values{} {}
59+
60+
std::string AttributeName;
61+
AttributeValueList Values;
62+
};
63+
64+
enum ArgUsage : unsigned char {
65+
// Used to indicate that an argument is not used by the kernel
66+
Unused = 0,
67+
// Used to indicate that an argument is used by the kernel
68+
Used = 1u,
69+
// Used to indicate that the accessor/pointer argument has been promoted to
70+
// private memory
71+
PromotedPrivate = 1u << 4,
72+
// Used to indicate that the accessor/pointer argument has been promoted to
73+
// local memory
74+
PromotedLocal = 1u << 5,
75+
};
76+
77+
///
78+
/// Encode usage of parameters for the actual kernel function.
79+
// This is a vector of unsigned char, because std::vector<bool> is a weird
80+
// construct and unlike all other std::vectors, and LLVM YAML I/O is having a
81+
// hard time coping with it.
82+
using ArgUsageMask = std::vector<std::underlying_type_t<ArgUsage>>;
83+
84+
///
85+
/// Describe the list of arguments by their kind.
86+
struct SYCLArgumentDescriptor {
87+
88+
// Explicit constructor for compatibility with LLVM YAML I/O.
89+
SYCLArgumentDescriptor() : Kinds{}, UsageMask{} {}
90+
91+
std::vector<ParameterKind> Kinds;
92+
93+
ArgUsageMask UsageMask;
94+
};
95+
96+
///
97+
/// List of SYCL/OpenCL kernel attributes.
98+
using AttributeList = std::vector<SYCLKernelAttribute>;
99+
100+
/// Information about a kernel from DPC++.
101+
struct SYCLKernelInfo {
102+
103+
std::string Name;
104+
105+
SYCLArgumentDescriptor Args;
106+
107+
AttributeList Attributes;
108+
109+
SYCLKernelBinaryInfo BinaryInfo;
110+
111+
//// Explicit constructor for compatibility with LLVM YAML I/O.
112+
SYCLKernelInfo() : Name{}, Args{}, Attributes{}, BinaryInfo{} {}
113+
114+
SYCLKernelInfo(const std::string &KernelName,
115+
const SYCLArgumentDescriptor &ArgDesc,
116+
const SYCLKernelBinaryInfo &BinInfo)
117+
: Name{KernelName}, Args{ArgDesc}, Attributes{}, BinaryInfo{BinInfo} {}
118+
119+
explicit SYCLKernelInfo(const std::string &KernelName)
120+
: Name{KernelName}, Args{}, Attributes{}, BinaryInfo{} {}
121+
};
122+
123+
///
124+
/// Represents a SPIR-V translation unit containing SYCL kernels by the
125+
/// KernelInfo for each of the contained kernels.
126+
class SYCLModuleInfo {
127+
public:
128+
using KernelInfoList = std::vector<SYCLKernelInfo>;
129+
130+
void addKernel(SYCLKernelInfo &Kernel) { Kernels.push_back(Kernel); }
131+
132+
KernelInfoList &kernels() { return Kernels; }
133+
134+
bool hasKernelFor(const std::string &KernelName) {
135+
return findKernelFor(KernelName) != nullptr;
136+
}
137+
138+
SYCLKernelInfo *getKernelFor(const std::string &KernelName) {
139+
return findKernelFor(KernelName);
140+
}
141+
142+
private:
143+
SYCLKernelInfo *findKernelFor(const std::string &KernelName) {
144+
auto It =
145+
std::find_if(Kernels.begin(), Kernels.end(),
146+
[&](SYCLKernelInfo &K) { return K.Name == KernelName; });
147+
return (It != Kernels.end()) ? &*It : nullptr;
148+
}
149+
150+
KernelInfoList Kernels;
151+
};
152+
153+
} // namespace jit_compiler
154+
155+
#endif // SYCL_FUSION_COMMON_KERNEL_H
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//==----- KernelIO.h - YAML output of internal SYCL kernel representation --==//
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 SYCL_FUSION_COMMON_KERNELIO_H
10+
#define SYCL_FUSION_COMMON_KERNELIO_H
11+
12+
#include "Kernel.h"
13+
#include "llvm/Support/YAMLParser.h"
14+
#include "llvm/Support/YAMLTraits.h"
15+
16+
using llvm::yaml::IO;
17+
using llvm::yaml::MappingTraits;
18+
using llvm::yaml::ScalarEnumerationTraits;
19+
20+
// Specify how to map std::vectors of different user-defined types to YAML
21+
// sequences.
22+
LLVM_YAML_IS_SEQUENCE_VECTOR(jit_compiler::ArgUsageMask)
23+
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(jit_compiler::ParameterKind)
24+
LLVM_YAML_IS_SEQUENCE_VECTOR(jit_compiler::SYCLArgumentDescriptor)
25+
LLVM_YAML_IS_SEQUENCE_VECTOR(jit_compiler::SYCLKernelAttribute)
26+
LLVM_YAML_IS_SEQUENCE_VECTOR(jit_compiler::SYCLKernelInfo)
27+
28+
//
29+
// Mapping traits for the different elements of KernelInfo.
30+
namespace llvm {
31+
namespace yaml {
32+
33+
template <> struct ScalarEnumerationTraits<jit_compiler::ParameterKind> {
34+
static void enumeration(IO &IO, jit_compiler::ParameterKind &PK) {
35+
IO.enumCase(PK, "Accessor", jit_compiler::ParameterKind::Accessor);
36+
IO.enumCase(PK, "StdLayout", jit_compiler::ParameterKind::StdLayout);
37+
IO.enumCase(PK, "Sampler", jit_compiler::ParameterKind::Sampler);
38+
IO.enumCase(PK, "Pointer", jit_compiler::ParameterKind::Pointer);
39+
IO.enumCase(PK, "SpecConstantBuffer",
40+
jit_compiler::ParameterKind::SpecConstBuffer);
41+
IO.enumCase(PK, "Stream", jit_compiler::ParameterKind::Stream);
42+
IO.enumCase(PK, "Invalid", jit_compiler::ParameterKind::Invalid);
43+
}
44+
};
45+
46+
template <> struct ScalarEnumerationTraits<jit_compiler::BinaryFormat> {
47+
static void enumeration(IO &IO, jit_compiler::BinaryFormat &BF) {
48+
IO.enumCase(BF, "LLVM", jit_compiler::BinaryFormat::LLVM);
49+
IO.enumCase(BF, "SPIRV", jit_compiler::BinaryFormat::SPIRV);
50+
IO.enumCase(BF, "INVALID", jit_compiler::BinaryFormat::INVALID);
51+
}
52+
};
53+
54+
template <> struct MappingTraits<jit_compiler::SYCLKernelBinaryInfo> {
55+
static void mapping(IO &IO, jit_compiler::SYCLKernelBinaryInfo &BI) {
56+
IO.mapRequired("Format", BI.Format);
57+
IO.mapRequired("AddressBits", BI.AddressBits);
58+
// We do not serialize the pointer here on purpose.
59+
IO.mapRequired("BinarySize", BI.BinarySize);
60+
}
61+
};
62+
63+
template <> struct MappingTraits<jit_compiler::SYCLArgumentDescriptor> {
64+
static void mapping(IO &IO, jit_compiler::SYCLArgumentDescriptor &AD) {
65+
IO.mapRequired("Kinds", AD.Kinds);
66+
IO.mapRequired("Mask", AD.UsageMask);
67+
}
68+
};
69+
70+
template <> struct MappingTraits<jit_compiler::SYCLKernelAttribute> {
71+
static void mapping(IO &IO, jit_compiler::SYCLKernelAttribute &KA) {
72+
IO.mapRequired("AttrName", KA.AttributeName);
73+
IO.mapRequired("Values", KA.Values);
74+
}
75+
};
76+
77+
template <> struct MappingTraits<jit_compiler::SYCLKernelInfo> {
78+
static void mapping(IO &IO, jit_compiler::SYCLKernelInfo &KI) {
79+
IO.mapRequired("KernelName", KI.Name);
80+
IO.mapRequired("Args", KI.Args);
81+
IO.mapOptional("Attributes", KI.Attributes);
82+
IO.mapRequired("BinInfo", KI.BinaryInfo);
83+
}
84+
};
85+
86+
template <> struct MappingTraits<jit_compiler::SYCLModuleInfo> {
87+
static void mapping(IO &IO, jit_compiler::SYCLModuleInfo &SMI) {
88+
IO.mapRequired("Kernels", SMI.kernels());
89+
}
90+
};
91+
92+
} // namespace yaml
93+
} // namespace llvm
94+
95+
#endif // SYCL_FUSION_COMMON_KERNELIO_H
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
add_llvm_library(sycl-fusion
3+
SHARED
4+
lib/KernelFusion.cpp
5+
lib/JITContext.cpp
6+
lib/translation/SPIRVLLVMTranslation.cpp
7+
lib/fusion/FusionHelper.cpp
8+
lib/fusion/ModuleHelper.cpp
9+
lib/helper/ConfigHelper.cpp
10+
11+
LINK_COMPONENTS
12+
Core
13+
Support
14+
Analysis
15+
TransformUtils
16+
Passes
17+
Linker
18+
ScalarOpts
19+
InstCombine
20+
)
21+
22+
target_include_directories(sycl-fusion
23+
PUBLIC
24+
$<INSTALL_INTERFACE:include>
25+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
26+
$<BUILD_INTERFACE:${SYCL_JIT_BASE_DIR}/common/include>
27+
PRIVATE
28+
${CMAKE_CURRENT_SOURCE_DIR}/lib
29+
${LLVM_SPIRV_INCLUDE_DIRS}
30+
)
31+
32+
find_package(Threads REQUIRED)
33+
34+
target_link_libraries(sycl-fusion
35+
PRIVATE
36+
LLVMSPIRVLib
37+
${CMAKE_THREAD_LIBS_INIT}
38+
)
39+
40+
install(TARGETS sycl-fusion
41+
LIBRARY DESTINATION "lib${LLVM_LIBDIR_SUFFIX}" COMPONENT sycl-fusion
42+
RUNTIME DESTINATION "bin" COMPONENT sycl-fusion)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//==------- JITContext.h - Context holding data for the JIT compiler -------==//
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 SYCL_FUSION_JIT_COMPILER_JITCONTEXT_H
10+
#define SYCL_FUSION_JIT_COMPILER_JITCONTEXT_H
11+
12+
#include "llvm/IR/LLVMContext.h"
13+
#include <shared_mutex>
14+
#include <unordered_map>
15+
16+
#include "Kernel.h"
17+
#include "Parameter.h"
18+
19+
namespace jit_compiler {
20+
21+
///
22+
/// Wrapper around a SPIR-V binary.
23+
class SPIRVBinary {
24+
public:
25+
explicit SPIRVBinary(std::string Binary);
26+
27+
jit_compiler::BinaryAddress address() const;
28+
29+
size_t size() const;
30+
31+
private:
32+
std::string Blob;
33+
};
34+
35+
///
36+
/// Context to persistenly store information across invocations of the JIT
37+
/// compiler and manage lifetimes of binaries.
38+
class JITContext {
39+
40+
public:
41+
JITContext();
42+
43+
~JITContext();
44+
45+
llvm::LLVMContext *getLLVMContext();
46+
47+
SPIRVBinary &emplaceSPIRVBinary(std::string Binary);
48+
49+
private:
50+
// FIXME: Change this to std::shared_mutex after switching to C++17.
51+
using MutexT = std::shared_timed_mutex;
52+
53+
using ReadLockT = std::shared_lock<MutexT>;
54+
55+
using WriteLockT = std::unique_lock<MutexT>;
56+
57+
std::unique_ptr<llvm::LLVMContext> LLVMCtx;
58+
59+
MutexT BinariesMutex;
60+
61+
std::vector<SPIRVBinary> Binaries;
62+
};
63+
} // namespace jit_compiler
64+
65+
#endif // SYCL_FUSION_JIT_COMPILER_JITCONTEXT_H

0 commit comments

Comments
 (0)