Skip to content

Commit e498b79

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. 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 e498b79

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

offload/liboffload/include/OffloadImpl.hpp

Lines changed: 13 additions & 0 deletions
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

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,9 @@ ol_impl_result_t olMemAlloc_impl(ol_device_handle_t Device,
311311
auto Alloc =
312312
Device->Device->dataAlloc(Size, nullptr, convertOlToPluginAllocTy(Type));
313313
if (!Alloc)
314-
return {OL_ERRC_OUT_OF_RESOURCES,
315-
formatv("Could not create allocation on device {0}", Device).str()};
314+
ol_impl_result_t::fromError(
315+
Alloc.takeError(),
316+
formatv("Could not create allocation on device {0}", Device).str());
316317

317318
*AllocationOut = *Alloc;
318319
allocInfoMap().insert_or_assign(*Alloc, AllocInfo{Device, Type});
@@ -330,7 +331,8 @@ ol_impl_result_t olMemFree_impl(void *Address) {
330331
auto Res =
331332
Device->Device->dataDelete(Address, convertOlToPluginAllocTy(Type));
332333
if (Res)
333-
return {OL_ERRC_OUT_OF_RESOURCES, "Could not free allocation"};
334+
return ol_impl_result_t::fromError(std::move(Res),
335+
"Could not free allocation");
334336

335337
allocInfoMap().erase(Address);
336338

@@ -342,7 +344,8 @@ ol_impl_result_t olCreateQueue_impl(ol_device_handle_t Device,
342344
auto CreatedQueue = std::make_unique<ol_queue_impl_t>(nullptr, Device);
343345
auto Err = Device->Device->initAsyncInfo(&(CreatedQueue->AsyncInfo));
344346
if (Err)
345-
return {OL_ERRC_UNKNOWN, "Could not initialize stream resource"};
347+
return ol_impl_result_t::fromError(std::move(Err),
348+
"Could not initialize stream resource");
346349

347350
*Queue = CreatedQueue.release();
348351
return OL_SUCCESS;
@@ -358,23 +361,26 @@ ol_impl_result_t olWaitQueue_impl(ol_queue_handle_t Queue) {
358361
if (Queue->AsyncInfo->Queue) {
359362
auto Err = Queue->Device->Device->synchronize(Queue->AsyncInfo);
360363
if (Err)
361-
return {OL_ERRC_INVALID_QUEUE, "The queue failed to synchronize"};
364+
ol_impl_result_t::fromError(std::move(Err),
365+
"The queue failed to synchronize");
362366
}
363367

364368
// Recreate the stream resource so the queue can be reused
365369
// TODO: Would be easier for the synchronization to (optionally) not release
366370
// it to begin with.
367371
auto Res = Queue->Device->Device->initAsyncInfo(&Queue->AsyncInfo);
368372
if (Res)
369-
return {OL_ERRC_UNKNOWN, "Could not reinitialize the stream resource"};
373+
return ol_impl_result_t::fromError(
374+
std::move(Res), "Could not reinitialize the stream resource");
370375

371376
return OL_SUCCESS;
372377
}
373378

374379
ol_impl_result_t olWaitEvent_impl(ol_event_handle_t Event) {
375380
auto Res = Event->Queue->Device->Device->syncEvent(Event->EventInfo);
376381
if (Res)
377-
return {OL_ERRC_INVALID_EVENT, "The event failed to synchronize"};
382+
ol_impl_result_t::fromError(std::move(Res),
383+
"The event failed to synchronize");
378384

379385
return OL_SUCCESS;
380386
}
@@ -390,13 +396,17 @@ ol_impl_result_t olDestroyEvent_impl(ol_event_handle_t Event) {
390396
ol_event_handle_t makeEvent(ol_queue_handle_t Queue) {
391397
auto EventImpl = std::make_unique<ol_event_impl_t>(nullptr, Queue);
392398
auto Res = Queue->Device->Device->createEvent(&EventImpl->EventInfo);
393-
if (Res)
399+
if (Res) {
400+
llvm::consumeError(std::move(Res));
394401
return nullptr;
402+
}
395403

396404
Res = Queue->Device->Device->recordEvent(EventImpl->EventInfo,
397405
Queue->AsyncInfo);
398-
if (Res)
406+
if (Res) {
407+
llvm::consumeError(std::move(Res));
399408
return nullptr;
409+
}
400410

401411
return EventImpl.release();
402412
}
@@ -422,16 +432,19 @@ ol_impl_result_t olMemcpy_impl(ol_queue_handle_t Queue, void *DstPtr,
422432
if (DstDevice == HostDevice()) {
423433
auto Res = SrcDevice->Device->dataRetrieve(DstPtr, SrcPtr, Size, QueueImpl);
424434
if (Res)
425-
return {OL_ERRC_UNKNOWN, "The data retrieve operation failed"};
435+
return ol_impl_result_t::fromError(std::move(Res),
436+
"The data retrieve operation failed");
426437
} else if (SrcDevice == HostDevice()) {
427438
auto Res = DstDevice->Device->dataSubmit(DstPtr, SrcPtr, Size, QueueImpl);
428439
if (Res)
429-
return {OL_ERRC_UNKNOWN, "The data submit operation failed"};
440+
return ol_impl_result_t::fromError(std::move(Res),
441+
"The data submit operation failed");
430442
} else {
431443
auto Res = SrcDevice->Device->dataExchange(SrcPtr, *DstDevice->Device,
432444
DstPtr, Size, QueueImpl);
433445
if (Res)
434-
return {OL_ERRC_UNKNOWN, "The data exchange operation failed"};
446+
return ol_impl_result_t::fromError(std::move(Res),
447+
"The data exchange operation failed");
435448
}
436449

437450
if (EventOut)
@@ -459,7 +472,7 @@ ol_impl_result_t olCreateProgram_impl(ol_device_handle_t Device,
459472
Device->Device->loadBinary(Device->Device->Plugin, &Prog->DeviceImage);
460473
if (!Res) {
461474
delete Prog;
462-
return OL_ERRC_INVALID_VALUE;
475+
return ol_impl_result_t::fromError(Res.takeError(), "Invalid binary");
463476
}
464477

465478
Prog->Image = *Res;
@@ -483,7 +496,8 @@ ol_impl_result_t olGetKernel_impl(ol_program_handle_t Program,
483496

484497
auto Err = KernelImpl->init(Device, *Program->Image);
485498
if (Err)
486-
return {OL_ERRC_UNKNOWN, "Could not initialize the kernel"};
499+
return ol_impl_result_t::fromError(std::move(Err),
500+
"Could not initialize the kernel");
487501

488502
*Kernel = &*KernelImpl;
489503

@@ -526,7 +540,8 @@ olLaunchKernel_impl(ol_queue_handle_t Queue, ol_device_handle_t Device,
526540

527541
AsyncInfoWrapper.finalize(Err);
528542
if (Err)
529-
return {OL_ERRC_UNKNOWN, "Could not finalize the AsyncInfoWrapper"};
543+
return ol_impl_result_t::fromError(
544+
std::move(Err), "Could not finalize the AsyncInfoWrapper");
530545

531546
if (EventOut)
532547
*EventOut = makeEvent(Queue);

offload/unittests/OffloadAPI/kernel/olGetKernel.cpp

Lines changed: 7 additions & 0 deletions
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)