Skip to content

Commit 699fe4c

Browse files
authored
Merge branch 'sycl' into devsan-only-report-one-error
2 parents 7fc1446 + 9a76a3a commit 699fe4c

File tree

17 files changed

+477
-3
lines changed

17 files changed

+477
-3
lines changed

sycl-jit/common/include/Kernel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ struct SYCLKernelInfo {
350350
: Name{KernelName}, Args{NumArgs}, Attributes{}, NDR{}, BinaryInfo{} {}
351351
};
352352

353+
struct InMemoryFile {
354+
const char *Path;
355+
const char *Contents;
356+
};
357+
353358
} // namespace jit_compiler
354359

355360
#endif // SYCL_FUSION_COMMON_KERNEL_H

sycl-jit/jit-compiler/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_llvm_library(sycl-jit
77
lib/fusion/FusionHelper.cpp
88
lib/fusion/JITContext.cpp
99
lib/fusion/ModuleHelper.cpp
10+
lib/rtc/DeviceCompilation.cpp
1011
lib/helper/ConfigHelper.cpp
1112

1213
SHARED
@@ -29,6 +30,14 @@ add_llvm_library(sycl-jit
2930
TargetParser
3031
MC
3132
${LLVM_TARGETS_TO_BUILD}
33+
34+
LINK_LIBS
35+
clangBasic
36+
clangDriver
37+
clangFrontend
38+
clangCodeGen
39+
clangTooling
40+
clangSerialization
3241
)
3342

3443
target_compile_options(sycl-jit PRIVATE ${SYCL_JIT_WARNING_FLAGS})
@@ -40,6 +49,8 @@ target_include_directories(sycl-jit
4049
SYSTEM PRIVATE
4150
${LLVM_MAIN_INCLUDE_DIR}
4251
${LLVM_SPIRV_INCLUDE_DIRS}
52+
${LLVM_EXTERNAL_CLANG_SOURCE_DIR}/include
53+
${CMAKE_BINARY_DIR}/tools/clang/include
4354
)
4455
target_include_directories(sycl-jit
4556
PUBLIC

sycl-jit/jit-compiler/include/KernelFusion.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ JITResult materializeSpecConstants(const char *KernelName,
6666
jit_compiler::SYCLKernelBinaryInfo &BinInfo,
6767
View<unsigned char> SpecConstBlob);
6868

69+
JITResult compileSYCL(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
70+
View<const char *> UserArgs);
71+
6972
/// Clear all previously set options.
7073
void resetJITConfiguration();
7174

sycl-jit/jit-compiler/ld-version-script.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/* Export the library entry points */
44
fuseKernels;
55
materializeSpecConstants;
6+
compileSYCL;
67
resetJITConfiguration;
78
addToJITConfiguration;
89

sycl-jit/jit-compiler/lib/KernelFusion.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "fusion/FusionPipeline.h"
1515
#include "helper/ConfigHelper.h"
1616
#include "helper/ErrorHandling.h"
17+
#include "rtc/DeviceCompilation.h"
1718
#include "translation/KernelTranslation.h"
1819
#include "translation/SPIRVLLVMTranslation.h"
1920
#include <llvm/Support/Error.h>
@@ -235,6 +236,31 @@ extern "C" JITResult fuseKernels(View<SYCLKernelInfo> KernelInformation,
235236
return JITResult{FusedKernelInfo};
236237
}
237238

239+
extern "C" JITResult compileSYCL(InMemoryFile SourceFile,
240+
View<InMemoryFile> IncludeFiles,
241+
View<const char *> UserArgs) {
242+
auto ModuleOrErr = compileDeviceCode(SourceFile, IncludeFiles, UserArgs);
243+
if (!ModuleOrErr) {
244+
return errorToFusionResult(ModuleOrErr.takeError(),
245+
"Device compilation failed");
246+
}
247+
std::unique_ptr<llvm::Module> Module = std::move(*ModuleOrErr);
248+
249+
SYCLKernelInfo Kernel;
250+
auto Error = translation::KernelTranslator::translateKernel(
251+
Kernel, *Module, JITContext::getInstance(), BinaryFormat::SPIRV);
252+
253+
auto *LLVMCtx = &Module->getContext();
254+
Module.reset();
255+
delete LLVMCtx;
256+
257+
if (Error) {
258+
return errorToFusionResult(std::move(Error), "SPIR-V translation failed");
259+
}
260+
261+
return JITResult{Kernel};
262+
}
263+
238264
extern "C" void resetJITConfiguration() { ConfigHelper::reset(); }
239265

240266
extern "C" void addToJITConfiguration(OptionStorage &&Opt) {
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//==---------------------- DeviceCompilation.cpp ---------------------------==//
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+
#include "DeviceCompilation.h"
10+
11+
#include <clang/Basic/Version.h>
12+
#include <clang/CodeGen/CodeGenAction.h>
13+
#include <clang/Driver/Compilation.h>
14+
#include <clang/Frontend/CompilerInstance.h>
15+
#include <clang/Tooling/CompilationDatabase.h>
16+
#include <clang/Tooling/Tooling.h>
17+
18+
#ifdef _GNU_SOURCE
19+
#include <dlfcn.h>
20+
static char X; // Dummy symbol, used as an anchor for `dlinfo` below.
21+
#endif
22+
23+
static constexpr auto InvalidDPCPPRoot = "<invalid>";
24+
static constexpr auto JITLibraryPathSuffix = "/lib/libsycl-jit.so";
25+
26+
static const std::string &getDPCPPRoot() {
27+
thread_local std::string DPCPPRoot;
28+
29+
if (!DPCPPRoot.empty()) {
30+
return DPCPPRoot;
31+
}
32+
DPCPPRoot = InvalidDPCPPRoot;
33+
34+
#ifdef _GNU_SOURCE
35+
Dl_info Info;
36+
if (dladdr(&X, &Info)) {
37+
std::string LoadedLibraryPath = Info.dli_fname;
38+
auto Pos = LoadedLibraryPath.rfind(JITLibraryPathSuffix);
39+
if (Pos != std::string::npos) {
40+
DPCPPRoot = LoadedLibraryPath.substr(0, Pos);
41+
}
42+
}
43+
#endif // _GNU_SOURCE
44+
45+
// TODO: Implemenent other means of determining the DPCPP root, e.g.
46+
// evaluating the `CMPLR_ROOT` env.
47+
48+
return DPCPPRoot;
49+
}
50+
51+
namespace {
52+
using namespace clang;
53+
using namespace clang::tooling;
54+
using namespace clang::driver;
55+
56+
struct GetLLVMModuleAction : public ToolAction {
57+
// Code adapted from `FrontendActionFactory::runInvocation`.
58+
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
59+
FileManager *Files,
60+
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
61+
DiagnosticConsumer *DiagConsumer) override {
62+
assert(!Module && "Action should only be invoked on a single file");
63+
64+
// Create a compiler instance to handle the actual work.
65+
CompilerInstance Compiler(std::move(PCHContainerOps));
66+
Compiler.setInvocation(std::move(Invocation));
67+
Compiler.setFileManager(Files);
68+
69+
// Create the compiler's actual diagnostics engine.
70+
Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
71+
if (!Compiler.hasDiagnostics()) {
72+
return false;
73+
}
74+
75+
Compiler.createSourceManager(*Files);
76+
77+
// Ignore `Compiler.getFrontendOpts().ProgramAction` (would be `EmitBC`) and
78+
// create/execute an `EmitLLVMOnlyAction` (= codegen to LLVM module without
79+
// emitting anything) instead.
80+
EmitLLVMOnlyAction ELOA;
81+
const bool Success = Compiler.ExecuteAction(ELOA);
82+
Files->clearStatCache();
83+
if (!Success) {
84+
return false;
85+
}
86+
87+
// Take the module and its context to extend the objects' lifetime.
88+
Module = ELOA.takeModule();
89+
ELOA.takeLLVMContext();
90+
91+
return true;
92+
}
93+
94+
std::unique_ptr<llvm::Module> Module;
95+
};
96+
97+
} // anonymous namespace
98+
99+
llvm::Expected<std::unique_ptr<llvm::Module>>
100+
jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
101+
View<InMemoryFile> IncludeFiles,
102+
View<const char *> UserArgs) {
103+
const std::string &DPCPPRoot = getDPCPPRoot();
104+
if (DPCPPRoot == InvalidDPCPPRoot) {
105+
return llvm::createStringError("Could not locate DPCPP root directory");
106+
}
107+
108+
SmallVector<std::string> CommandLine = {"-fsycl-device-only"};
109+
// TODO: Allow instrumentation again when device library linking is
110+
// implemented.
111+
CommandLine.push_back("-fno-sycl-instrument-device-code");
112+
CommandLine.append(UserArgs.begin(), UserArgs.end());
113+
clang::tooling::FixedCompilationDatabase DB{".", CommandLine};
114+
115+
clang::tooling::ClangTool Tool{DB, {SourceFile.Path}};
116+
117+
// Set up in-memory filesystem.
118+
Tool.mapVirtualFile(SourceFile.Path, SourceFile.Contents);
119+
for (const auto &IF : IncludeFiles) {
120+
Tool.mapVirtualFile(IF.Path, IF.Contents);
121+
}
122+
123+
// Reset argument adjusters to drop the `-fsyntax-only` flag which is added by
124+
// default by this API.
125+
Tool.clearArgumentsAdjusters();
126+
// Then, modify argv[0] and set the resource directory so that the driver
127+
// picks up the correct SYCL environment.
128+
Tool.appendArgumentsAdjuster(
129+
[&DPCPPRoot](const CommandLineArguments &Args,
130+
StringRef Filename) -> CommandLineArguments {
131+
(void)Filename;
132+
CommandLineArguments NewArgs = Args;
133+
NewArgs[0] = (Twine(DPCPPRoot) + "/bin/clang++").str();
134+
NewArgs.push_back((Twine("-resource-dir=") + DPCPPRoot + "/lib/clang/" +
135+
Twine(CLANG_VERSION_MAJOR))
136+
.str());
137+
return NewArgs;
138+
});
139+
140+
GetLLVMModuleAction Action;
141+
if (!Tool.run(&Action)) {
142+
return std::move(Action.Module);
143+
}
144+
145+
// TODO: Capture compiler errors from the ClangTool.
146+
return llvm::createStringError("Unable to obtain LLVM module");
147+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//==---- DeviceCompilation.h - Compile SYCL device code with libtooling ----==//
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_JIT_COMPILER_RTC_DEVICE_COMPILATION_H
10+
#define SYCL_JIT_COMPILER_RTC_DEVICE_COMPILATION_H
11+
12+
#include "Kernel.h"
13+
#include "View.h"
14+
15+
#include <llvm/IR/Module.h>
16+
#include <llvm/Support/Error.h>
17+
18+
#include <memory>
19+
20+
namespace jit_compiler {
21+
22+
llvm::Expected<std::unique_ptr<llvm::Module>>
23+
compileDeviceCode(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
24+
View<const char *> UserArgs);
25+
26+
} // namespace jit_compiler
27+
28+
#endif // SYCL_JIT_COMPILER_RTC_DEVICE_COMPILATION_H

sycl-jit/jit-compiler/lib/translation/SPIRVLLVMTranslation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ SPIRV::TranslatorOpts &SPIRVLLVMTranslator::translatorOpts() {
4141
// there's currently no obvious way to iterate the
4242
// array of extensions in KernelInfo.
4343
TransOpt.enableAllExtensions();
44+
// TODO: Remove this workaround.
45+
TransOpt.setAllowedToUseExtension(
46+
SPIRV::ExtensionID::SPV_KHR_untyped_pointers, false);
4447
TransOpt.setDesiredBIsRepresentation(
4548
SPIRV::BIsRepresentation::SPIRVFriendlyIR);
4649
// TODO: We need to take care of specialization constants, either by

sycl/include/sycl/kernel_bundle_enums.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ enum class bundle_state : char {
2020

2121
namespace ext::oneapi::experimental {
2222

23-
enum class source_language : int { opencl = 0, spirv = 1, sycl = 2 /* cuda */ };
23+
enum class source_language : int {
24+
opencl = 0,
25+
spirv = 1,
26+
sycl = 2,
27+
/* cuda */
28+
sycl_jit = 99 /* temporary, alternative implementation for SYCL */
29+
};
2430

2531
// opencl versions
2632
struct cl_version {

sycl/source/detail/jit_compiler.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ jit_compiler::jit_compiler() {
7474
return false;
7575
}
7676

77+
this->CompileSYCLHandle = reinterpret_cast<CompileSYCLFuncT>(
78+
sycl::detail::ur::getOsLibraryFuncAddress(LibraryPtr, "compileSYCL"));
79+
if (!this->CompileSYCLHandle) {
80+
printPerformanceWarning(
81+
"Cannot resolve JIT library function entry point");
82+
return false;
83+
}
84+
7785
return true;
7886
};
7987
Available = checkJITLibrary();
@@ -1145,6 +1153,52 @@ std::vector<uint8_t> jit_compiler::encodeReqdWorkGroupSize(
11451153
return Encoded;
11461154
}
11471155

1156+
std::vector<uint8_t> jit_compiler::compileSYCL(
1157+
const std::string &Id, const std::string &SYCLSource,
1158+
const std::vector<std::pair<std::string, std::string>> &IncludePairs,
1159+
const std::vector<std::string> &UserArgs, std::string *LogPtr,
1160+
const std::vector<std::string> &RegisteredKernelNames) {
1161+
1162+
// TODO: Handle template instantiation.
1163+
if (!RegisteredKernelNames.empty()) {
1164+
throw sycl::exception(
1165+
sycl::errc::build,
1166+
"Property `sycl::ext::oneapi::experimental::registered_kernel_names` "
1167+
"is not yet supported for the `sycl_jit` source language");
1168+
}
1169+
1170+
std::string SYCLFileName = Id + ".cpp";
1171+
::jit_compiler::InMemoryFile SourceFile{SYCLFileName.c_str(),
1172+
SYCLSource.c_str()};
1173+
1174+
std::vector<::jit_compiler::InMemoryFile> IncludeFilesView;
1175+
IncludeFilesView.reserve(IncludePairs.size());
1176+
std::transform(IncludePairs.begin(), IncludePairs.end(),
1177+
std::back_inserter(IncludeFilesView), [](const auto &Pair) {
1178+
return ::jit_compiler::InMemoryFile{Pair.first.c_str(),
1179+
Pair.second.c_str()};
1180+
});
1181+
std::vector<const char *> UserArgsView;
1182+
UserArgsView.reserve(UserArgs.size());
1183+
std::transform(UserArgs.begin(), UserArgs.end(),
1184+
std::back_inserter(UserArgsView),
1185+
[](const auto &Arg) { return Arg.c_str(); });
1186+
1187+
auto Result = CompileSYCLHandle(SourceFile, IncludeFilesView, UserArgsView);
1188+
1189+
if (Result.failed()) {
1190+
throw sycl::exception(sycl::errc::build, Result.getErrorMessage());
1191+
}
1192+
1193+
// TODO: We currently don't have a meaningful build log.
1194+
(void)LogPtr;
1195+
1196+
const auto &BI = Result.getKernelInfo().BinaryInfo;
1197+
assert(BI.Format == ::jit_compiler::BinaryFormat::SPIRV);
1198+
std::vector<uint8_t> SPV(BI.BinaryStart, BI.BinaryStart + BI.BinarySize);
1199+
return SPV;
1200+
}
1201+
11481202
} // namespace detail
11491203
} // namespace _V1
11501204
} // namespace sycl

0 commit comments

Comments
 (0)