https://github.com/ScottTodd updated https://github.com/llvm/llvm-project/pull/209898
>From 81c581070eb82700ba431fad354b7ced801a712a Mon Sep 17 00:00:00 2001 From: Scott Todd <[email protected]> Date: Wed, 15 Jul 2026 11:44:12 -0700 Subject: [PATCH 1/4] [offload-arch] Fix amdgpu HIP DLL search path on Windows --- clang/tools/offload-arch/AMDGPUArchByHIP.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp index 9cfccf416f783..db4387db3c0c7 100644 --- a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp +++ b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp @@ -229,8 +229,19 @@ static void primeLibraryLoad(StringRef Path) { static HMODULE PinnedModule = nullptr; if (PinnedModule || !sys::path::is_absolute(Path)) return; + + // Other paths here use '/' for consistency, but LoadLibraryExW's altered + // search path needs '\\' to locate dependencies relative to the DLL. + // + // See https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw + // "If the string specifies a fully qualified path, the function searches only + // that path for the module. When specifying a path, be sure to use + // backslashes (\), not forward slashes (/)." + SmallString<256> NativePath; + sys::path::native(Path, NativePath, sys::path::Style::windows_backslash); + SmallVector<UTF16, 256> WPath; - if (!convertUTF8ToUTF16String(Path, WPath)) + if (!convertUTF8ToUTF16String(NativePath, WPath)) return; WPath.push_back(0); PinnedModule = LoadLibraryExW(reinterpret_cast<LPCWSTR>(WPath.data()), >From eb808f79208862569915d3018294735a699c9d05 Mon Sep 17 00:00:00 2001 From: Scott Todd <[email protected]> Date: Wed, 15 Jul 2026 13:32:07 -0700 Subject: [PATCH 2/4] Add a unit test for primeLibraryLoad. --- clang/tools/offload-arch/AMDGPUArchByHIP.cpp | 9 +++-- .../offload-arch/OffloadArchTest.cpp | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp index db4387db3c0c7..b75471fec1c88 100644 --- a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp +++ b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp @@ -221,9 +221,12 @@ static std::pair<std::string, bool> findNewestHIPDLL() { } #ifdef _WIN32 +using LoadLibraryExWFn = decltype(&::LoadLibraryExW); + // Pre-load DLL with LOAD_WITH_ALTERED_SEARCH_PATH so transitive deps // resolve from its directory. Pinned so getPermanentLibrary reuses it. -static void primeLibraryLoad(StringRef Path) { +void primeLibraryLoad(StringRef Path, + LoadLibraryExWFn Loader = &::LoadLibraryExW) { // One DLL primed per process; subsequent calls are no-ops. // Not thread-safe, but offload-arch is single-threaded. static HMODULE PinnedModule = nullptr; @@ -244,8 +247,8 @@ static void primeLibraryLoad(StringRef Path) { if (!convertUTF8ToUTF16String(NativePath, WPath)) return; WPath.push_back(0); - PinnedModule = LoadLibraryExW(reinterpret_cast<LPCWSTR>(WPath.data()), - nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); + PinnedModule = Loader(reinterpret_cast<LPCWSTR>(WPath.data()), nullptr, + LOAD_WITH_ALTERED_SEARCH_PATH); DWORD Err = GetLastError(); if (!PinnedModule && Verbose) WithColor::note() << "priming LoadLibraryExW failed for " << Path diff --git a/clang/unittests/offload-arch/OffloadArchTest.cpp b/clang/unittests/offload-arch/OffloadArchTest.cpp index 4b07af39a918a..e845e7c8b434d 100644 --- a/clang/unittests/offload-arch/OffloadArchTest.cpp +++ b/clang/unittests/offload-arch/OffloadArchTest.cpp @@ -13,10 +13,17 @@ #include <algorithm> #include <string> +#ifdef _WIN32 +#include <windows.h> +#endif + // Defined in AMDGPUArchByHIP.cpp (non-static, compiled into this test). #ifdef _WIN32 +using LoadLibraryExWFn = decltype(&::LoadLibraryExW); + bool compareVersions(llvm::StringRef A, llvm::StringRef B); llvm::SmallVector<std::string, 8> getCandidateBinPaths(llvm::StringRef ExeDir); +void primeLibraryLoad(llvm::StringRef Path, LoadLibraryExWFn Loader); #endif using namespace llvm; @@ -25,6 +32,37 @@ cl::opt<bool> Verbose("offload-arch-test-verbose", cl::Hidden, cl::init(false)); #ifdef _WIN32 +// --- primeLibraryLoad --- + +namespace { +std::wstring CapturedPath; +HANDLE CapturedFile; +DWORD CapturedFlags; + +HMODULE WINAPI mockLoadLibraryExW(LPCWSTR Path, HANDLE File, DWORD Flags) { + CapturedPath = Path; + CapturedFile = File; + CapturedFlags = Flags; + return reinterpret_cast<HMODULE>(1); +} +} // namespace + +TEST(PrimeLibraryLoad, UsesWindowsBackslashes) { + CapturedPath.clear(); + CapturedFile = reinterpret_cast<HANDLE>(1); + CapturedFlags = 0; + + primeLibraryLoad("C:/rocm\\bin/amdhip64_7.dll", mockLoadLibraryExW); + + // The underlying LoadLibraryExW function should be called with backslashes, + // not forward slashes to ensure that it can discover and load dependent + // DLLs in the same directory. + EXPECT_EQ(CapturedPath, L"C:\\rocm\\bin\\amdhip64_7.dll"); + EXPECT_EQ(CapturedPath.find(L'/'), std::wstring::npos); + EXPECT_EQ(CapturedFile, nullptr); + EXPECT_EQ(CapturedFlags, LOAD_WITH_ALTERED_SEARCH_PATH); +} + // --- compareVersions --- TEST(CompareVersions, HigherVersionWins) { >From 8c4adee01c76afbfaa8e894dfb4fabe90e73acbe Mon Sep 17 00:00:00 2001 From: Scott Todd <[email protected]> Date: Wed, 15 Jul 2026 14:05:54 -0700 Subject: [PATCH 3/4] Format --- clang/tools/offload-arch/AMDGPUArchByHIP.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp index b75471fec1c88..220fc81021fb7 100644 --- a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp +++ b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp @@ -236,7 +236,8 @@ void primeLibraryLoad(StringRef Path, // Other paths here use '/' for consistency, but LoadLibraryExW's altered // search path needs '\\' to locate dependencies relative to the DLL. // - // See https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw + // See + // https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw // "If the string specifies a fully qualified path, the function searches only // that path for the module. When specifying a path, be sure to use // backslashes (\), not forward slashes (/)." >From f214c2d7b0e5c810de31402fa1b36a68d11f8528 Mon Sep 17 00:00:00 2001 From: Scott Todd <[email protected]> Date: Mon, 20 Jul 2026 08:13:22 -0700 Subject: [PATCH 4/4] Revert "Add a unit test for primeLibraryLoad." This reverts commit eb808f79208862569915d3018294735a699c9d05. --- clang/tools/offload-arch/AMDGPUArchByHIP.cpp | 9 ++--- .../offload-arch/OffloadArchTest.cpp | 38 ------------------- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp index 220fc81021fb7..36c3c98002a31 100644 --- a/clang/tools/offload-arch/AMDGPUArchByHIP.cpp +++ b/clang/tools/offload-arch/AMDGPUArchByHIP.cpp @@ -221,12 +221,9 @@ static std::pair<std::string, bool> findNewestHIPDLL() { } #ifdef _WIN32 -using LoadLibraryExWFn = decltype(&::LoadLibraryExW); - // Pre-load DLL with LOAD_WITH_ALTERED_SEARCH_PATH so transitive deps // resolve from its directory. Pinned so getPermanentLibrary reuses it. -void primeLibraryLoad(StringRef Path, - LoadLibraryExWFn Loader = &::LoadLibraryExW) { +static void primeLibraryLoad(StringRef Path) { // One DLL primed per process; subsequent calls are no-ops. // Not thread-safe, but offload-arch is single-threaded. static HMODULE PinnedModule = nullptr; @@ -248,8 +245,8 @@ void primeLibraryLoad(StringRef Path, if (!convertUTF8ToUTF16String(NativePath, WPath)) return; WPath.push_back(0); - PinnedModule = Loader(reinterpret_cast<LPCWSTR>(WPath.data()), nullptr, - LOAD_WITH_ALTERED_SEARCH_PATH); + PinnedModule = LoadLibraryExW(reinterpret_cast<LPCWSTR>(WPath.data()), + nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); DWORD Err = GetLastError(); if (!PinnedModule && Verbose) WithColor::note() << "priming LoadLibraryExW failed for " << Path diff --git a/clang/unittests/offload-arch/OffloadArchTest.cpp b/clang/unittests/offload-arch/OffloadArchTest.cpp index e845e7c8b434d..4b07af39a918a 100644 --- a/clang/unittests/offload-arch/OffloadArchTest.cpp +++ b/clang/unittests/offload-arch/OffloadArchTest.cpp @@ -13,17 +13,10 @@ #include <algorithm> #include <string> -#ifdef _WIN32 -#include <windows.h> -#endif - // Defined in AMDGPUArchByHIP.cpp (non-static, compiled into this test). #ifdef _WIN32 -using LoadLibraryExWFn = decltype(&::LoadLibraryExW); - bool compareVersions(llvm::StringRef A, llvm::StringRef B); llvm::SmallVector<std::string, 8> getCandidateBinPaths(llvm::StringRef ExeDir); -void primeLibraryLoad(llvm::StringRef Path, LoadLibraryExWFn Loader); #endif using namespace llvm; @@ -32,37 +25,6 @@ cl::opt<bool> Verbose("offload-arch-test-verbose", cl::Hidden, cl::init(false)); #ifdef _WIN32 -// --- primeLibraryLoad --- - -namespace { -std::wstring CapturedPath; -HANDLE CapturedFile; -DWORD CapturedFlags; - -HMODULE WINAPI mockLoadLibraryExW(LPCWSTR Path, HANDLE File, DWORD Flags) { - CapturedPath = Path; - CapturedFile = File; - CapturedFlags = Flags; - return reinterpret_cast<HMODULE>(1); -} -} // namespace - -TEST(PrimeLibraryLoad, UsesWindowsBackslashes) { - CapturedPath.clear(); - CapturedFile = reinterpret_cast<HANDLE>(1); - CapturedFlags = 0; - - primeLibraryLoad("C:/rocm\\bin/amdhip64_7.dll", mockLoadLibraryExW); - - // The underlying LoadLibraryExW function should be called with backslashes, - // not forward slashes to ensure that it can discover and load dependent - // DLLs in the same directory. - EXPECT_EQ(CapturedPath, L"C:\\rocm\\bin\\amdhip64_7.dll"); - EXPECT_EQ(CapturedPath.find(L'/'), std::wstring::npos); - EXPECT_EQ(CapturedFile, nullptr); - EXPECT_EQ(CapturedFlags, LOAD_WITH_ALTERED_SEARCH_PATH); -} - // --- compareVersions --- TEST(CompareVersions, HigherVersionWins) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
