Skip to content

Commit 3aec7c2

Browse files
committed
[Offload] Ensure all llvm::Errors are handled
`llvm::Error`s containing errors must be explicitly handled or an assert will be raised. With this change, `ol_impl_result_t` can accept and consume an `llvm::Error` for errors raised by PluginInterface that have multiple causes and other places now call `llvm::consumeError`. Note that there is currently no facility for PluginInterface to communicate exact error codes, but the constructor is designed in such a way that it can be easily added later. This MR is to convert a crash into an error code. A new test was added, however due to the aforementioned issue with error codes, it does not pass and instead is disabled.
1 parent 724eea7 commit 3aec7c2

File tree

3 files changed

+53
-13
lines changed

3 files changed

+53
-13
lines changed

offload/liboffload/include/OffloadImpl.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/DenseSet.h"
2020
#include "llvm/ADT/StringRef.h"
2121
#include "llvm/ADT/StringSet.h"
22+
#include "llvm/Support/Error.h"
2223

2324
struct OffloadConfig {
2425
bool TracingEnabled = false;
@@ -88,6 +89,18 @@ struct ol_impl_result_t {
8889
Result = errors().emplace(std::move(Err)).first->get();
8990
}
9091

92+
static ol_impl_result_t fromError(llvm::Error &&Error,
93+
llvm::StringRef Details) {
94+
ol_errc_t ErrCode;
95+
llvm::handleAllErrors(std::move(Error), [&](llvm::StringError &Err) {
96+
// TODO: PluginInterface doesn't yet have a way to communicate offload
97+
// error codes
98+
ErrCode = OL_ERRC_UNKNOWN;
99+
});
100+
101+
return ol_impl_result_t{ErrCode, Details};
102+
}
103+
91104
operator ol_result_t() { return Result; }
92105

93106
private:

offload/liboffload/src/OffloadImpl.cpp

+33-13
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,11 @@ ol_impl_result_t olMemAlloc_impl(ol_device_handle_t Device,
310310
void **AllocationOut) {
311311
auto Alloc =
312312
Device->Device->dataAlloc(Size, nullptr, convertOlToPluginAllocTy(Type));
313-
if (!Alloc)
313+
if (!Alloc) {
314+
llvm::consumeError(Alloc.takeError());
314315
return {OL_ERRC_OUT_OF_RESOURCES,
315316
formatv("Could not create allocation on device {0}", Device).str()};
317+
}
316318

317319
*AllocationOut = *Alloc;
318320
allocInfoMap().insert_or_assign(*Alloc, AllocInfo{Device, Type});
@@ -329,8 +331,10 @@ ol_impl_result_t olMemFree_impl(void *Address) {
329331

330332
auto Res =
331333
Device->Device->dataDelete(Address, convertOlToPluginAllocTy(Type));
332-
if (Res)
334+
if (Res) {
335+
llvm::consumeError(std::move(Res));
333336
return {OL_ERRC_OUT_OF_RESOURCES, "Could not free allocation"};
337+
}
334338

335339
allocInfoMap().erase(Address);
336340

@@ -342,7 +346,8 @@ ol_impl_result_t olCreateQueue_impl(ol_device_handle_t Device,
342346
auto CreatedQueue = std::make_unique<ol_queue_impl_t>(nullptr, Device);
343347
auto Err = Device->Device->initAsyncInfo(&(CreatedQueue->AsyncInfo));
344348
if (Err)
345-
return {OL_ERRC_UNKNOWN, "Could not initialize stream resource"};
349+
return ol_impl_result_t::fromError(std::move(Err),
350+
"Could not initialize stream resource");
346351

347352
*Queue = CreatedQueue.release();
348353
return OL_SUCCESS;
@@ -357,24 +362,29 @@ ol_impl_result_t olWaitQueue_impl(ol_queue_handle_t Queue) {
357362
// on it, but we have nothing to synchronize in that situation anyway.
358363
if (Queue->AsyncInfo->Queue) {
359364
auto Err = Queue->Device->Device->synchronize(Queue->AsyncInfo);
360-
if (Err)
365+
if (Err) {
366+
llvm::consumeError(std::move(Err));
361367
return {OL_ERRC_INVALID_QUEUE, "The queue failed to synchronize"};
368+
}
362369
}
363370

364371
// Recreate the stream resource so the queue can be reused
365372
// TODO: Would be easier for the synchronization to (optionally) not release
366373
// it to begin with.
367374
auto Res = Queue->Device->Device->initAsyncInfo(&Queue->AsyncInfo);
368375
if (Res)
369-
return {OL_ERRC_UNKNOWN, "Could not reinitialize the stream resource"};
376+
return ol_impl_result_t::fromError(
377+
std::move(Res), "Could not reinitialize the stream resource");
370378

371379
return OL_SUCCESS;
372380
}
373381

374382
ol_impl_result_t olWaitEvent_impl(ol_event_handle_t Event) {
375383
auto Res = Event->Queue->Device->Device->syncEvent(Event->EventInfo);
376-
if (Res)
384+
if (Res) {
385+
llvm::consumeError(std::move(Res));
377386
return {OL_ERRC_INVALID_EVENT, "The event failed to synchronize"};
387+
}
378388

379389
return OL_SUCCESS;
380390
}
@@ -390,13 +400,17 @@ ol_impl_result_t olDestroyEvent_impl(ol_event_handle_t Event) {
390400
ol_event_handle_t makeEvent(ol_queue_handle_t Queue) {
391401
auto EventImpl = std::make_unique<ol_event_impl_t>(nullptr, Queue);
392402
auto Res = Queue->Device->Device->createEvent(&EventImpl->EventInfo);
393-
if (Res)
403+
if (Res) {
404+
llvm::consumeError(std::move(Res));
394405
return nullptr;
406+
}
395407

396408
Res = Queue->Device->Device->recordEvent(EventImpl->EventInfo,
397409
Queue->AsyncInfo);
398-
if (Res)
410+
if (Res) {
411+
llvm::consumeError(std::move(Res));
399412
return nullptr;
413+
}
400414

401415
return EventImpl.release();
402416
}
@@ -422,16 +436,19 @@ ol_impl_result_t olMemcpy_impl(ol_queue_handle_t Queue, void *DstPtr,
422436
if (DstDevice == HostDevice()) {
423437
auto Res = SrcDevice->Device->dataRetrieve(DstPtr, SrcPtr, Size, QueueImpl);
424438
if (Res)
425-
return {OL_ERRC_UNKNOWN, "The data retrieve operation failed"};
439+
return ol_impl_result_t::fromError(std::move(Res),
440+
"The data retrieve operation failed");
426441
} else if (SrcDevice == HostDevice()) {
427442
auto Res = DstDevice->Device->dataSubmit(DstPtr, SrcPtr, Size, QueueImpl);
428443
if (Res)
429-
return {OL_ERRC_UNKNOWN, "The data submit operation failed"};
444+
return ol_impl_result_t::fromError(std::move(Res),
445+
"The data submit operation failed");
430446
} else {
431447
auto Res = SrcDevice->Device->dataExchange(SrcPtr, *DstDevice->Device,
432448
DstPtr, Size, QueueImpl);
433449
if (Res)
434-
return {OL_ERRC_UNKNOWN, "The data exchange operation failed"};
450+
return ol_impl_result_t::fromError(std::move(Res),
451+
"The data exchange operation failed");
435452
}
436453

437454
if (EventOut)
@@ -458,6 +475,7 @@ ol_impl_result_t olCreateProgram_impl(ol_device_handle_t Device,
458475
auto Res =
459476
Device->Device->loadBinary(Device->Device->Plugin, &Prog->DeviceImage);
460477
if (!Res) {
478+
llvm::consumeError(Res.takeError());
461479
delete Prog;
462480
return OL_ERRC_INVALID_VALUE;
463481
}
@@ -483,7 +501,8 @@ ol_impl_result_t olGetKernel_impl(ol_program_handle_t Program,
483501

484502
auto Err = KernelImpl->init(Device, *Program->Image);
485503
if (Err)
486-
return {OL_ERRC_UNKNOWN, "Could not initialize the kernel"};
504+
return ol_impl_result_t::fromError(std::move(Err),
505+
"Could not initialize the kernel");
487506

488507
*Kernel = &*KernelImpl;
489508

@@ -526,7 +545,8 @@ olLaunchKernel_impl(ol_queue_handle_t Queue, ol_device_handle_t Device,
526545

527546
AsyncInfoWrapper.finalize(Err);
528547
if (Err)
529-
return {OL_ERRC_UNKNOWN, "Could not finalize the AsyncInfoWrapper"};
548+
return ol_impl_result_t::fromError(
549+
std::move(Err), "Could not finalize the AsyncInfoWrapper");
530550

531551
if (EventOut)
532552
*EventOut = makeEvent(Queue);

offload/unittests/OffloadAPI/kernel/olGetKernel.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ TEST_P(olGetKernelTest, InvalidNullKernelPointer) {
2929
ASSERT_ERROR(OL_ERRC_INVALID_NULL_POINTER,
3030
olGetKernel(Program, "foo", nullptr));
3131
}
32+
33+
// Error code returning from plugin interface not yet supported
34+
TEST_F(olGetKernelTest, DISABLED_InvalidKernelName) {
35+
ol_kernel_handle_t Kernel = nullptr;
36+
ASSERT_ERROR(OL_ERRC_INVALID_KERNEL_NAME,
37+
olGetKernel(Program, "invalid_kernel_name", &Kernel));
38+
}

0 commit comments

Comments
 (0)