[llvm] [Offload] Implement the remaining initial Offload API (PR #122106)

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 19 08:06:31 PST 2025


================
@@ -245,3 +315,331 @@ ol_impl_result_t olGetDeviceInfoSize_impl(ol_device_handle_t Device,
                                           size_t *PropSizeRet) {
   return olGetDeviceInfoImplDetail(Device, PropName, 0, nullptr, PropSizeRet);
 }
+
+ol_impl_result_t olGetHostDevice_impl(ol_device_handle_t *Device) {
+  *Device = HostDevice();
+  return OL_SUCCESS;
+}
+
+TargetAllocTy convertOlToPluginAllocTy(ol_alloc_type_t Type) {
+  switch (Type) {
+  case OL_ALLOC_TYPE_DEVICE:
+    return TARGET_ALLOC_DEVICE;
+  case OL_ALLOC_TYPE_HOST:
+    return TARGET_ALLOC_HOST;
+  case OL_ALLOC_TYPE_SHARED:
+  default:
+    return TARGET_ALLOC_SHARED;
+  }
+}
+
+ol_impl_result_t olMemAlloc_impl(ol_device_handle_t Device,
+                                 ol_alloc_type_t Type, size_t Size,
+                                 void **AllocationOut) {
+  auto Alloc =
+      Device->Device->dataAlloc(Size, nullptr, convertOlToPluginAllocTy(Type));
+  if (!Alloc)
+    return {OL_ERRC_OUT_OF_RESOURCES,
+            formatv("Could not create allocation on device {0}", Device).str()};
+
+  *AllocationOut = *Alloc;
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olMemFree_impl(ol_device_handle_t Device, ol_alloc_type_t Type,
+                                void *Address) {
+  auto Res =
+      Device->Device->dataDelete(Address, convertOlToPluginAllocTy(Type));
+  if (Res)
+    return {OL_ERRC_OUT_OF_RESOURCES, "Could not free allocation"};
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olCreateQueue_impl(ol_device_handle_t Device,
+                                    ol_queue_handle_t *Queue) {
+  auto CreatedQueue = std::make_unique<ol_queue_impl_t>();
+  auto Err = Device->Device->initAsyncInfo(&(CreatedQueue->AsyncInfo));
+  if (Err)
+    return {OL_ERRC_UNKNOWN, "Could not initialize stream resource"};
+
+  CreatedQueue->Device = Device;
+  CreatedQueue->RefCount = 1;
+  *Queue = CreatedQueue.release();
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olRetainQueue_impl(ol_queue_handle_t Queue) {
+  Queue->RefCount++;
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olReleaseQueue_impl(ol_queue_handle_t Queue) {
+  if (--Queue->RefCount == 0)
+    delete Queue;
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olFinishQueue_impl(ol_queue_handle_t Queue) {
+  // Host plugin doesn't have a queue set so it's not safe to call synchronize
+  // on it, but we have nothing to synchronize in that situation anyway.
+  if (Queue->AsyncInfo->Queue) {
+    auto Err = Queue->Device->Device->synchronize(Queue->AsyncInfo);
+    if (Err)
+      return {OL_ERRC_INVALID_QUEUE, "The queue failed to synchronize"};
+  }
+
+  // Recreate the stream resource so the queue can be reused
+  // TODO: Would be easier for the synchronization to (optionally) not release
+  // it to begin with.
+  auto Res = Queue->Device->Device->initAsyncInfo(&Queue->AsyncInfo);
+  if (Res)
+    return {OL_ERRC_UNKNOWN, "Could not reinitialize the stream resource"};
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olWaitEvent_impl(ol_event_handle_t Event) {
+  auto Res = Event->Queue->Device->Device->syncEvent(Event->EventInfo);
+  if (Res)
+    return {OL_ERRC_INVALID_EVENT, "The event failed to synchronize"};
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olRetainEvent_impl(ol_event_handle_t Event) {
+  Event->RefCount++;
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olReleaseEvent_impl(ol_event_handle_t Event) {
+  if (--Event->RefCount == 0)
+    delete Event;
+
+  return OL_SUCCESS;
+}
+
+ol_event_handle_t makeEvent(ol_queue_handle_t Queue) {
+  auto EventImpl = std::make_unique<ol_event_impl_t>();
+  EventImpl->Queue = Queue;
+  auto Res = Queue->Device->Device->createEvent(&EventImpl->EventInfo);
+  if (Res)
+    return nullptr;
+
+  Res = Queue->Device->Device->recordEvent(EventImpl->EventInfo,
+                                           Queue->AsyncInfo);
+  if (Res)
+    return nullptr;
+
+  return EventImpl.release();
+}
+
+ol_impl_result_t olEnqueueMemcpy_impl(ol_queue_handle_t Queue, void *DstPtr,
+                                      ol_device_handle_t DstDevice,
+                                      void *SrcPtr,
+                                      ol_device_handle_t SrcDevice, size_t Size,
+                                      ol_event_handle_t *EventOut) {
+  if (DstDevice == HostDevice() && SrcDevice == HostDevice()) {
+    // TODO: We could actually handle this with a plain memcpy but we currently
+    // have no way of synchronizing this with the queue
+    return {OL_ERRC_INVALID_ARGUMENT,
+            "One of DstDevice and SrcDevice must be a non-host device"};
+  }
+
+  if (DstDevice == HostDevice()) {
+    auto Res =
+        SrcDevice->Device->dataRetrieve(DstPtr, SrcPtr, Size, Queue->AsyncInfo);
+    if (Res)
+      return {OL_ERRC_UNKNOWN, "The data retrieve operation failed"};
+  } else if (SrcDevice == HostDevice()) {
+    auto Res =
+        DstDevice->Device->dataSubmit(DstPtr, SrcPtr, Size, Queue->AsyncInfo);
+    if (Res)
+      return {OL_ERRC_UNKNOWN, "The data submit operation failed"};
+  } else {
+    auto Res = SrcDevice->Device->dataExchange(SrcPtr, *DstDevice->Device,
+                                               DstPtr, Size, Queue->AsyncInfo);
+    if (Res)
+      return {OL_ERRC_UNKNOWN, "The data exchange operation failed"};
+  }
+
+  if (EventOut)
+    *EventOut = makeEvent(Queue);
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olEnqueueMemcpyHtoD_impl(ol_queue_handle_t Queue, void *DstPtr,
+                                          void *SrcPtr, size_t Size,
+                                          ol_event_handle_t *EventOut) {
+  auto *DeviceImpl = Queue->Device->Device;
+
+  auto Res = DeviceImpl->dataSubmit(DstPtr, SrcPtr, Size, Queue->AsyncInfo);
+
+  if (Res)
+    return {OL_ERRC_UNKNOWN, "The data submit operation failed"};
+
+  if (EventOut)
+    *EventOut = makeEvent(Queue);
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olEnqueueMemcpyDtoH_impl(ol_queue_handle_t Queue, void *DstPtr,
+                                          void *SrcPtr, size_t Size,
+                                          ol_event_handle_t *EventOut) {
+  auto *DeviceImpl = Queue->Device->Device;
+
+  auto Res = DeviceImpl->dataRetrieve(DstPtr, SrcPtr, Size, Queue->AsyncInfo);
+
+  if (Res)
+    return {OL_ERRC_UNKNOWN, "The data retrieve operation failed"};
+
+  if (EventOut)
+    *EventOut = makeEvent(Queue);
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olEnqueueMemcpyDtoD_impl(ol_queue_handle_t Queue,
+                                          ol_device_handle_t DstDevice,
+                                          void *DstPtr, void *SrcPtr,
+                                          size_t Size,
+                                          ol_event_handle_t *EventOut) {
+  auto *DeviceImpl = Queue->Device->Device;
+
+  auto Res = DeviceImpl->dataExchange(SrcPtr, *DstDevice->Device, DstPtr, Size,
+                                      Queue->AsyncInfo);
+
+  if (Res)
+    return {OL_ERRC_UNKNOWN, "The data exchange operation failed"};
+
+  if (EventOut)
+    *EventOut = makeEvent(Queue);
+
+  return OL_SUCCESS;
+}
+
+ol_impl_result_t olCreateProgram_impl(ol_device_handle_t Device, void *ProgData,
+                                      size_t ProgDataSize,
+                                      ol_program_handle_t *Program) {
+  // Make a copy of the program binary in case it is released by the caller.
+  // TODO: Make this copy optional.
+  auto ImageData = MemoryBuffer::getMemBufferCopy(
+      StringRef(reinterpret_cast<char *>(ProgData), ProgDataSize));
+  __tgt_device_image DeviceImage{
+      const_cast<char *>(ImageData->getBuffer().data()),
+      const_cast<char *>(ImageData->getBuffer().data()) + ProgDataSize - 1,
----------------
jdoerfert wrote:

The ProgDataSize is one past the buffer? Is there a null character?

https://github.com/llvm/llvm-project/pull/122106


More information about the llvm-commits mailing list