[libc-commits] [libc] [llvm] [LLVM] Port 'llvm-gpu-loader' to use LLVMOffload (PR #162739)

Artem Belevich via libc-commits libc-commits at lists.llvm.org
Fri Oct 24 16:01:04 PDT 2025


================
@@ -1,108 +1,177 @@
-//===-- Generic device loader interface -----------------------------------===//
+//===-- Dynamically loaded offload API ------------------------------------===//
 //
 // 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
 //
 //===----------------------------------------------------------------------===//
+//
+// Dynamically loads the API provided by the LLVMOffload library. We need to do
+// this dynamically because this tool is used before it is actually built and
+// should be provided even when the user did not specify the offload runtime.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
 #define LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
 
-#include <cstddef>
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-/// Generic launch parameters for configuration the number of blocks / threads.
-struct LaunchParameters {
-  uint32_t num_threads_x;
-  uint32_t num_threads_y;
-  uint32_t num_threads_z;
-  uint32_t num_blocks_x;
-  uint32_t num_blocks_y;
-  uint32_t num_blocks_z;
-};
-
-/// The arguments to the '_begin' kernel.
-struct begin_args_t {
-  int argc;
-  void *argv;
-  void *envp;
-};
-
-/// The arguments to the '_start' kernel.
-struct start_args_t {
-  int argc;
-  void *argv;
-  void *envp;
-  void *ret;
-};
-
-/// The arguments to the '_end' kernel.
-struct end_args_t {};
-
-/// Generic interface to load the \p image and launch execution of the _start
-/// kernel on the target device. Copies \p argc and \p argv to the device.
-/// Returns the final value of the `main` function on the device.
-#ifdef AMDHSA_SUPPORT
-int load_amdhsa(int argc, const char **argv, const char **evnp, void *image,
-                size_t size, const LaunchParameters &params,
-                bool print_resource_usage);
-#endif
-#ifdef NVPTX_SUPPORT
-int load_nvptx(int argc, const char **argv, const char **evnp, void *image,
-               size_t size, const LaunchParameters &params,
-               bool print_resource_usage);
-#endif
-
-/// Return \p V aligned "upwards" according to \p Align.
-template <typename V, typename A> inline V align_up(V val, A align) {
-  return ((val + V(align) - 1) / V(align)) * V(align);
-}
-
-/// Copy the system's argument vector to GPU memory allocated using \p alloc.
-template <typename Allocator>
-void *copy_argument_vector(int argc, const char **argv, Allocator alloc) {
-  size_t argv_size = sizeof(char *) * (argc + 1);
-  size_t str_size = 0;
-  for (int i = 0; i < argc; ++i)
-    str_size += strlen(argv[i]) + 1;
-
-  // We allocate enough space for a null terminated array and all the strings.
-  void *dev_argv = alloc(argv_size + str_size);
-  if (!dev_argv)
-    return nullptr;
-
-  // Store the strings linerally in the same memory buffer.
-  void *dev_str = reinterpret_cast<uint8_t *>(dev_argv) + argv_size;
-  for (int i = 0; i < argc; ++i) {
-    size_t size = strlen(argv[i]) + 1;
-    std::memcpy(dev_str, argv[i], size);
-    static_cast<void **>(dev_argv)[i] = dev_str;
-    dev_str = reinterpret_cast<uint8_t *>(dev_str) + size;
-  }
-
-  // Ensure the vector is null terminated.
-  reinterpret_cast<void **>(dev_argv)[argc] = nullptr;
-  return dev_argv;
-}
-
-/// Copy the system's environment to GPU memory allocated using \p alloc.
-template <typename Allocator>
-void *copy_environment(const char **envp, Allocator alloc) {
-  int envc = 0;
-  for (const char **env = envp; *env != 0; ++env)
-    ++envc;
-
-  return copy_argument_vector(envc, envp, alloc);
-}
-
-inline void handle_error_impl(const char *file, int32_t line, const char *msg) {
-  fprintf(stderr, "%s:%d:0: Error: %s\n", file, line, msg);
-  exit(EXIT_FAILURE);
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+
+typedef enum ol_alloc_type_t {
+  OL_ALLOC_TYPE_HOST = 0,
+  OL_ALLOC_TYPE_DEVICE = 1,
+  OL_ALLOC_TYPE_FORCE_UINT32 = 0x7fffffff
----------------
Artem-B wrote:

If the intent is to replicate the constants of autogenerated OffloadAPI.h then it actually raises more questions.

- why can't we use that header directly?
- if we can't use that header directly for some reason, how do we guarantee that the enums here match enums there?
- with OffloadAPI.h being generated, it's not present in the source tree, so replicating all idiosyncrasies of the generator does not really buy us anything other than more questions. IMO. We literally have nothing to be consistent with here.

If we do need to replicate parts of the OffloadAPI.h here, then there should be a very prominent comment pointing to where one can find the ground truth for these constants. Ideally we should add a note where we generate offloadAPI.h, too to remind us to change things here when the API gets updated. Bonus points for some guardrails for automatically catching the moment when this header starts to diverge, though I'm not sure how it can be done without having access to the OffloadApi.h

Perhaps we should just commit OffloadApi.h to the tree, and update it on API change. It will be less error prone than this indirect replication.


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


More information about the libc-commits mailing list