[llvm-branch-commits] [llvm] [OFFLOAD] Add olIterateCompatibleDevices API (PR #221734)
Alex Duran via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Sep 7 06:49:11 PDT 2026
https://github.com/adurang created https://github.com/llvm/llvm-project/pull/221734
<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
>From c40b30f8304a17aa550504d1e452d83ae9a2c2d5 Mon Sep 17 00:00:00 2001
From: "Duran, Alex" <alejandro.duran at intel.com>
Date: Mon, 7 Sep 2026 03:17:04 -0700
Subject: [PATCH] [OFFLOAD] Add olIterateCompatibleDevices API
---
offload/liboffload/API/Program.td | 15 ++++
offload/liboffload/src/OffloadImpl.cpp | 26 +++++++
offload/unittests/OffloadAPI/CMakeLists.txt | 1 +
.../program/olIterateCompatibleDevices.cpp | 73 +++++++++++++++++++
4 files changed, 115 insertions(+)
create mode 100644 offload/unittests/OffloadAPI/program/olIterateCompatibleDevices.cpp
diff --git a/offload/liboffload/API/Program.td b/offload/liboffload/API/Program.td
index ecc8fb73dad3f..9f945872aec3c 100644
--- a/offload/liboffload/API/Program.td
+++ b/offload/liboffload/API/Program.td
@@ -46,6 +46,21 @@ def olIsValidBinary : Function {
let returns = [];
}
+def olIterateCompatibleDevices : Function {
+ let desc = "Iterates over all available devices that are compatible with the binary image pointed to by `ProgData`, calling the callback for each device.";
+ let details = [
+ "The provided `ProgData` will not be loaded onto any device",
+ "If the user-provided callback returns `false`, the iteration is stopped."
+ ];
+ let params = [
+ Param<"const void*", "ProgData", "pointer to the program binary data", PARAM_IN>,
+ Param<"size_t", "ProgDataSize", "size of the program binary in bytes", PARAM_IN>,
+ Param<"ol_device_iterate_cb_t", "Callback", "User-provided function called for each compatible device", PARAM_IN>,
+ Param<"void*", "UserData", "Optional user data to pass to the callback", PARAM_IN_OPTIONAL>
+ ];
+ let returns = [];
+}
+
def olDestroyProgram : Function {
let desc = "Destroy the program and free all underlying resources.";
let details = [];
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index cdc586b975bc4..87306cee4fbe2 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -1328,6 +1328,32 @@ Error olIsValidBinary_impl(ol_device_handle_t Device, const void *ProgData,
return Error::success();
}
+Error olIterateCompatibleDevices_impl(const void *ProgData, size_t ProgDataSize,
+ ol_device_iterate_cb_t Callback,
+ void *UserData) {
+ StringRef Buffer(reinterpret_cast<const char *>(ProgData), ProgDataSize);
+
+ for (auto &Platform : OffloadContext::get().Platforms) {
+ if (!Platform->Plugin || !Platform->Plugin->isPluginCompatible(Buffer))
+ continue;
+
+ // If the image is compatible, initialize the platform.
+ if (auto Err = Platform->init())
+ return Err;
+
+ for (auto &Device : Platform->Devices) {
+ if (!Device->Platform.Plugin->isDeviceCompatible(Device->DeviceNum,
+ Buffer))
+ continue;
+
+ if (!Callback(Device.get(), UserData))
+ return Error::success();
+ }
+ }
+
+ return Error::success();
+}
+
Error olDestroyProgram_impl(ol_program_handle_t Program) {
auto &Device = Program->Image->getDevice();
if (auto Err = Device.unloadBinary(Program->Image))
diff --git a/offload/unittests/OffloadAPI/CMakeLists.txt b/offload/unittests/OffloadAPI/CMakeLists.txt
index 292ea1eb4852f..8bed11be4d85e 100644
--- a/offload/unittests/OffloadAPI/CMakeLists.txt
+++ b/offload/unittests/OffloadAPI/CMakeLists.txt
@@ -49,6 +49,7 @@ add_offload_unittest("platform"
add_offload_unittest("program"
program/olCreateProgram.cpp
program/olIsValidBinary.cpp
+ program/olIterateCompatibleDevices.cpp
program/olDestroyProgram.cpp)
add_offload_unittest("queue"
diff --git a/offload/unittests/OffloadAPI/program/olIterateCompatibleDevices.cpp b/offload/unittests/OffloadAPI/program/olIterateCompatibleDevices.cpp
new file mode 100644
index 0000000000000..afa26c57d6728
--- /dev/null
+++ b/offload/unittests/OffloadAPI/program/olIterateCompatibleDevices.cpp
@@ -0,0 +1,73 @@
+//===------- Offload API tests - olIterateCompatibleDevices -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../common/Fixtures.hpp"
+#include <OffloadAPI.h>
+#include <gtest/gtest.h>
+
+using olIterateCompatibleDevicesTest = OffloadDeviceTest;
+OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olIterateCompatibleDevicesTest);
+
+TEST_P(olIterateCompatibleDevicesTest, Success) {
+ std::unique_ptr<llvm::MemoryBuffer> DeviceBin;
+ ASSERT_TRUE(TestEnvironment::loadDeviceBinary("foo", Device, DeviceBin));
+ ASSERT_GE(DeviceBin->getBufferSize(), 0lu);
+
+ struct CallbackDataTy {
+ ol_device_handle_t ExpectedDevice;
+ bool Found = false;
+ } CallbackData{Device};
+
+ ASSERT_SUCCESS(olIterateCompatibleDevices(
+ DeviceBin->getBufferStart(), DeviceBin->getBufferSize(),
+ [](ol_device_handle_t D, void *UserData) {
+ auto *Data = static_cast<CallbackDataTy *>(UserData);
+ if (D == Data->ExpectedDevice)
+ Data->Found = true;
+ return true;
+ },
+ &CallbackData));
+
+ ASSERT_TRUE(CallbackData.Found);
+}
+
+TEST_P(olIterateCompatibleDevicesTest, SuccessStopIteration) {
+ std::unique_ptr<llvm::MemoryBuffer> DeviceBin;
+ ASSERT_TRUE(TestEnvironment::loadDeviceBinary("foo", Device, DeviceBin));
+ ASSERT_GE(DeviceBin->getBufferSize(), 0lu);
+
+ uint32_t CallCount = 0;
+ ASSERT_SUCCESS(olIterateCompatibleDevices(
+ DeviceBin->getBufferStart(), DeviceBin->getBufferSize(),
+ [](ol_device_handle_t, void *UserData) {
+ auto *Count = static_cast<uint32_t *>(UserData);
+ *Count += 1;
+ return false;
+ },
+ &CallCount));
+
+ ASSERT_EQ(CallCount, 1u);
+}
+
+TEST_P(olIterateCompatibleDevicesTest, EmptyBinary) {
+ std::unique_ptr<llvm::MemoryBuffer> DeviceBin;
+ ASSERT_TRUE(TestEnvironment::loadDeviceBinary("foo", Device, DeviceBin));
+ ASSERT_GE(DeviceBin->getBufferSize(), 0lu);
+
+ uint32_t CallCount = 0;
+ ASSERT_SUCCESS(olIterateCompatibleDevices(
+ DeviceBin->getBufferStart(), 0,
+ [](ol_device_handle_t, void *UserData) {
+ auto *Count = static_cast<uint32_t *>(UserData);
+ *Count += 1;
+ return true;
+ },
+ &CallCount));
+
+ ASSERT_EQ(CallCount, 0u);
+}
More information about the llvm-branch-commits
mailing list