From 623e6f915fc8cbc7a0c3a0f7e4238bb32f7b2baf Mon Sep 17 00:00:00 2001 From: zhenzew Date: Tue, 16 Jun 2026 05:01:40 -0500 Subject: [PATCH 1/6] =?UTF-8?q?=EF=BB=BFfeat(amdgpu):=20add=20hipep=20back?= =?UTF-8?q?end=20selected=20via=20profile=3Dllm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the hipep backend to the AMD GPU umbrella EP: load the pre-built hipep-backend plugin EP DLL as a third backend (alongside DirectML and MIGraphX) and route to it when the user selects profile=llm. - Profile::Llm parses "llm" / "3"; gpu_ep.cc routes profile=llm to ProviderFactory::CreateHipepBackend. - ProviderFactory loads hipep-backend and forwards CreateEp / ReleaseEp to it, mirroring the DirectML/MIGraphX backend pattern. hipep is a pre-built plugin EP DLL loaded at runtime, so no ROCm SDK is required to build amdgpu-ep. - CreateEp forwards the ORT-selected hardware device(s) + ep_metadata to the backend's CreateEp. Unlike DirectML/MIGraphX, hipep's CreateEp rejects num_devices == 0, so the umbrella must pass the selected device. DirectML and MIGraphX paths are unchanged. Co-authored-by: Cursor --- src/amdgpu/gpu_ep.cc | 12 ++++++++++++ src/amdgpu/gpu_ep.h | 2 ++ src/amdgpu/gpu_factory.cc | 21 +++++++++++++++++++-- src/amdgpu/gpu_factory.h | 16 ++++++++++++++++ src/amdgpu/gpu_info.cc | 2 ++ src/amdgpu/gpu_info.h | 3 ++- src/amdgpu/gpu_options.h | 1 + 7 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/amdgpu/gpu_ep.cc b/src/amdgpu/gpu_ep.cc index 8979077..1aa204e 100644 --- a/src/amdgpu/gpu_ep.cc +++ b/src/amdgpu/gpu_ep.cc @@ -36,6 +36,8 @@ namespace gpu_ep { ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view ep_name, + [[maybe_unused]] gsl::span devices, + [[maybe_unused]] gsl::span ep_metadata, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger) : OrtEp{ORT_API_VERSION}, ApiPtrs{factory.ort_api, factory.ep_api, factory.model_editor_api}, @@ -116,6 +118,14 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view }; }; + const auto create_hipep_backend = [&] { + // hipep manages allocator/data-transfer at the backend factory level, + // reached through the amdgpu Allocator/DataTransfer wrappers — leave + // OrtEp::CreateAllocator null so ORT falls back to ep_factory_.CreateAllocator. + THROW_IF_ERROR(factory.CreateHipepBackend(devices, ep_metadata, local_session_options, + logger, backend_ep_)); + }; + const auto create_migraphx_backend = [&] { const auto get_name = [](const std::string_view sv) { return std::string{"ep."}.append(kMIGraphXBackend).append(".").append(sv); @@ -165,6 +175,8 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view create_directml_backend(); } else if (info.profile == Profile::MIGraphX) { create_migraphx_backend(); + } else if (info.profile == Profile::Llm) { + create_hipep_backend(); } else { create_migraphx_backend(); } diff --git a/src/amdgpu/gpu_ep.h b/src/amdgpu/gpu_ep.h index d8f0290..45a9a93 100644 --- a/src/amdgpu/gpu_ep.h +++ b/src/amdgpu/gpu_ep.h @@ -10,6 +10,8 @@ namespace gpu_ep { struct ExecutionProvider : OrtEp, ApiPtrs { ExecutionProvider(ProviderFactory& factory, std::string_view ep_name, + gsl::span devices, + gsl::span ep_metadata, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger); ~ExecutionProvider(); diff --git a/src/amdgpu/gpu_factory.cc b/src/amdgpu/gpu_factory.cc index d2b2d93..51ba153 100644 --- a/src/amdgpu/gpu_factory.cc +++ b/src/amdgpu/gpu_factory.cc @@ -47,6 +47,7 @@ namespace gpu_ep { namespace { constexpr auto directmlBackend{LIBRARY_PREFIX ORT_TSTR("directml-backend") LIBRARY_SUFFIX}; constexpr auto migraphxBackend{LIBRARY_PREFIX ORT_TSTR("migraphx-backend") LIBRARY_SUFFIX}; +constexpr auto hipepBackend{LIBRARY_PREFIX ORT_TSTR("hipep-backend") LIBRARY_SUFFIX}; } ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_api_base, const char* ep_name, const OrtLogger* default_logger) @@ -145,6 +146,18 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_ THROW_IF_ERROR(mgx_create_ep_factories(kMIGraphXBackend, ort_api_base, default_logger, &mgx_ep_factory_, 1, &factories_created)); + THROW_IF_ERROR(LoadDynamicLibrary(hipepBackend, &hip_backend_)); + THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, + "ReleaseEpFactory", reinterpret_cast(&hip_release_ep_factory_))); + + CreateEpFactories_t hip_create_ep_factories{}; + THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, + "CreateEpFactories", reinterpret_cast(&hip_create_ep_factories))); + + // Pass ep_name_ so the hipep backend's EP reports the same name ORT sees. + THROW_IF_ERROR(hip_create_ep_factories(ep_name_.c_str(), ort_api_base, default_logger, + &hip_ep_factory_, 1, &factories_created)); + data_transfer_ = std::make_unique(*this); } @@ -169,6 +182,9 @@ ProviderFactory::~ProviderFactory() { if (!UnloadDynamicLibrary(mgx_backend_).IsOK()) { /* TODO: log failure while unloading MIGraphX EP library */ } + if (!UnloadDynamicLibrary(hip_backend_).IsOK()) { + /* TODO: log failure while unloading hipep EP library */ + } } const char* ProviderFactory::GetName() const { @@ -222,7 +238,7 @@ Ort::Status ProviderFactory::GetSupportedDevices(const std::vector devices, - gsl::span /* ep_metadata */, + gsl::span ep_metadata, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger, OrtEp* &ep) try { ep = nullptr; @@ -230,7 +246,8 @@ try { return MAKE_STATUS(ORT_INVALID_ARGUMENT, "only supports selection for a single device"); } - ep = std::make_unique(*this, ep_name_, session_options, logger).release(); + ep = std::make_unique(*this, ep_name_, devices, ep_metadata, + session_options, logger).release(); return STATUS_OK; } catch (const Ort::Exception& e) { return Ort::Status{e}; diff --git a/src/amdgpu/gpu_factory.h b/src/amdgpu/gpu_factory.h index 8f9d399..19ea8f3 100644 --- a/src/amdgpu/gpu_factory.h +++ b/src/amdgpu/gpu_factory.h @@ -24,6 +24,17 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs { return STATUS_OK; } + // Unlike DirectML/MIGraphX, the hipep backend requires the selected + // hardware device(s) to be forwarded (its CreateEp rejects num_devices == 0). + Ort::Status CreateHipepBackend(gsl::span devices, + gsl::span ep_metadata, + const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) { + RETURN_IF_ERROR(hip_ep_factory_->CreateEp(hip_ep_factory_, devices.data(), + ep_metadata.data(), devices.size(), session_options, logger, &ep)); + backend_ep_factory_ = hip_ep_factory_; + return STATUS_OK; + } + OrtEpFactory* GetBackendFactory() const noexcept { return backend_ep_factory_; } @@ -87,6 +98,11 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs { OrtEpFactory* mgx_ep_factory_{}; + void* hip_backend_{}; + ReleaseEpFactory_t hip_release_ep_factory_{}; + + OrtEpFactory* hip_ep_factory_{}; + OrtHardwareDevice* virtual_device_{}; // Owned memory infos for the GPU and pinned device slots, registered with OrtEpDevice. diff --git a/src/amdgpu/gpu_info.cc b/src/amdgpu/gpu_info.cc index 0c0d1d8..b7cc036 100644 --- a/src/amdgpu/gpu_info.cc +++ b/src/amdgpu/gpu_info.cc @@ -27,6 +27,8 @@ ProviderInfo::ProviderInfo(const ProviderOptions& provider_options) { profile = Profile::MIGraphX; } else if (lower == "directml" || value == "4") { profile = Profile::DirectML; + } else if (lower == "llm" || value == "5") { + profile = Profile::Llm; } else { return MAKE_STATUS(ORT_FAIL, "unknown profile: '", value, "'"); } diff --git a/src/amdgpu/gpu_info.h b/src/amdgpu/gpu_info.h index 18ded75..5e2a8ba 100644 --- a/src/amdgpu/gpu_info.h +++ b/src/amdgpu/gpu_info.h @@ -15,7 +15,8 @@ enum class Profile { Eager, Optimized, MIGraphX, - DirectML + DirectML, + Llm }; struct ProviderInfo { diff --git a/src/amdgpu/gpu_options.h b/src/amdgpu/gpu_options.h index 63d5181..558ea5f 100644 --- a/src/amdgpu/gpu_options.h +++ b/src/amdgpu/gpu_options.h @@ -10,6 +10,7 @@ namespace gpu_ep { constexpr auto kDirectMLBackend = "directml"; constexpr auto kMIGraphXBackend = "migraphx"; +constexpr auto kHipepBackend = "hipep"; namespace provider_option { constexpr auto kDeviceId = "device_id"sv; From cf42a92b67b647e2ec17cf68e21af9e53ef61f58 Mon Sep 17 00:00:00 2001 From: zhenzew Date: Tue, 16 Jun 2026 23:02:30 -0500 Subject: [PATCH 2/6] =?UTF-8?q?=EF=BB=BFrefactor(amdgpu):=20pass=20no=20de?= =?UTF-8?q?vice=20to=20the=20hipep=20backend,=20matching=20DirectML/MIGrap?= =?UTF-8?q?hX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hipep backend no longer requires the umbrella to forward the ORT-selected device: its CreateEp now tolerates a null device array / num_devices == 0 (ROCm/MorphiZen#234). Drop the devices/ep_metadata parameters from ProviderFactory::CreateHipepBackend and the ExecutionProvider constructor and pass nullptr/nullptr/0, so the hipep path matches the DirectML and MIGraphX backends and the EP constructor keeps the same signature as the sibling EPs. Co-authored-by: Cursor --- src/amdgpu/gpu_ep.cc | 5 +---- src/amdgpu/gpu_ep.h | 2 -- src/amdgpu/gpu_factory.cc | 5 ++--- src/amdgpu/gpu_factory.h | 9 ++------- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/amdgpu/gpu_ep.cc b/src/amdgpu/gpu_ep.cc index 1aa204e..f7f3f4e 100644 --- a/src/amdgpu/gpu_ep.cc +++ b/src/amdgpu/gpu_ep.cc @@ -36,8 +36,6 @@ namespace gpu_ep { ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view ep_name, - [[maybe_unused]] gsl::span devices, - [[maybe_unused]] gsl::span ep_metadata, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger) : OrtEp{ORT_API_VERSION}, ApiPtrs{factory.ort_api, factory.ep_api, factory.model_editor_api}, @@ -122,8 +120,7 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view // hipep manages allocator/data-transfer at the backend factory level, // reached through the amdgpu Allocator/DataTransfer wrappers — leave // OrtEp::CreateAllocator null so ORT falls back to ep_factory_.CreateAllocator. - THROW_IF_ERROR(factory.CreateHipepBackend(devices, ep_metadata, local_session_options, - logger, backend_ep_)); + THROW_IF_ERROR(factory.CreateHipepBackend(local_session_options, logger, backend_ep_)); }; const auto create_migraphx_backend = [&] { diff --git a/src/amdgpu/gpu_ep.h b/src/amdgpu/gpu_ep.h index 45a9a93..d8f0290 100644 --- a/src/amdgpu/gpu_ep.h +++ b/src/amdgpu/gpu_ep.h @@ -10,8 +10,6 @@ namespace gpu_ep { struct ExecutionProvider : OrtEp, ApiPtrs { ExecutionProvider(ProviderFactory& factory, std::string_view ep_name, - gsl::span devices, - gsl::span ep_metadata, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger); ~ExecutionProvider(); diff --git a/src/amdgpu/gpu_factory.cc b/src/amdgpu/gpu_factory.cc index 51ba153..6259052 100644 --- a/src/amdgpu/gpu_factory.cc +++ b/src/amdgpu/gpu_factory.cc @@ -238,7 +238,7 @@ Ort::Status ProviderFactory::GetSupportedDevices(const std::vector devices, - gsl::span ep_metadata, + gsl::span /* ep_metadata */, const Ort::ConstSessionOptions& session_options, const OrtLogger* logger, OrtEp* &ep) try { ep = nullptr; @@ -246,8 +246,7 @@ try { return MAKE_STATUS(ORT_INVALID_ARGUMENT, "only supports selection for a single device"); } - ep = std::make_unique(*this, ep_name_, devices, ep_metadata, - session_options, logger).release(); + ep = std::make_unique(*this, ep_name_, session_options, logger).release(); return STATUS_OK; } catch (const Ort::Exception& e) { return Ort::Status{e}; diff --git a/src/amdgpu/gpu_factory.h b/src/amdgpu/gpu_factory.h index 19ea8f3..d6be395 100644 --- a/src/amdgpu/gpu_factory.h +++ b/src/amdgpu/gpu_factory.h @@ -24,13 +24,8 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs { return STATUS_OK; } - // Unlike DirectML/MIGraphX, the hipep backend requires the selected - // hardware device(s) to be forwarded (its CreateEp rejects num_devices == 0). - Ort::Status CreateHipepBackend(gsl::span devices, - gsl::span ep_metadata, - const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) { - RETURN_IF_ERROR(hip_ep_factory_->CreateEp(hip_ep_factory_, devices.data(), - ep_metadata.data(), devices.size(), session_options, logger, &ep)); + Ort::Status CreateHipepBackend(const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) { + RETURN_IF_ERROR(hip_ep_factory_->CreateEp(hip_ep_factory_, nullptr, nullptr, 0, session_options, logger, &ep)); backend_ep_factory_ = hip_ep_factory_; return STATUS_OK; } From 3354a4b188567c332cf50987194bba4bc2ee9cea Mon Sep 17 00:00:00 2001 From: zhenzew Date: Wed, 17 Jun 2026 03:19:26 -0500 Subject: [PATCH 3/6] feat(hipep): add hipep-backend shim that loads the HIP EP DLL Add src/hipep parallel to directml/migraphx. It builds hipep-backend.dll, a thin pass-through OrtEpFactory that loads hipep.dll, forwards CreateEpFactories, and returns the HIP EP's factory unchanged so the AMD GPU umbrella forwards to it directly. ReleaseEpFactory forwards to the HIP EP and unloads the DLL. Only a single factory is supported. Wired via a new USE_HIPEP option (forced on by USE_AMDGPU) and add_subdirectory(hipep). Co-authored-by: Cursor --- CMakeLists.txt | 2 ++ src/CMakeLists.txt | 3 ++ src/hipep/CMakeLists.txt | 30 ++++++++++++++++++ src/hipep/hipep_factory.cc | 62 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 src/hipep/CMakeLists.txt create mode 100644 src/hipep/hipep_factory.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 92c399e..1394340 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,10 +39,12 @@ endif() option(USE_AMDGPU "Build the AMD GPU Execution Provider" OFF) option(USE_DML "Build the DirectML Execution Provider" OFF) option(USE_MIGRAPHX "Build the MIGraphX Execution Provider" OFF) +option(USE_HIPEP "Build the HIP (morphizen) backend shim" OFF) if(USE_AMDGPU) set(CACHE{USE_DML} TYPE BOOL FORCE VALUE ON) set(CACHE{USE_MIGRAPHX} TYPE BOOL FORCE VALUE ON) + set(CACHE{USE_HIPEP} TYPE BOOL FORCE VALUE ON) endif() add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7648cd2..aa2ac2a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,3 +167,6 @@ endif() if(USE_MIGRAPHX) add_subdirectory(migraphx) endif() +if(USE_HIPEP) + add_subdirectory(hipep) +endif() diff --git a/src/hipep/CMakeLists.txt b/src/hipep/CMakeLists.txt new file mode 100644 index 0000000..d4d9eae --- /dev/null +++ b/src/hipep/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT + +add_library(hipep-ep MODULE hipep_factory.cc) + +target_link_libraries(hipep-ep PRIVATE plugin-ep-utils) + +if(WIN32) + set_property(TARGET hipep-ep APPEND_STRING + PROPERTY LINK_FLAGS /DEF:${PROJECT_SOURCE_DIR}/src/shared/symbols.def) + + install(TARGETS hipep-ep + DESTINATION ".") + + install(FILES $ + DESTINATION "." OPTIONAL) +else() + set_property(TARGET hipep-ep APPEND_STRING + PROPERTY LINK_FLAGS "-Xlinker --version-script=${PROJECT_SOURCE_DIR}/src/shared/version_script.lds -Xlinker --gc-sections") + + install(TARGETS hipep-ep + DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + +set_target_properties(hipep-ep PROPERTIES OUTPUT_NAME "hipep-backend") + +add_version_info( + TARGET hipep-ep + DESCRIPTION "HIP Execution Provider - ONNX Runtime plugin" + PRODUCT "HIP Plugin EP") diff --git a/src/hipep/hipep_factory.cc b/src/hipep/hipep_factory.cc new file mode 100644 index 0000000..570f2e2 --- /dev/null +++ b/src/hipep/hipep_factory.cc @@ -0,0 +1,62 @@ +// Copyright (c) Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#include "common/dynamic_library.h" +#include "common/plugin_ep_utils.h" + +namespace { + +// The HIP EP ships as a separate prebuilt DLL. hipep-backend is a thin +// pass-through: it loads that DLL, forwards CreateEpFactories, and hands back +// its OrtEpFactory unchanged so the parent EP forwards to it directly. This +// presents a repo-built backend parallel to directml/migraphx while keeping the +// HIP EP external. The DLL search directory is set by whoever loads this shim +// (the AMD GPU umbrella, or the executable that registers it). +constexpr auto hipepLib{LIBRARY_PREFIX ORT_TSTR("hipep") LIBRARY_SUFFIX}; + +using CreateEpFactories_t = OrtStatus* (*)(const char*, const OrtApiBase*, const OrtLogger*, + OrtEpFactory**, size_t, size_t*); +using ReleaseEpFactory_t = OrtStatus* (*)(OrtEpFactory*); + +// hipep-backend only ever creates a single factory, so a single module handle +// plus release pointer is enough. +void* g_hipep_module{}; +ReleaseEpFactory_t g_hipep_release{}; + +} // namespace + +extern "C" { + +OrtStatus* CreateEpFactories(const char* registration_name, const OrtApiBase* ort_api_base, + const OrtLogger* default_logger, OrtEpFactory** factories, size_t max_factories, size_t* num_factories) +{ + try { + const OrtApi* ort_api{ort_api_base->GetApi(ORT_API_VERSION)}; + Ort::InitApi(ort_api); + + THROW_IF_ERROR(LoadDynamicLibrary(hipepLib, &g_hipep_module)); + + CreateEpFactories_t hipep_create{}; + THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "CreateEpFactories", + reinterpret_cast(&hipep_create))); + THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "ReleaseEpFactory", + reinterpret_cast(&g_hipep_release))); + + return hipep_create(registration_name, ort_api_base, default_logger, + factories, max_factories, num_factories); + } + catch (const std::exception& e) { + RETURN_STATUS(ORT_EP_FAIL, e.what()); + } +} + +OrtStatus* ReleaseEpFactory(OrtEpFactory* factory) { + OrtStatus* status = (g_hipep_release != nullptr) ? g_hipep_release(factory) : nullptr; + if (g_hipep_module != nullptr) { + UnloadDynamicLibrary(g_hipep_module); + g_hipep_module = nullptr; + } + return status; +} + +} // extern "C" From 3ba6ae62348ec8b1d100d456455201630388dd95 Mon Sep 17 00:00:00 2001 From: zhenzew Date: Wed, 17 Jun 2026 05:18:03 -0500 Subject: [PATCH 4/6] =?UTF-8?q?=EF=BB=BFfix(hipep):=20reference-count=20th?= =?UTF-8?q?e=20HIP=20EP=20DLL=20across=20CreateEpFactories?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CreateEpFactories can be invoked more than once (e.g. a real session plus the device-init session in OGA). The previous single-handle logic reloaded the DLL on each call (leaking the earlier handle) and unloaded it on the first ReleaseEpFactory while later factories were still live. Load on the first factory and unload only after the last is released; roll back the refcount if the load fails so a retry re-attempts it. Co-authored-by: Cursor Co-authored-by: Cursor --- src/hipep/hipep_factory.cc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/hipep/hipep_factory.cc b/src/hipep/hipep_factory.cc index 570f2e2..c14e6dd 100644 --- a/src/hipep/hipep_factory.cc +++ b/src/hipep/hipep_factory.cc @@ -1,6 +1,8 @@ // Copyright (c) Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT +#include + #include "common/dynamic_library.h" #include "common/plugin_ep_utils.h" @@ -18,10 +20,13 @@ using CreateEpFactories_t = OrtStatus* (*)(const char*, const OrtApiBase*, const OrtEpFactory**, size_t, size_t*); using ReleaseEpFactory_t = OrtStatus* (*)(OrtEpFactory*); -// hipep-backend only ever creates a single factory, so a single module handle -// plus release pointer is enough. +// CreateEpFactories may be called more than once (e.g. a real session plus a +// device-init session in OGA). Reference-count the underlying HIP EP DLL so it +// is loaded on the first factory and unloaded only after the last is released. void* g_hipep_module{}; +CreateEpFactories_t g_hipep_create{}; ReleaseEpFactory_t g_hipep_release{}; +std::atomic g_refcount{0}; } // namespace @@ -34,27 +39,31 @@ OrtStatus* CreateEpFactories(const char* registration_name, const OrtApiBase* or const OrtApi* ort_api{ort_api_base->GetApi(ORT_API_VERSION)}; Ort::InitApi(ort_api); - THROW_IF_ERROR(LoadDynamicLibrary(hipepLib, &g_hipep_module)); - - CreateEpFactories_t hipep_create{}; - THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "CreateEpFactories", - reinterpret_cast(&hipep_create))); - THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "ReleaseEpFactory", - reinterpret_cast(&g_hipep_release))); + if (g_refcount++ == 0) { + THROW_IF_ERROR(LoadDynamicLibrary(hipepLib, &g_hipep_module)); + THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "CreateEpFactories", + reinterpret_cast(&g_hipep_create))); + THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "ReleaseEpFactory", + reinterpret_cast(&g_hipep_release))); + } - return hipep_create(registration_name, ort_api_base, default_logger, + return g_hipep_create(registration_name, ort_api_base, default_logger, factories, max_factories, num_factories); } catch (const std::exception& e) { + // Roll back the refcount bump so a later retry re-attempts the load. + --g_refcount; RETURN_STATUS(ORT_EP_FAIL, e.what()); } } OrtStatus* ReleaseEpFactory(OrtEpFactory* factory) { OrtStatus* status = (g_hipep_release != nullptr) ? g_hipep_release(factory) : nullptr; - if (g_hipep_module != nullptr) { + if (--g_refcount == 0 && g_hipep_module != nullptr) { UnloadDynamicLibrary(g_hipep_module); g_hipep_module = nullptr; + g_hipep_create = nullptr; + g_hipep_release = nullptr; } return status; } From 71c00fbaf2540607888b00a12d8df5a0c1418904 Mon Sep 17 00:00:00 2001 From: zhenzew Date: Wed, 24 Jun 2026 05:51:15 -0500 Subject: [PATCH 5/6] refactor(amdgpu): rename hipep backend to hip Address PR review: the backend name must not contain "ep". Rename the umbrella backend shim from hipep to hip (src/hip/, hip-ep target, hip-backend.dll, USE_HIP option, and all C++ identifiers). The shim now loads the HIP EP DLL as hipgpu (hipgpu.dll / libhipgpu.so), to be renamed on the onnx-hipdnn-ep side in a follow-up. Co-authored-by: Cursor --- CMakeLists.txt | 4 +-- src/CMakeLists.txt | 4 +-- src/amdgpu/gpu_ep.cc | 8 ++--- src/amdgpu/gpu_factory.cc | 8 ++--- src/amdgpu/gpu_factory.h | 2 +- src/amdgpu/gpu_options.h | 2 +- src/{hipep => hip}/CMakeLists.txt | 18 +++++----- .../hipep_factory.cc => hip/hip_factory.cc} | 34 +++++++++---------- 8 files changed, 40 insertions(+), 40 deletions(-) rename src/{hipep => hip}/CMakeLists.txt (58%) rename src/{hipep/hipep_factory.cc => hip/hip_factory.cc} (64%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1394340..59b5a39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,12 +39,12 @@ endif() option(USE_AMDGPU "Build the AMD GPU Execution Provider" OFF) option(USE_DML "Build the DirectML Execution Provider" OFF) option(USE_MIGRAPHX "Build the MIGraphX Execution Provider" OFF) -option(USE_HIPEP "Build the HIP (morphizen) backend shim" OFF) +option(USE_HIP "Build the HIP (morphizen) backend shim" OFF) if(USE_AMDGPU) set(CACHE{USE_DML} TYPE BOOL FORCE VALUE ON) set(CACHE{USE_MIGRAPHX} TYPE BOOL FORCE VALUE ON) - set(CACHE{USE_HIPEP} TYPE BOOL FORCE VALUE ON) + set(CACHE{USE_HIP} TYPE BOOL FORCE VALUE ON) endif() add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa2ac2a..7526e72 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,6 +167,6 @@ endif() if(USE_MIGRAPHX) add_subdirectory(migraphx) endif() -if(USE_HIPEP) - add_subdirectory(hipep) +if(USE_HIP) + add_subdirectory(hip) endif() diff --git a/src/amdgpu/gpu_ep.cc b/src/amdgpu/gpu_ep.cc index f7f3f4e..a11c31d 100644 --- a/src/amdgpu/gpu_ep.cc +++ b/src/amdgpu/gpu_ep.cc @@ -116,11 +116,11 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view }; }; - const auto create_hipep_backend = [&] { - // hipep manages allocator/data-transfer at the backend factory level, + const auto create_hip_backend = [&] { + // hip backend manages allocator/data-transfer at the backend factory level, // reached through the amdgpu Allocator/DataTransfer wrappers — leave // OrtEp::CreateAllocator null so ORT falls back to ep_factory_.CreateAllocator. - THROW_IF_ERROR(factory.CreateHipepBackend(local_session_options, logger, backend_ep_)); + THROW_IF_ERROR(factory.CreateHipBackend(local_session_options, logger, backend_ep_)); }; const auto create_migraphx_backend = [&] { @@ -173,7 +173,7 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view } else if (info.profile == Profile::MIGraphX) { create_migraphx_backend(); } else if (info.profile == Profile::Llm) { - create_hipep_backend(); + create_hip_backend(); } else { create_migraphx_backend(); } diff --git a/src/amdgpu/gpu_factory.cc b/src/amdgpu/gpu_factory.cc index 6259052..2471322 100644 --- a/src/amdgpu/gpu_factory.cc +++ b/src/amdgpu/gpu_factory.cc @@ -47,7 +47,7 @@ namespace gpu_ep { namespace { constexpr auto directmlBackend{LIBRARY_PREFIX ORT_TSTR("directml-backend") LIBRARY_SUFFIX}; constexpr auto migraphxBackend{LIBRARY_PREFIX ORT_TSTR("migraphx-backend") LIBRARY_SUFFIX}; -constexpr auto hipepBackend{LIBRARY_PREFIX ORT_TSTR("hipep-backend") LIBRARY_SUFFIX}; +constexpr auto hipBackend{LIBRARY_PREFIX ORT_TSTR("hip-backend") LIBRARY_SUFFIX}; } ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_api_base, const char* ep_name, const OrtLogger* default_logger) @@ -146,7 +146,7 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_ THROW_IF_ERROR(mgx_create_ep_factories(kMIGraphXBackend, ort_api_base, default_logger, &mgx_ep_factory_, 1, &factories_created)); - THROW_IF_ERROR(LoadDynamicLibrary(hipepBackend, &hip_backend_)); + THROW_IF_ERROR(LoadDynamicLibrary(hipBackend, &hip_backend_)); THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, "ReleaseEpFactory", reinterpret_cast(&hip_release_ep_factory_))); @@ -154,7 +154,7 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_ THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, "CreateEpFactories", reinterpret_cast(&hip_create_ep_factories))); - // Pass ep_name_ so the hipep backend's EP reports the same name ORT sees. + // Pass ep_name_ so the hip backend's EP reports the same name ORT sees. THROW_IF_ERROR(hip_create_ep_factories(ep_name_.c_str(), ort_api_base, default_logger, &hip_ep_factory_, 1, &factories_created)); @@ -183,7 +183,7 @@ ProviderFactory::~ProviderFactory() { /* TODO: log failure while unloading MIGraphX EP library */ } if (!UnloadDynamicLibrary(hip_backend_).IsOK()) { - /* TODO: log failure while unloading hipep EP library */ + /* TODO: log failure while unloading hip EP library */ } } diff --git a/src/amdgpu/gpu_factory.h b/src/amdgpu/gpu_factory.h index d6be395..b3775e7 100644 --- a/src/amdgpu/gpu_factory.h +++ b/src/amdgpu/gpu_factory.h @@ -24,7 +24,7 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs { return STATUS_OK; } - Ort::Status CreateHipepBackend(const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) { + Ort::Status CreateHipBackend(const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) { RETURN_IF_ERROR(hip_ep_factory_->CreateEp(hip_ep_factory_, nullptr, nullptr, 0, session_options, logger, &ep)); backend_ep_factory_ = hip_ep_factory_; return STATUS_OK; diff --git a/src/amdgpu/gpu_options.h b/src/amdgpu/gpu_options.h index 558ea5f..7f91338 100644 --- a/src/amdgpu/gpu_options.h +++ b/src/amdgpu/gpu_options.h @@ -10,7 +10,7 @@ namespace gpu_ep { constexpr auto kDirectMLBackend = "directml"; constexpr auto kMIGraphXBackend = "migraphx"; -constexpr auto kHipepBackend = "hipep"; +constexpr auto kHipBackend = "hip"; namespace provider_option { constexpr auto kDeviceId = "device_id"sv; diff --git a/src/hipep/CMakeLists.txt b/src/hip/CMakeLists.txt similarity index 58% rename from src/hipep/CMakeLists.txt rename to src/hip/CMakeLists.txt index d4d9eae..70f1b3a 100644 --- a/src/hipep/CMakeLists.txt +++ b/src/hip/CMakeLists.txt @@ -1,30 +1,30 @@ # Copyright (c) Advanced Micro Devices, Inc. # SPDX-License-Identifier: MIT -add_library(hipep-ep MODULE hipep_factory.cc) +add_library(hip-ep MODULE hip_factory.cc) -target_link_libraries(hipep-ep PRIVATE plugin-ep-utils) +target_link_libraries(hip-ep PRIVATE plugin-ep-utils) if(WIN32) - set_property(TARGET hipep-ep APPEND_STRING + set_property(TARGET hip-ep APPEND_STRING PROPERTY LINK_FLAGS /DEF:${PROJECT_SOURCE_DIR}/src/shared/symbols.def) - install(TARGETS hipep-ep + install(TARGETS hip-ep DESTINATION ".") - install(FILES $ + install(FILES $ DESTINATION "." OPTIONAL) else() - set_property(TARGET hipep-ep APPEND_STRING + set_property(TARGET hip-ep APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker --version-script=${PROJECT_SOURCE_DIR}/src/shared/version_script.lds -Xlinker --gc-sections") - install(TARGETS hipep-ep + install(TARGETS hip-ep DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() -set_target_properties(hipep-ep PROPERTIES OUTPUT_NAME "hipep-backend") +set_target_properties(hip-ep PROPERTIES OUTPUT_NAME "hip-backend") add_version_info( - TARGET hipep-ep + TARGET hip-ep DESCRIPTION "HIP Execution Provider - ONNX Runtime plugin" PRODUCT "HIP Plugin EP") diff --git a/src/hipep/hipep_factory.cc b/src/hip/hip_factory.cc similarity index 64% rename from src/hipep/hipep_factory.cc rename to src/hip/hip_factory.cc index c14e6dd..8d4dc01 100644 --- a/src/hipep/hipep_factory.cc +++ b/src/hip/hip_factory.cc @@ -8,13 +8,13 @@ namespace { -// The HIP EP ships as a separate prebuilt DLL. hipep-backend is a thin +// The HIP EP ships as a separate prebuilt DLL. hip-backend is a thin // pass-through: it loads that DLL, forwards CreateEpFactories, and hands back // its OrtEpFactory unchanged so the parent EP forwards to it directly. This // presents a repo-built backend parallel to directml/migraphx while keeping the // HIP EP external. The DLL search directory is set by whoever loads this shim // (the AMD GPU umbrella, or the executable that registers it). -constexpr auto hipepLib{LIBRARY_PREFIX ORT_TSTR("hipep") LIBRARY_SUFFIX}; +constexpr auto hipLib{LIBRARY_PREFIX ORT_TSTR("hipgpu") LIBRARY_SUFFIX}; using CreateEpFactories_t = OrtStatus* (*)(const char*, const OrtApiBase*, const OrtLogger*, OrtEpFactory**, size_t, size_t*); @@ -23,9 +23,9 @@ using ReleaseEpFactory_t = OrtStatus* (*)(OrtEpFactory*); // CreateEpFactories may be called more than once (e.g. a real session plus a // device-init session in OGA). Reference-count the underlying HIP EP DLL so it // is loaded on the first factory and unloaded only after the last is released. -void* g_hipep_module{}; -CreateEpFactories_t g_hipep_create{}; -ReleaseEpFactory_t g_hipep_release{}; +void* g_hip_module{}; +CreateEpFactories_t g_hip_create{}; +ReleaseEpFactory_t g_hip_release{}; std::atomic g_refcount{0}; } // namespace @@ -40,14 +40,14 @@ OrtStatus* CreateEpFactories(const char* registration_name, const OrtApiBase* or Ort::InitApi(ort_api); if (g_refcount++ == 0) { - THROW_IF_ERROR(LoadDynamicLibrary(hipepLib, &g_hipep_module)); - THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "CreateEpFactories", - reinterpret_cast(&g_hipep_create))); - THROW_IF_ERROR(GetSymbolFromLibrary(g_hipep_module, "ReleaseEpFactory", - reinterpret_cast(&g_hipep_release))); + THROW_IF_ERROR(LoadDynamicLibrary(hipLib, &g_hip_module)); + THROW_IF_ERROR(GetSymbolFromLibrary(g_hip_module, "CreateEpFactories", + reinterpret_cast(&g_hip_create))); + THROW_IF_ERROR(GetSymbolFromLibrary(g_hip_module, "ReleaseEpFactory", + reinterpret_cast(&g_hip_release))); } - return g_hipep_create(registration_name, ort_api_base, default_logger, + return g_hip_create(registration_name, ort_api_base, default_logger, factories, max_factories, num_factories); } catch (const std::exception& e) { @@ -58,12 +58,12 @@ OrtStatus* CreateEpFactories(const char* registration_name, const OrtApiBase* or } OrtStatus* ReleaseEpFactory(OrtEpFactory* factory) { - OrtStatus* status = (g_hipep_release != nullptr) ? g_hipep_release(factory) : nullptr; - if (--g_refcount == 0 && g_hipep_module != nullptr) { - UnloadDynamicLibrary(g_hipep_module); - g_hipep_module = nullptr; - g_hipep_create = nullptr; - g_hipep_release = nullptr; + OrtStatus* status = (g_hip_release != nullptr) ? g_hip_release(factory) : nullptr; + if (--g_refcount == 0 && g_hip_module != nullptr) { + UnloadDynamicLibrary(g_hip_module); + g_hip_module = nullptr; + g_hip_create = nullptr; + g_hip_release = nullptr; } return status; } From daa120c415b00d52a59add8a7328221b4d25f4ff Mon Sep 17 00:00:00 2001 From: zhenzew Date: Wed, 17 Jun 2026 01:11:37 -0500 Subject: [PATCH 6/6] build: make DirectML/MIGraphX optional to build amdgpu without a MIGraphX SDK [do not merge] NOT FOR MERGE - local build/test scaffolding, stacked on the hipep backend PR. USE_AMDGPU normally force-enables USE_DML and USE_MIGRAPHX, migraphx-ep runs find_package(migraphx REQUIRED), and ProviderFactory unconditionally loads the DirectML and MIGraphX backend DLLs - so the umbrella can't build/run on a machine without a MIGraphX SDK. Make DML/MIGraphX opt-in so the hipep (profile=llm) path can be reproduced and tested locally: - USE_AMDGPU forces USE_DML / USE_MIGRAPHX OFF. - amdgpu-ep guards the migraphx-ep / directml-ep include directories behind USE_MIGRAPHX / USE_DML and passes USE_DML / USE_MIGRAPHX compile defs. - gpu_factory.cc / gpu_ep.cc guard the DirectML and MIGraphX backend loads and profile branches behind #ifdef USE_DML / USE_MIGRAPHX (the hipep backend stays unconditional). Local repro: build with --use_amdgpu, place hipep-backend.dll next to amdgpu-ep, then run a model with provider option profile=llm. Co-authored-by: Cursor --- CMakeLists.txt | 4 +-- src/amdgpu/CMakeLists.txt | 16 ++++++++--- src/amdgpu/gpu_ep.cc | 32 +++++++++++++++++---- src/amdgpu/gpu_factory.cc | 60 ++++++++++++++++++++++++--------------- 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59b5a39..ace4a40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,8 @@ option(USE_MIGRAPHX "Build the MIGraphX Execution Provider" OFF) option(USE_HIP "Build the HIP (morphizen) backend shim" OFF) if(USE_AMDGPU) - set(CACHE{USE_DML} TYPE BOOL FORCE VALUE ON) - set(CACHE{USE_MIGRAPHX} TYPE BOOL FORCE VALUE ON) + set(CACHE{USE_DML} TYPE BOOL FORCE VALUE OFF) + set(CACHE{USE_MIGRAPHX} TYPE BOOL FORCE VALUE OFF) set(CACHE{USE_HIP} TYPE BOOL FORCE VALUE ON) endif() diff --git a/src/amdgpu/CMakeLists.txt b/src/amdgpu/CMakeLists.txt index f1b1e83..e3e85be 100644 --- a/src/amdgpu/CMakeLists.txt +++ b/src/amdgpu/CMakeLists.txt @@ -21,11 +21,19 @@ add_library(amdgpu-ep MODULE target_link_libraries(amdgpu-ep PRIVATE plugin-ep-utils flatbuffers) -target_include_directories(amdgpu-ep PRIVATE - $) +if(USE_MIGRAPHX) + target_include_directories(amdgpu-ep PRIVATE + $) +endif() + +if(USE_DML) + target_include_directories(amdgpu-ep PRIVATE + $) +endif() -target_include_directories(amdgpu-ep PRIVATE - $) +target_compile_definitions(amdgpu-ep PRIVATE + $<$:USE_DML> + $<$:USE_MIGRAPHX>) if(WIN32) set_property(TARGET amdgpu-ep APPEND_STRING diff --git a/src/amdgpu/gpu_ep.cc b/src/amdgpu/gpu_ep.cc index a11c31d..9a99abb 100644 --- a/src/amdgpu/gpu_ep.cc +++ b/src/amdgpu/gpu_ep.cc @@ -5,7 +5,9 @@ #include "gpu_ep.h" #include "gpu_options.h" +#ifdef USE_MIGRAPHX #include "mgx_options.h" +#endif #define EP_CALL_T(backend, fn, defval, ...) \ do { \ @@ -123,6 +125,7 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view THROW_IF_ERROR(factory.CreateHipBackend(local_session_options, logger, backend_ep_)); }; +#ifdef USE_MIGRAPHX const auto create_migraphx_backend = [&] { const auto get_name = [](const std::string_view sv) { return std::string{"ep."}.append(kMIGraphXBackend).append(".").append(sv); @@ -165,17 +168,34 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view } THROW_IF_ERROR(factory.CreateMIGraphXBackend(local_session_options, logger, backend_ep_)); }; +#endif - if (info.profile == Profile::Eager) { + bool backend_created = false; + if (info.profile == Profile::Eager || info.profile == Profile::DirectML) { create_directml_backend(); - } else if (info.profile == Profile::DirectML) { - create_directml_backend(); - } else if (info.profile == Profile::MIGraphX) { + backend_created = true; + } +#ifdef USE_MIGRAPHX + if (!backend_created && info.profile == Profile::MIGraphX) { create_migraphx_backend(); - } else if (info.profile == Profile::Llm) { + backend_created = true; + } +#endif + if (!backend_created && info.profile == Profile::Llm) { create_hip_backend(); - } else { + backend_created = true; + } +#ifdef USE_MIGRAPHX + if (!backend_created) { create_migraphx_backend(); + backend_created = true; + } +#endif + if (!backend_created) { + ort_api.ReleaseSessionOptions(local_session_options); + THROW_IF_ERROR(MAKE_STATUS(ORT_EP_FAIL, + "amdgpu EP: no backend available for the requested profile " + "(check build flags USE_DML/USE_MIGRAPHX)")); } ort_api.ReleaseSessionOptions(local_session_options); } diff --git a/src/amdgpu/gpu_factory.cc b/src/amdgpu/gpu_factory.cc index 2471322..8a16c0d 100644 --- a/src/amdgpu/gpu_factory.cc +++ b/src/amdgpu/gpu_factory.cc @@ -119,32 +119,41 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_ API_CALL_S(ProviderFactory, this_, GetCustomOpDomains, domains, num_domains); }; - THROW_IF_ERROR(LoadDynamicLibrary(directmlBackend, &dml_backend_)); - THROW_IF_ERROR(GetSymbolFromLibrary(dml_backend_, - "ReleaseEpFactory", reinterpret_cast(&dml_release_ep_factory_))); - - CreateEpFactories_t dml_create_ep_factories{}; - THROW_IF_ERROR(GetSymbolFromLibrary(dml_backend_, - "CreateEpFactories", reinterpret_cast(&dml_create_ep_factories))); - - size_t factories_created{}; - // Pass ep_name_ (e.g. "amdgpu") so the directml backend registers its kernels, - // allocators, and node assignments under the same name ORT sees for this EP. - // Using kDirectMLBackend ("directml") would cause a provider name mismatch: - // ORT would look up kernels under "amdgpu" but find them stamped as "directml". - THROW_IF_ERROR(dml_create_ep_factories(ep_name_.c_str(), ort_api_base, default_logger, - &dml_ep_factory_, 1, &factories_created)); +#ifdef USE_DML + { + THROW_IF_ERROR(LoadDynamicLibrary(directmlBackend, &dml_backend_)); + THROW_IF_ERROR(GetSymbolFromLibrary(dml_backend_, + "ReleaseEpFactory", reinterpret_cast(&dml_release_ep_factory_))); + + CreateEpFactories_t dml_create_ep_factories{}; + THROW_IF_ERROR(GetSymbolFromLibrary(dml_backend_, + "CreateEpFactories", reinterpret_cast(&dml_create_ep_factories))); + + size_t factories_created{}; + // Pass ep_name_ (e.g. "amdgpu") so the directml backend registers its kernels, + // allocators, and node assignments under the same name ORT sees for this EP. + // Using kDirectMLBackend ("directml") would cause a provider name mismatch: + // ORT would look up kernels under "amdgpu" but find them stamped as "directml". + THROW_IF_ERROR(dml_create_ep_factories(ep_name_.c_str(), ort_api_base, default_logger, + &dml_ep_factory_, 1, &factories_created)); + } +#endif - THROW_IF_ERROR(LoadDynamicLibrary(migraphxBackend, &mgx_backend_)); - THROW_IF_ERROR(GetSymbolFromLibrary(mgx_backend_, - "ReleaseEpFactory", reinterpret_cast(&mgx_release_ep_factory_))); +#ifdef USE_MIGRAPHX + { + THROW_IF_ERROR(LoadDynamicLibrary(migraphxBackend, &mgx_backend_)); + THROW_IF_ERROR(GetSymbolFromLibrary(mgx_backend_, + "ReleaseEpFactory", reinterpret_cast(&mgx_release_ep_factory_))); - CreateEpFactories_t mgx_create_ep_factories{}; - THROW_IF_ERROR(GetSymbolFromLibrary(mgx_backend_, - "CreateEpFactories", reinterpret_cast(&mgx_create_ep_factories))); + CreateEpFactories_t mgx_create_ep_factories{}; + THROW_IF_ERROR(GetSymbolFromLibrary(mgx_backend_, + "CreateEpFactories", reinterpret_cast(&mgx_create_ep_factories))); - THROW_IF_ERROR(mgx_create_ep_factories(kMIGraphXBackend, ort_api_base, default_logger, - &mgx_ep_factory_, 1, &factories_created)); + size_t factories_created{}; + THROW_IF_ERROR(mgx_create_ep_factories(kMIGraphXBackend, ort_api_base, default_logger, + &mgx_ep_factory_, 1, &factories_created)); + } +#endif THROW_IF_ERROR(LoadDynamicLibrary(hipBackend, &hip_backend_)); THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, @@ -154,6 +163,7 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_ THROW_IF_ERROR(GetSymbolFromLibrary(hip_backend_, "CreateEpFactories", reinterpret_cast(&hip_create_ep_factories))); + size_t factories_created{}; // Pass ep_name_ so the hip backend's EP reports the same name ORT sees. THROW_IF_ERROR(hip_create_ep_factories(ep_name_.c_str(), ort_api_base, default_logger, &hip_ep_factory_, 1, &factories_created)); @@ -176,12 +186,16 @@ ProviderFactory::~ProviderFactory() { if (pinned_memory_info_) { ort_api.ReleaseMemoryInfo(pinned_memory_info_); } +#ifdef USE_DML if (!UnloadDynamicLibrary(dml_backend_).IsOK()) { /* TODO: log failure while unloading DirectML EP library */ } +#endif +#ifdef USE_MIGRAPHX if (!UnloadDynamicLibrary(mgx_backend_).IsOK()) { /* TODO: log failure while unloading MIGraphX EP library */ } +#endif if (!UnloadDynamicLibrary(hip_backend_).IsOK()) { /* TODO: log failure while unloading hip EP library */ }