From 53ead32bfabaf78b250b78a34f9db6826c665207 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Mon, 30 Mar 2026 15:07:27 +0200 Subject: [PATCH] api-query: Continue device initialization when a backend fails Device::initialize() returns early when any backend fails to initialize, preventing subsequent backends from being discovered. For example, a Vulkan initialization failure (e.g. VK_ERROR_INCOMPATIBLE_DRIVER when MoltenVK is not installed) blocks Metal device discovery on macOS. Collect backend initialization errors with joinErrors() and return them together instead. Also make lit.cfg.py resilient to an empty device list from api-query. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/API/Device.cpp | 24 +++++++++++++++++------- test/lit.cfg.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/API/Device.cpp b/lib/API/Device.cpp index fc1044884..c1be35d15 100644 --- a/lib/API/Device.cpp +++ b/lib/API/Device.cpp @@ -14,8 +14,8 @@ #include "Config.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" -#include #include using namespace offloadtest; @@ -27,21 +27,31 @@ Device::~Device() {} llvm::Expected>> offloadtest::initializeDevices(const DeviceConfig Config) { llvm::SmallVector> Devices; + llvm::Error Err = llvm::Error::success(); #ifdef OFFLOADTEST_ENABLE_D3D12 - if (auto Err = initializeDX12Devices(Config, Devices)) - return Err; + if (auto E = initializeDX12Devices(Config, Devices)) + Err = llvm::joinErrors(std::move(Err), std::move(E)); #endif #ifdef OFFLOADTEST_ENABLE_VULKAN - if (auto Err = initializeVulkanDevices(Config, Devices)) - return Err; + if (auto E = initializeVulkanDevices(Config, Devices)) + Err = llvm::joinErrors(std::move(Err), std::move(E)); #endif #ifdef OFFLOADTEST_ENABLE_METAL - if (auto Err = initializeMetalDevices(Config, Devices)) - return Err; + if (auto E = initializeMetalDevices(Config, Devices)) + Err = llvm::joinErrors(std::move(Err), std::move(E)); #endif + if (Devices.empty()) { + if (Err) + return std::move(Err); + return llvm::createStringError(std::errc::no_such_device, + "No GPU devices found."); + } + // Log errors from backends that failed while others succeeded. + if (Err) + llvm::logAllUnhandledErrors(std::move(Err), llvm::errs()); return Devices; } diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 35e8f2ba5..029953e74 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -241,7 +241,7 @@ def setDeviceFeatures(config, device, compiler): target_device = None # Find the right device to configure against pattern = re.compile(GPUName, re.IGNORECASE) -for device in devices["Devices"]: +for device in devices.get("Devices", []): is_warp = "Microsoft Basic Render Driver" in device["Description"] is_gpu_name_match = bool(pattern.search(device["Description"])) if device["API"] == "DirectX" and config.offloadtest_enable_d3d12: