Skip to content

Commit e302c82

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 9f94e36 commit e302c82

File tree

3 files changed

+53
-13
lines changed

3 files changed

+53
-13
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: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,11 @@ ol_impl_result_t olMemAlloc_impl(ol_device_handle_t Device,
308308
void **AllocationOut) {
309309
auto Alloc =
310310
Device->Device->dataAlloc(Size, nullptr, convertOlToPluginAllocTy(Type));
311-
if (!Alloc)
311+
if (!Alloc) {
312+
llvm::consumeError(Alloc.takeError());
312313
return {OL_ERRC_OUT_OF_RESOURCES,
313314
formatv("Could not create allocation on device {0}", Device).str()};
315+
}
314316

315317
*AllocationOut = *Alloc;
316318
allocInfoMap().insert_or_assign(*Alloc, AllocInfo{Device, Type});
@@ -327,8 +329,10 @@ ol_impl_result_t olMemFree_impl(void *Address) {
327329

328330
auto Res =
329331
Device->Device->dataDelete(Address, convertOlToPluginAllocTy(Type));
330-
if (Res)
332+
if (Res) {
333+
llvm::consumeError(std::move(Res));
331334
return {OL_ERRC_OUT_OF_RESOURCES, "Could not free allocation"};
335+
}
332336

333337
allocInfoMap().erase(Address);
334338

@@ -340,7 +344,8 @@ ol_impl_result_t olCreateQueue_impl(ol_device_handle_t Device,
340344
auto CreatedQueue = std::make_unique<ol_queue_impl_t>(nullptr, Device);
341345
auto Err = Device->Device->initAsyncInfo(&(CreatedQueue->AsyncInfo));
342346
if (Err)
343-
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");
344349

345350
*Queue = CreatedQueue.release();
346351
return OL_SUCCESS;
@@ -355,24 +360,29 @@ ol_impl_result_t olWaitQueue_impl(ol_queue_handle_t Queue) {
355360
// on it, but we have nothing to synchronize in that situation anyway.
356361
if (Queue->AsyncInfo->Queue) {
357362
auto Err = Queue->Device->Device->synchronize(Queue->AsyncInfo);
358-
if (Err)
363+
if (Err) {
364+
llvm::consumeError(std::move(Err));
359365
return {OL_ERRC_INVALID_QUEUE, "The queue failed to synchronize"};
366+
}
360367
}
361368

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

369377
return OL_SUCCESS;
370378
}
371379

372380
ol_impl_result_t olWaitEvent_impl(ol_event_handle_t Event) {
373381
auto Res = Event->Queue->Device->Device->syncEvent(Event->EventInfo);
374-
if (Res)
382+
if (Res) {
383+
llvm::consumeError(std::move(Res));
375384
return {OL_ERRC_INVALID_EVENT, "The event failed to synchronize"};
385+
}
376386

377387
return OL_SUCCESS;
378388
}
@@ -384,13 +394,17 @@ ol_impl_result_t olDestroyEvent_impl(ol_event_handle_t Event) {
384394
ol_event_handle_t makeEvent(ol_queue_handle_t Queue) {
385395
auto EventImpl = std::make_unique<ol_event_impl_t>(nullptr, Queue);
386396
auto Res = Queue->Device->Device->createEvent(&EventImpl->EventInfo);
387-
if (Res)
397+
if (Res) {
398+
llvm::consumeError(std::move(Res));
388399
return nullptr;
400+
}
389401

390402
Res = Queue->Device->Device->recordEvent(EventImpl->EventInfo,
391403
Queue->AsyncInfo);
392-
if (Res)
404+
if (Res) {
405+
llvm::consumeError(std::move(Res));
393406
return nullptr;
407+
}
394408

395409
return EventImpl.release();
396410
}
@@ -416,16 +430,19 @@ ol_impl_result_t olMemcpy_impl(ol_queue_handle_t Queue, void *DstPtr,
416430
if (DstDevice == HostDevice()) {
417431
auto Res = SrcDevice->Device->dataRetrieve(DstPtr, SrcPtr, Size, QueueImpl);
418432
if (Res)
419-
return {OL_ERRC_UNKNOWN, "The data retrieve operation failed"};
433+
return ol_impl_result_t::fromError(std::move(Res),
434+
"The data retrieve operation failed");
420435
} else if (SrcDevice == HostDevice()) {
421436
auto Res = DstDevice->Device->dataSubmit(DstPtr, SrcPtr, Size, QueueImpl);
422437
if (Res)
423-
return {OL_ERRC_UNKNOWN, "The data submit operation failed"};
438+
return ol_impl_result_t::fromError(std::move(Res),
439+
"The data submit operation failed");
424440
} else {
425441
auto Res = SrcDevice->Device->dataExchange(SrcPtr, *DstDevice->Device,
426442
DstPtr, Size, QueueImpl);
427443
if (Res)
428-
return {OL_ERRC_UNKNOWN, "The data exchange operation failed"};
444+
return ol_impl_result_t::fromError(std::move(Res),
445+
"The data exchange operation failed");
429446
}
430447

431448
if (EventOut)
@@ -452,6 +469,7 @@ ol_impl_result_t olCreateProgram_impl(ol_device_handle_t Device,
452469
auto Res =
453470
Device->Device->loadBinary(Device->Device->Plugin, &Prog->DeviceImage);
454471
if (!Res) {
472+
llvm::consumeError(Res.takeError());
455473
delete Prog;
456474
return OL_ERRC_INVALID_VALUE;
457475
}
@@ -477,7 +495,8 @@ ol_impl_result_t olGetKernel_impl(ol_program_handle_t Program,
477495

478496
auto Err = KernelImpl->init(Device, *Program->Image);
479497
if (Err)
480-
return {OL_ERRC_UNKNOWN, "Could not initialize the kernel"};
498+
return ol_impl_result_t::fromError(std::move(Err),
499+
"Could not initialize the kernel");
481500

482501
*Kernel = &*KernelImpl;
483502

@@ -520,7 +539,8 @@ olLaunchKernel_impl(ol_queue_handle_t Queue, ol_device_handle_t Device,
520539

521540
AsyncInfoWrapper.finalize(Err);
522541
if (Err)
523-
return {OL_ERRC_UNKNOWN, "Could not finalize the AsyncInfoWrapper"};
542+
return ol_impl_result_t::fromError(
543+
std::move(Err), "Could not finalize the AsyncInfoWrapper");
524544

525545
if (EventOut)
526546
*EventOut = makeEvent(Queue);

offload/unittests/OffloadAPI/kernel/olGetKernel.cpp

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

0 commit comments

Comments
 (0)