Skip to content

Commit c6ce623

Browse files
authored
[SYCL][RTC] Add support for errors and build log in JIT-based RTC (#16132)
Adds support for correct error message routing and the `save_log` property to the SYCL-RTC implementation based on the SYCL-JIT library. If the compilation fails, any diagnostic messages encountered during runtime compilation are stored in the `what` of the exception thrown. If the user passes the `save_log` property defined in the `kernel_compiler` extension, all diagnostics encountered during compilation (errors, warnings, notes and remarks) are stored in the user-provided string. --------- Signed-off-by: Lukas Sommer <[email protected]>
1 parent b437fa4 commit c6ce623

File tree

6 files changed

+200
-52
lines changed

6 files changed

+200
-52
lines changed

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,15 @@ class JITResult {
5858

5959
class RTCResult {
6060
public:
61-
explicit RTCResult(const char *ErrorMessage)
62-
: Failed{true}, BundleInfo{}, ErrorMessage{ErrorMessage} {}
61+
explicit RTCResult(const char *BuildLog)
62+
: Failed{true}, BundleInfo{}, BuildLog{BuildLog} {}
6363

64-
explicit RTCResult(RTCBundleInfo &&BundleInfo)
65-
: Failed{false}, BundleInfo{std::move(BundleInfo)}, ErrorMessage{} {}
64+
RTCResult(RTCBundleInfo &&BundleInfo, const char *BuildLog)
65+
: Failed{false}, BundleInfo{std::move(BundleInfo)}, BuildLog{BuildLog} {}
6666

6767
bool failed() const { return Failed; }
6868

69-
const char *getErrorMessage() const {
70-
assert(failed() && "No error message present");
71-
return ErrorMessage.c_str();
72-
}
69+
const char *getBuildLog() const { return BuildLog.c_str(); }
7370

7471
const RTCBundleInfo &getBundleInfo() const {
7572
assert(!failed() && "No bundle info");
@@ -79,7 +76,7 @@ class RTCResult {
7976
private:
8077
bool Failed;
8178
RTCBundleInfo BundleInfo;
82-
sycl::detail::string ErrorMessage;
79+
sycl::detail::string BuildLog;
8380
};
8481

8582
extern "C" {

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,10 @@ compileSYCL(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
244244
}
245245
llvm::opt::InputArgList UserArgList = std::move(*UserArgListOrErr);
246246

247-
auto ModuleOrErr = compileDeviceCode(SourceFile, IncludeFiles, UserArgList);
247+
std::string BuildLog;
248+
249+
auto ModuleOrErr =
250+
compileDeviceCode(SourceFile, IncludeFiles, UserArgList, BuildLog);
248251
if (!ModuleOrErr) {
249252
return errorTo<RTCResult>(ModuleOrErr.takeError(),
250253
"Device compilation failed");
@@ -254,7 +257,7 @@ compileSYCL(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
254257
std::unique_ptr<llvm::Module> Module = std::move(*ModuleOrErr);
255258
Context.reset(&Module->getContext());
256259

257-
if (auto Error = linkDeviceLibraries(*Module, UserArgList)) {
260+
if (auto Error = linkDeviceLibraries(*Module, UserArgList, BuildLog)) {
258261
return errorTo<RTCResult>(std::move(Error), "Device linking failed");
259262
}
260263

@@ -274,7 +277,7 @@ compileSYCL(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
274277
}
275278
BundleInfo.BinaryInfo = std::move(*BinaryInfoOrError);
276279

277-
return RTCResult{std::move(BundleInfo)};
280+
return RTCResult{std::move(BundleInfo), BuildLog.c_str()};
278281
}
279282

280283
extern "C" KF_EXPORT_SYMBOL void resetJITConfiguration() {

sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
#include <clang/CodeGen/CodeGenAction.h>
1414
#include <clang/Driver/Compilation.h>
1515
#include <clang/Driver/Options.h>
16+
#include <clang/Frontend/ChainedDiagnosticConsumer.h>
1617
#include <clang/Frontend/CompilerInstance.h>
1718
#include <clang/Frontend/TextDiagnosticBuffer.h>
19+
#include <clang/Frontend/TextDiagnosticPrinter.h>
1820
#include <clang/Tooling/CompilationDatabase.h>
1921
#include <clang/Tooling/Tooling.h>
2022

23+
#include <llvm/IR/DiagnosticInfo.h>
24+
#include <llvm/IR/DiagnosticPrinter.h>
2125
#include <llvm/IR/PassInstrumentation.h>
2226
#include <llvm/IR/PassManager.h>
2327
#include <llvm/IRReader/IRReader.h>
@@ -27,6 +31,10 @@
2731
#include <llvm/SYCLLowerIR/SYCLJointMatrixTransform.h>
2832
#include <llvm/Support/PropertySetIO.h>
2933

34+
#include <algorithm>
35+
#include <array>
36+
#include <sstream>
37+
3038
using namespace clang;
3139
using namespace clang::tooling;
3240
using namespace clang::driver;
@@ -132,6 +140,9 @@ struct GetLLVMModuleAction : public ToolAction {
132140
CompilerInstance Compiler(std::move(PCHContainerOps));
133141
Compiler.setInvocation(std::move(Invocation));
134142
Compiler.setFileManager(Files);
143+
// Suppress summary with number of warnings and errors being printed to
144+
// stdout.
145+
Compiler.setVerboseOutputStream(std::make_unique<llvm::raw_null_ostream>());
135146

136147
// Create the compiler's actual diagnostics engine.
137148
Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
@@ -161,12 +172,59 @@ struct GetLLVMModuleAction : public ToolAction {
161172
std::unique_ptr<llvm::Module> Module;
162173
};
163174

175+
class ClangDiagnosticWrapper {
176+
177+
llvm::raw_string_ostream LogStream;
178+
179+
std::unique_ptr<clang::TextDiagnosticPrinter> LogPrinter;
180+
181+
public:
182+
ClangDiagnosticWrapper(std::string &LogString, DiagnosticOptions *DiagOpts)
183+
: LogStream(LogString),
184+
LogPrinter(
185+
std::make_unique<TextDiagnosticPrinter>(LogStream, DiagOpts)) {}
186+
187+
clang::TextDiagnosticPrinter *consumer() { return LogPrinter.get(); }
188+
189+
llvm::raw_ostream &stream() { return LogStream; }
190+
};
191+
192+
class LLVMDiagnosticWrapper : public llvm::DiagnosticHandler {
193+
llvm::raw_string_ostream LogStream;
194+
195+
DiagnosticPrinterRawOStream LogPrinter;
196+
197+
public:
198+
LLVMDiagnosticWrapper(std::string &BuildLog)
199+
: LogStream(BuildLog), LogPrinter(LogStream) {}
200+
201+
bool handleDiagnostics(const DiagnosticInfo &DI) override {
202+
auto Prefix = [](DiagnosticSeverity Severity) -> llvm::StringLiteral {
203+
switch (Severity) {
204+
case llvm::DiagnosticSeverity::DS_Error:
205+
return "ERROR";
206+
case llvm::DiagnosticSeverity::DS_Warning:
207+
return "WARNING";
208+
case llvm::DiagnosticSeverity::DS_Note:
209+
return "NOTE:";
210+
case llvm::DiagnosticSeverity::DS_Remark:
211+
return "REMARK:";
212+
default:
213+
llvm_unreachable("Unhandled case");
214+
}
215+
}(DI.getSeverity());
216+
LogPrinter << Prefix;
217+
DI.print(LogPrinter);
218+
LogPrinter << "\n";
219+
return true;
220+
}
221+
};
222+
164223
} // anonymous namespace
165224

166-
Expected<std::unique_ptr<llvm::Module>>
167-
jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
168-
View<InMemoryFile> IncludeFiles,
169-
const InputArgList &UserArgList) {
225+
Expected<std::unique_ptr<llvm::Module>> jit_compiler::compileDeviceCode(
226+
InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
227+
const InputArgList &UserArgList, std::string &BuildLog) {
170228
const std::string &DPCPPRoot = getDPCPPRoot();
171229
if (DPCPPRoot == InvalidDPCPPRoot) {
172230
return createStringError("Could not locate DPCPP root directory");
@@ -197,6 +255,12 @@ jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
197255
FixedCompilationDatabase DB{".", CommandLine};
198256
ClangTool Tool{DB, {SourceFile.Path}};
199257

258+
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{new DiagnosticOptions};
259+
ClangDiagnosticWrapper Wrapper(BuildLog, DiagOpts.get());
260+
Tool.setDiagnosticConsumer(Wrapper.consumer());
261+
// Suppress message "Error while processing" being printed to stdout.
262+
Tool.setPrintErrorMessage(false);
263+
200264
// Set up in-memory filesystem.
201265
Tool.mapVirtualFile(SourceFile.Path, SourceFile.Contents);
202266
for (const auto &IF : IncludeFiles) {
@@ -222,15 +286,15 @@ jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
222286
return std::move(Action.Module);
223287
}
224288

225-
// TODO: Capture compiler errors from the ClangTool.
226-
return createStringError("Unable to obtain LLVM module");
289+
return createStringError(BuildLog);
227290
}
228291

229292
// This function is a simplified copy of the device library selection process in
230293
// `clang::driver::tools::SYCL::getDeviceLibraries`, assuming a SPIR-V target
231294
// (no AoT, no third-party GPUs, no native CPU). Keep in sync!
232-
static SmallVector<std::string, 8>
233-
getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
295+
static bool getDeviceLibraries(const ArgList &Args,
296+
SmallVectorImpl<std::string> &LibraryList,
297+
DiagnosticsEngine &Diags) {
234298
struct DeviceLibOptInfo {
235299
StringRef DeviceLibName;
236300
StringRef DeviceLibOption;
@@ -247,6 +311,8 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
247311
// libraries cannot be affected via -fno-sycl-device-lib.
248312
bool ExcludeDeviceLibs = false;
249313

314+
bool FoundUnknownLib = false;
315+
250316
if (Arg *A = Args.getLastArg(OPT_fsycl_device_lib_EQ,
251317
OPT_fno_sycl_device_lib_EQ)) {
252318
if (A->getValues().size() == 0) {
@@ -268,6 +334,7 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
268334
if (LinkInfoIter == DeviceLibLinkInfo.end() || Val == "internal") {
269335
Diags.Report(diag::err_drv_unsupported_option_argument)
270336
<< A->getSpelling() << Val;
337+
FoundUnknownLib = true;
271338
}
272339
DeviceLibLinkInfo[Val] = !ExcludeDeviceLibs;
273340
}
@@ -292,7 +359,6 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
292359
{"libsycl-itt-compiler-wrappers", "internal"},
293360
{"libsycl-itt-stubs", "internal"}};
294361

295-
SmallVector<std::string, 8> LibraryList;
296362
StringRef LibSuffix = ".bc";
297363
auto AddLibraries = [&](const SYCLDeviceLibsList &LibsList) {
298364
for (const DeviceLibOptInfo &Lib : LibsList) {
@@ -312,37 +378,33 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
312378
AddLibraries(SYCLDeviceAnnotationLibs);
313379
}
314380

315-
return LibraryList;
381+
return FoundUnknownLib;
316382
}
317383

318384
Error jit_compiler::linkDeviceLibraries(llvm::Module &Module,
319-
const InputArgList &UserArgList) {
385+
const InputArgList &UserArgList,
386+
std::string &BuildLog) {
320387
const std::string &DPCPPRoot = getDPCPPRoot();
321388
if (DPCPPRoot == InvalidDPCPPRoot) {
322389
return createStringError("Could not locate DPCPP root directory");
323390
}
324391

325-
// TODO: Seems a bit excessive to set up this machinery for one warning and
326-
// one error. Rethink when implementing the build log/error reporting as
327-
// mandated by the extension.
328392
IntrusiveRefCntPtr<DiagnosticIDs> DiagID{new DiagnosticIDs};
329393
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{new DiagnosticOptions};
330-
TextDiagnosticBuffer *DiagBuffer = new TextDiagnosticBuffer;
331-
DiagnosticsEngine Diags(DiagID, DiagOpts, DiagBuffer);
332-
333-
auto LibNames = getDeviceLibraries(UserArgList, Diags);
334-
if (std::distance(DiagBuffer->err_begin(), DiagBuffer->err_end()) > 0) {
335-
std::string DiagMsg;
336-
raw_string_ostream SOS{DiagMsg};
337-
interleave(
338-
DiagBuffer->err_begin(), DiagBuffer->err_end(),
339-
[&](const auto &D) { SOS << D.second; }, [&]() { SOS << '\n'; });
394+
ClangDiagnosticWrapper Wrapper(BuildLog, DiagOpts.get());
395+
DiagnosticsEngine Diags(DiagID, DiagOpts, Wrapper.consumer(),
396+
/* ShouldOwnClient=*/false);
397+
398+
SmallVector<std::string> LibNames;
399+
bool FoundUnknownLib = getDeviceLibraries(UserArgList, LibNames, Diags);
400+
if (FoundUnknownLib) {
340401
return createStringError("Could not determine list of device libraries: %s",
341-
DiagMsg.c_str());
402+
BuildLog.c_str());
342403
}
343-
// TODO: Add warnings to build log.
344404

345405
LLVMContext &Context = Module.getContext();
406+
Context.setDiagnosticHandler(
407+
std::make_unique<LLVMDiagnosticWrapper>(BuildLog));
346408
for (const std::string &LibName : LibNames) {
347409
std::string LibPath = DPCPPRoot + "/lib/" + LibName;
348410

@@ -356,10 +418,8 @@ Error jit_compiler::linkDeviceLibraries(llvm::Module &Module,
356418
}
357419

358420
if (Linker::linkModules(Module, std::move(Lib), Linker::LinkOnlyNeeded)) {
359-
// TODO: Obtain detailed error message from the context's diagnostics
360-
// handler.
361-
return createStringError("Unable to link device library: %s",
362-
LibPath.c_str());
421+
return createStringError("Unable to link device library %s: %s",
422+
LibPath.c_str(), BuildLog.c_str());
363423
}
364424
}
365425

sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,18 @@
1717
#include <llvm/Support/Error.h>
1818

1919
#include <memory>
20+
#include <string>
2021

2122
namespace jit_compiler {
2223

2324
llvm::Expected<std::unique_ptr<llvm::Module>>
2425
compileDeviceCode(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
25-
const llvm::opt::InputArgList &UserArgList);
26+
const llvm::opt::InputArgList &UserArgList,
27+
std::string &BuildLog);
2628

2729
llvm::Error linkDeviceLibraries(llvm::Module &Module,
28-
const llvm::opt::InputArgList &UserArgList);
30+
const llvm::opt::InputArgList &UserArgList,
31+
std::string &BuildLog);
2932

3033
llvm::Expected<RTCBundleInfo>
3134
performPostLink(llvm::Module &Module,

sycl/source/detail/jit_compiler.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,12 +1242,13 @@ sycl_device_binaries jit_compiler::compileSYCL(
12421242

12431243
auto Result = CompileSYCLHandle(SourceFile, IncludeFilesView, UserArgsView);
12441244

1245-
if (Result.failed()) {
1246-
throw sycl::exception(sycl::errc::build, Result.getErrorMessage());
1245+
if (LogPtr) {
1246+
LogPtr->append(Result.getBuildLog());
12471247
}
12481248

1249-
// TODO: We currently don't have a meaningful build log.
1250-
(void)LogPtr;
1249+
if (Result.failed()) {
1250+
throw sycl::exception(sycl::errc::build, Result.getBuildLog());
1251+
}
12511252

12521253
return createDeviceBinaryImage(Result.getBundleInfo());
12531254
}

0 commit comments

Comments
 (0)