Skip to content

Commit 482c07e

Browse files
committed
[SYCL][RTC] Error message and build log for JIT RTC
Signed-off-by: Lukas Sommer <[email protected]>
1 parent 34554e6 commit 482c07e

File tree

6 files changed

+194
-45
lines changed

6 files changed

+194
-45
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ class RTCResult {
6161
explicit RTCResult(const char *ErrorMessage)
6262
: Failed{true}, BundleInfo{}, ErrorMessage{ErrorMessage} {}
6363

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

6768
bool failed() const { return Failed; }
6869

6970
const char *getErrorMessage() const {
70-
assert(failed() && "No error message present");
7171
return ErrorMessage.c_str();
7272
}
7373

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: 88 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,56 @@ 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+
185+
LogPrinter = std::make_unique<TextDiagnosticPrinter>(LogStream, DiagOpts);
186+
}
187+
188+
clang::TextDiagnosticPrinter *consumer() { return LogPrinter.get(); }
189+
190+
llvm::raw_ostream &stream() { return LogStream; }
191+
};
192+
193+
class LLVMDiagnosticWrapper : public llvm::DiagnosticHandler {
194+
llvm::raw_string_ostream LogStream;
195+
196+
DiagnosticPrinterRawOStream LogPrinter;
197+
198+
public:
199+
LLVMDiagnosticWrapper(std::string &BuildLog)
200+
: LogStream(BuildLog), LogPrinter(LogStream) {}
201+
202+
bool handleDiagnostics(const DiagnosticInfo &DI) override {
203+
auto Prefix = [](DiagnosticSeverity Severity) -> llvm::StringLiteral {
204+
switch (Severity) {
205+
case llvm::DiagnosticSeverity::DS_Error:
206+
return "ERROR";
207+
case llvm::DiagnosticSeverity::DS_Warning:
208+
return "WARNING";
209+
default:
210+
return "NOTE:";
211+
}
212+
}(DI.getSeverity());
213+
LogPrinter << Prefix;
214+
DI.print(LogPrinter);
215+
LogPrinter << "\n";
216+
return true;
217+
}
218+
};
219+
164220
} // anonymous namespace
165221

