[llvm] [OFFLOAD] Support host plugin on Windows (PR #180401)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 8 02:24:24 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-offload

Author: Alex Duran (adurang)

<details>
<summary>Changes</summary>

Changes to make host plugin compile on Windows:
* Change IO code to be portable
* Adjust Makefiles

Allow plugin to work partially when libffi support is not found dynamically (compilation works fine even on Windows because of the wrapper support).

---
Full diff: https://github.com/llvm/llvm-project/pull/180401.diff


3 Files Affected:

- (modified) offload/CMakeLists.txt (-5) 
- (modified) offload/plugins-nextgen/host/CMakeLists.txt (+7-2) 
- (modified) offload/plugins-nextgen/host/src/rtl.cpp (+42-32) 


``````````diff
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 81e246d9f8892..75a1bb435916b 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -158,11 +158,6 @@ if(LIBOMPTARGET_PLUGINS_TO_BUILD STREQUAL "all")
   set(LIBOMPTARGET_PLUGINS_TO_BUILD ${LIBOMPTARGET_ALL_PLUGIN_TARGETS})
 endif()
 
-if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-   "host" IN_LIST LIBOMPTARGET_PLUGINS_TO_BUILD)
-  message(STATUS "Not building host plugin: only Linux systems are supported")
-  list(REMOVE_ITEM LIBOMPTARGET_PLUGINS_TO_BUILD "host")
-endif()
 if(NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(ppc64le)|(aarch64)$"
         AND CMAKE_SYSTEM_NAME MATCHES "Linux"))
   if("amdgpu" IN_LIST LIBOMPTARGET_PLUGINS_TO_BUILD)
diff --git a/offload/plugins-nextgen/host/CMakeLists.txt b/offload/plugins-nextgen/host/CMakeLists.txt
index 26750bd62d406..e1d66b67cbb53 100644
--- a/offload/plugins-nextgen/host/CMakeLists.txt
+++ b/offload/plugins-nextgen/host/CMakeLists.txt
@@ -1,10 +1,15 @@
+if(WIN32)
+set(supported_targets AMD64 IA64 ARM64 EM64T X86)
+else()
 set(supported_targets x86_64 aarch64 ppc64 ppc64le riscv64 s390x loongarch64)
-if(NOT ${CMAKE_SYSTEM_PROCESSOR} IN_LIST supported_targets)
+endif()
+
+set(machine ${CMAKE_SYSTEM_PROCESSOR})
+if(NOT ${machine} IN_LIST supported_targets)
   message(STATUS "Not building ${machine} NextGen offloading plugin")
   return()
 endif()
 
-set(machine ${CMAKE_SYSTEM_PROCESSOR})
 if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le$")
   set(machine ppc64)
 endif()
diff --git a/offload/plugins-nextgen/host/src/rtl.cpp b/offload/plugins-nextgen/host/src/rtl.cpp
index 603379630ae8e..48e863afdee84 100644
--- a/offload/plugins-nextgen/host/src/rtl.cpp
+++ b/offload/plugins-nextgen/host/src/rtl.cpp
@@ -30,6 +30,8 @@
 #include "llvm/Frontend/OpenMP/OMPDeviceConstants.h"
 #include "llvm/Frontend/OpenMP/OMPGridValues.h"
 #include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
 
 #if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
     !defined(__ORDER_BIG_ENDIAN__)
@@ -63,7 +65,8 @@ using namespace error;
 /// Class implementing kernel functionalities for GenELF64.
 struct GenELF64KernelTy : public GenericKernelTy {
   /// Construct the kernel with a name and an execution mode.
-  GenELF64KernelTy(const char *Name) : GenericKernelTy(Name), Func(nullptr) {}
+  GenELF64KernelTy(const char *Name, bool SupportsFFI)
+      : GenericKernelTy(Name), Func(nullptr), supportsFFI(SupportsFFI) {}
 
   /// Initialize the kernel.
   Error initImpl(GenericDeviceTy &Device, DeviceImageTy &Image) override {
@@ -97,6 +100,9 @@ struct GenELF64KernelTy : public GenericKernelTy {
                    uint32_t NumBlocks[3], KernelArgsTy &KernelArgs,
                    KernelLaunchParamsTy LaunchParams,
                    AsyncInfoWrapperTy &AsyncInfoWrapper) const override {
+    if (!supportsFFI)
+      return Plugin::error(ErrorCode::UNSUPPORTED,
+                           "libffi is not available, cannot launch kernel");
     // Create a vector of ffi_types, one per argument.
     SmallVector<ffi_type *, 16> ArgTypes(KernelArgs.NumArgs, &ffi_type_pointer);
     ffi_type **ArgTypesPtr = (ArgTypes.size()) ? &ArgTypes[0] : nullptr;
@@ -127,6 +133,8 @@ struct GenELF64KernelTy : public GenericKernelTy {
 private:
   /// The kernel function to execute.
   void (*Func)(void);
+  /// Whether this kernel supports FFI-based launch.
+  bool supportsFFI;
 };
 
 /// Class implementing the GenELF64 device images properties.
@@ -149,8 +157,9 @@ struct GenELF64DeviceImageTy : public DeviceImageTy {
 struct GenELF64DeviceTy : public GenericDeviceTy {
   /// Create the device with a specific id.
   GenELF64DeviceTy(GenericPluginTy &Plugin, int32_t DeviceId,
-                   int32_t NumDevices)
-      : GenericDeviceTy(Plugin, DeviceId, NumDevices, GenELF64GridValues) {}
+                   int32_t NumDevices, bool SupportsFFI)
+      : GenericDeviceTy(Plugin, DeviceId, NumDevices, GenELF64GridValues),
+        supportsFFI(SupportsFFI) {}
 
   ~GenELF64DeviceTy() {}
 
@@ -182,7 +191,7 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
       return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
                            "failed to allocate memory for GenELF64 kernel");
 
-    new (GenELF64Kernel) GenELF64KernelTy(Name);
+    new (GenELF64Kernel) GenELF64KernelTy(Name, supportsFFI);
 
     return *GenELF64Kernel;
   }
@@ -198,37 +207,30 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
     GenELF64DeviceImageTy *Image = Plugin.allocate<GenELF64DeviceImageTy>();
     new (Image) GenELF64DeviceImageTy(ImageId, *this, std::move(TgtImage));
 
-    // Create a temporary file.
-    char TmpFileName[] = "/tmp/tmpfile_XXXXXX";
-    int TmpFileFd = mkstemp(TmpFileName);
-    if (TmpFileFd == -1)
-      return Plugin::error(ErrorCode::HOST_IO,
-                           "failed to create tmpfile for loading target image");
-
-    // Open the temporary file.
-    FILE *TmpFile = fdopen(TmpFileFd, "wb");
-    if (!TmpFile)
-      return Plugin::error(ErrorCode::HOST_IO,
-                           "failed to open tmpfile %s for loading target image",
-                           TmpFileName);
+    SmallString<128> TmpFileName;
+    int TmpFileFd;
+    if (auto EC = llvm::sys::fs::createTemporaryFile("tmpfile", "tmp",
+                                                     TmpFileFd, TmpFileName))
+      return Plugin::error(
+          ErrorCode::HOST_IO,
+          "failed to create tmpfile for loading target image: %s",
+          EC.message().c_str());
 
     // Write the image into the temporary file.
-    size_t Written = fwrite(Image->getStart(), Image->getSize(), 1, TmpFile);
-    if (Written != 1)
-      return Plugin::error(ErrorCode::HOST_IO,
-                           "failed to write target image to tmpfile %s",
-                           TmpFileName);
+    llvm::raw_fd_ostream TmpFile(TmpFileFd, /*shouldClose=*/true);
+    TmpFile.write(static_cast<const char *>(Image->getStart()),
+                  Image->getSize());
+    TmpFile.close();
 
-    // Close the temporary file.
-    int Ret = fclose(TmpFile);
-    if (Ret)
+    if (TmpFile.has_error())
       return Plugin::error(ErrorCode::HOST_IO,
-                           "failed to close tmpfile %s with the target image",
-                           TmpFileName);
+                           "failed to write target image to tmpfile %s",
+                           TmpFileName.c_str());
 
     // Load the temporary file as a dynamic library.
     std::string ErrMsg;
-    DynamicLibrary DynLib = DynamicLibrary::getLibrary(TmpFileName, &ErrMsg);
+    DynamicLibrary DynLib =
+        DynamicLibrary::getLibrary(TmpFileName.c_str(), &ErrMsg);
 
     // Check if the loaded library is valid.
     if (!DynLib.isValid())
@@ -405,6 +407,9 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
       1, // GV_Max_WG_Size
       1, // GV_Default_WG_Size
   };
+
+  /// Whether this device supports FFI-based launch.
+  bool supportsFFI;
 };
 
 class GenELF64GlobalHandlerTy final : public GenericGlobalHandlerTy {
@@ -441,12 +446,13 @@ struct GenELF64PluginTy final : public GenericPluginTy {
   /// This class should not be copied.
   GenELF64PluginTy(const GenELF64PluginTy &) = delete;
   GenELF64PluginTy(GenELF64PluginTy &&) = delete;
-
   /// Initialize the plugin and return the number of devices.
   Expected<int32_t> initImpl() override {
 #ifdef USES_DYNAMIC_FFI
-    if (auto Err = Plugin::check(ffi_init(), "failed to initialize libffi"))
-      return std::move(Err);
+    SupportsFFI = ffi_init() == FFI_OK ? true : false;
+    if (!SupportsFFI)
+      ODBG(OLDT_Init) << "libffi is not available, kernels will not be launched "
+                         "through libffi, and some features may be unavailable";
 #endif
     ODBG(OLDT_Init) << "GenELF64 plugin detected " << ODBG_IF_LEVEL(2)
                     << NUM_DEVICES << " " << ODBG_RESET_LEVEL() << "devices";
@@ -460,7 +466,7 @@ struct GenELF64PluginTy final : public GenericPluginTy {
   /// Creates a generic ELF device.
   GenericDeviceTy *createDevice(GenericPluginTy &Plugin, int32_t DeviceId,
                                 int32_t NumDevices) override {
-    return new GenELF64DeviceTy(Plugin, DeviceId, NumDevices);
+    return new GenELF64DeviceTy(Plugin, DeviceId, NumDevices, SupportsFFI);
   }
 
   /// Creates a generic global handler.
@@ -510,6 +516,10 @@ struct GenELF64PluginTy final : public GenericPluginTy {
   }
 
   const char *getName() const override { return GETNAME(TARGET_NAME); }
+
+private:
+  /// Whether this plugin supports FFI-based launch.
+  bool SupportsFFI = true;
 };
 
 template <typename... ArgsTy>

``````````

</details>


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


More information about the llvm-commits mailing list