166-
Expected<std::unique_ptr<llvm::Module>>
167-
jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
168-
View<InMemoryFile> IncludeFiles,
169-
const InputArgList &UserArgList) {
222+
Expected<std::unique_ptr<llvm::Module>> jit_compiler::compileDeviceCode(
223+
InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
224+
const InputArgList &UserArgList, std::string &BuildLog) {
170225
const std::string &DPCPPRoot = getDPCPPRoot();
171226
if (DPCPPRoot == InvalidDPCPPRoot) {
172227
return createStringError("Could not locate DPCPP root directory");
@@ -197,12 +252,19 @@ jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
197252
FixedCompilationDatabase DB{".", CommandLine};
198253
ClangTool Tool{DB, {SourceFile.Path}};
199254

255+
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{new DiagnosticOptions};
256+
ClangDiagnosticWrapper Wrapper(BuildLog, DiagOpts.get());
257+
Tool.setDiagnosticConsumer(Wrapper.consumer());
258+
200259
// Set up in-memory filesystem.
201260
Tool.mapVirtualFile(SourceFile.Path, SourceFile.Contents);
202261
for (const auto &IF : IncludeFiles) {
203262
Tool.mapVirtualFile(IF.Path, IF.Contents);
204263
}
205264

265+
// Suppress message "Error while processing" being printed to stdout.
266+
Tool.setPrintErrorMessage(false);
267+
206268
// Reset argument adjusters to drop the `-fsyntax-only` flag which is added by
207269
// default by this API.
208270
Tool.clearArgumentsAdjusters();
@@ -222,15 +284,15 @@ jit_compiler::compileDeviceCode(InMemoryFile SourceFile,
222284
return std::move(Action.Module);
223285
}
224286

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

229290
// This function is a simplified copy of the device library selection process in
230291
// `clang::driver::tools::SYCL::getDeviceLibraries`, assuming a SPIR-V target
231292
// (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) {
293+
static bool getDeviceLibraries(const ArgList &Args,
294+
SmallVectorImpl<std::string> &LibraryList,
295+
DiagnosticsEngine &Diags) {
234296
struct DeviceLibOptInfo {
235297
StringRef DeviceLibName;
236298
StringRef DeviceLibOption;
@@ -247,6 +309,8 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
247309
// libraries cannot be affected via -fno-sycl-device-lib.
248310
bool ExcludeDeviceLibs = false;
249311

312+
bool FoundUnknownLib = false;
313+
250314
if (Arg *A = Args.getLastArg(OPT_fsycl_device_lib_EQ,
251315
OPT_fno_sycl_device_lib_EQ)) {
252316
if (A->getValues().size() == 0) {
@@ -268,6 +332,7 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
268332
if (LinkInfoIter == DeviceLibLinkInfo.end() || Val == "internal") {
269333
Diags.Report(diag::err_drv_unsupported_option_argument)
270334
<< A->getSpelling() << Val;
335+
FoundUnknownLib = true;
271336
}
272337
DeviceLibLinkInfo[Val] = !ExcludeDeviceLibs;
273338
}
@@ -292,7 +357,6 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
292357
{"libsycl-itt-compiler-wrappers", "internal"},
293358
{"libsycl-itt-stubs", "internal"}};
294359

295-
SmallVector<std::string, 8> LibraryList;
296360
StringRef LibSuffix = ".bc";
297361
auto AddLibraries = [&](const SYCLDeviceLibsList &LibsList) {
298362
for (const DeviceLibOptInfo &Lib : LibsList) {
@@ -312,37 +376,33 @@ getDeviceLibraries(const ArgList &Args, DiagnosticsEngine &Diags) {
312376
AddLibraries(SYCLDeviceAnnotationLibs);
313377
}
314378

315-
return LibraryList;
379+
return FoundUnknownLib;
316380
}
317381

318382
Error jit_compiler::linkDeviceLibraries(llvm::Module &Module,
319-
const InputArgList &UserArgList) {
383+
const InputArgList &UserArgList,
384+
std::string &BuildLog) {
320385
const std::string &DPCPPRoot = getDPCPPRoot();
321386
if (DPCPPRoot == InvalidDPCPPRoot) {
322387
return createStringError("Could not locate DPCPP root directory");
323388
}
324389

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.
328390
IntrusiveRefCntPtr<DiagnosticIDs> DiagID{new DiagnosticIDs};
329391
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'; });
392+
ClangDiagnosticWrapper Wrapper(BuildLog, DiagOpts.get());
393+
DiagnosticsEngine Diags(DiagID, DiagOpts, Wrapper.consumer(),
394+
/* ShouldOwnClient=*/false);
395+
396+
SmallVector<std::string> LibNames;
397+
bool FoundUnknownLib = getDeviceLibraries(UserArgList, LibNames, Diags);
398+
if (FoundUnknownLib) {
340399
return createStringError("Could not determine list of device libraries: %s",
341-
DiagMsg.c_str());
400+
BuildLog.c_str());
342401
}
343-
// TODO: Add warnings to build log.
344402

345403
LLVMContext &Context = Module.getContext();
404+
Context.setDiagnosticHandler(
405+
std::make_unique<LLVMDiagnosticWrapper>(BuildLog));
346406
for (const std::string &LibName : LibNames) {
347407
std::string LibPath = DPCPPRoot + "/lib/" + LibName;
348408

@@ -356,10 +416,8 @@ Error jit_compiler::linkDeviceLibraries(llvm::Module &Module,
356416
}
357417

358418
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());
419+
return createStringError("Unable to link device library %s: %s",
420+
LibPath.c_str(), BuildLog.c_str());
363421
}
364422
}
365423

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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,13 +1242,14 @@ sycl_device_binaries jit_compiler::compileSYCL(
12421242

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

1245+
if (LogPtr) {
1246+
LogPtr->append(Result.getErrorMessage());
1247+
}
1248+
12451249
if (Result.failed()) {
12461250
throw sycl::exception(sycl::errc::build, Result.getErrorMessage());
12471251
}
12481252

1249-
// TODO: We currently don't have a meaningful build log.
1250-
(void)LogPtr;
1251-
12521253
return createDeviceBinaryImage(Result.getBundleInfo());
12531254
}
12541255

0 commit comments

Comments
 (0)