[llvm] [Offload] Add `--kernel <name>` command to `llvm-gpu-loader` (PR #213738)
Joseph Huber via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 11:58:01 PDT 2026
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/213738
>From 58c767fa3f3c95665e8dce3024fd4492ba21a8e5 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 3 Aug 2026 13:31:42 -0500
Subject: [PATCH 1/2] [Offload] Add `--kernel <name>` command to
`llvm-gpu-loader`
Summary:
This makes it easier to test a single function without opting-in to the
whole `crt1.o` infra for `libc` that was originally intended to test
existing CPU tests. Good for possible future unit tests, cheap tool that
can launch a kernel. Only provides `foo(void)` kernels for now, can be
improved.
---
.../tools/llvm-gpu-loader/llvm-gpu-loader.cpp | 30 +++++++++++++++----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
index 2747757e1c200..42b10c0a4b189 100644
--- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
+++ b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
@@ -65,6 +65,11 @@ static cl::alias Blocks("blocks", cl::aliasopt(BlocksX),
cl::desc("Alias for --blocks-x"),
cl::cat(LoaderCategory));
+static cl::list<std::string> Kernels(
+ "kernel", cl::value_desc("name"),
+ cl::desc("Launch '<name>(void)' instead of the 'main' entry point."),
+ cl::cat(LoaderCategory));
+
static cl::opt<std::string> File(cl::Positional, cl::Required,
cl::desc("<gpu executable>"),
cl::cat(LoaderCategory));
@@ -164,6 +169,11 @@ ol_device_handle_t getHostDevice() {
return Device;
}
+static bool hasKernel(ol_program_handle_t Program, const char *Name) {
+ ol_symbol_handle_t Kernel;
+ return !olGetSymbol(Program, Name, OL_SYMBOL_KIND_KERNEL, &Kernel);
+}
+
template <typename... Args>
void launchKernel(ol_queue_handle_t Queue, ol_device_handle_t Device,
ol_program_handle_t Program, const char *Name,
@@ -263,9 +273,12 @@ int main(int argc, const char **argv, const char **envp) {
OFFLOAD_ERR(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, sizeof(int), &DevRet));
OFFLOAD_ERR(olMemcpy(Queue, DevRet, Device, &Zero, Host, sizeof(int)));
+ // The '_begin' and '_end' kernels perform libc startup and teardown. Global
+ // constructors and destructors are handled automatically by the runtime.
ol_kernel_launch_size_args_t BeginLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
- launchKernel(Queue, Device, Program, "_begin", BeginLaunch, DevArgc, DevArgv,
- DevEnvp);
+ if (hasKernel(Program, "_begin"))
+ launchKernel(Queue, Device, Program, "_begin", BeginLaunch, DevArgc,
+ DevArgv, DevEnvp);
OFFLOAD_ERR(olSyncQueue(Queue));
uint32_t Dims = (BlocksZ > 1) ? 3 : (BlocksY > 1) ? 2 : 1;
@@ -273,11 +286,18 @@ int main(int argc, const char **argv, const char **envp) {
{BlocksX, BlocksY, BlocksZ},
{ThreadsX, ThreadsY, ThreadsZ},
/*SharedMemBytes=*/0};
- launchKernel(Queue, Device, Program, "_start", StartLaunch, DevArgc, DevArgv,
- DevEnvp, DevRet);
+ if (Kernels.empty()) {
+ launchKernel(Queue, Device, Program, "_start", StartLaunch, DevArgc,
+ DevArgv, DevEnvp, DevRet);
+ } else {
+ // Launch the user-specified kernels in order. These must take no arguments.
+ for (const std::string &Kernel : Kernels)
+ launchKernel(Queue, Device, Program, Kernel.c_str(), StartLaunch);
+ }
ol_kernel_launch_size_args_t EndLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
- launchKernel(Queue, Device, Program, "_end", EndLaunch);
+ if (hasKernel(Program, "_end"))
+ launchKernel(Queue, Device, Program, "_end", EndLaunch);
int Ret;
OFFLOAD_ERR(olMemcpy(Queue, &Ret, Host, DevRet, Device, sizeof(int)));
>From a62efbd4680b56eebb65de3a3448f3138860e5b7 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 3 Aug 2026 13:57:43 -0500
Subject: [PATCH 2/2] commnets
---
.../tools/llvm-gpu-loader/llvm-gpu-loader.cpp | 33 ++++++++-----------
1 file changed, 13 insertions(+), 20 deletions(-)
diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
index 42b10c0a4b189..9505355e751ed 100644
--- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
+++ b/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp
@@ -169,11 +169,6 @@ ol_device_handle_t getHostDevice() {
return Device;
}
-static bool hasKernel(ol_program_handle_t Program, const char *Name) {
- ol_symbol_handle_t Kernel;
- return !olGetSymbol(Program, Name, OL_SYMBOL_KIND_KERNEL, &Kernel);
-}
-
template <typename... Args>
void launchKernel(ol_queue_handle_t Queue, ol_device_handle_t Device,
ol_program_handle_t Program, const char *Name,
@@ -273,31 +268,29 @@ int main(int argc, const char **argv, const char **envp) {
OFFLOAD_ERR(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, sizeof(int), &DevRet));
OFFLOAD_ERR(olMemcpy(Queue, DevRet, Device, &Zero, Host, sizeof(int)));
- // The '_begin' and '_end' kernels perform libc startup and teardown. Global
- // constructors and destructors are handled automatically by the runtime.
- ol_kernel_launch_size_args_t BeginLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
- if (hasKernel(Program, "_begin"))
- launchKernel(Queue, Device, Program, "_begin", BeginLaunch, DevArgc,
- DevArgv, DevEnvp);
- OFFLOAD_ERR(olSyncQueue(Queue));
-
uint32_t Dims = (BlocksZ > 1) ? 3 : (BlocksY > 1) ? 2 : 1;
ol_kernel_launch_size_args_t StartLaunch{Dims,
{BlocksX, BlocksY, BlocksZ},
{ThreadsX, ThreadsY, ThreadsZ},
/*SharedMemBytes=*/0};
- if (Kernels.empty()) {
- launchKernel(Queue, Device, Program, "_start", StartLaunch, DevArgc,
- DevArgv, DevEnvp, DevRet);
- } else {
+ if (!Kernels.empty()) {
// Launch the user-specified kernels in order. These must take no arguments.
for (const std::string &Kernel : Kernels)
launchKernel(Queue, Device, Program, Kernel.c_str(), StartLaunch);
- }
+ } else {
+ // The '_begin' and '_end' kernels perform libc startup and teardown. Global
+ // constructors and destructors are handled automatically by the runtime.
+ ol_kernel_launch_size_args_t BeginLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
+ launchKernel(Queue, Device, Program, "_begin", BeginLaunch, DevArgc,
+ DevArgv, DevEnvp);
+ OFFLOAD_ERR(olSyncQueue(Queue));
- ol_kernel_launch_size_args_t EndLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
- if (hasKernel(Program, "_end"))
+ launchKernel(Queue, Device, Program, "_start", StartLaunch, DevArgc,
+ DevArgv, DevEnvp, DevRet);
+
+ ol_kernel_launch_size_args_t EndLaunch{1, {1, 1, 1}, {1, 1, 1}, 0};
launchKernel(Queue, Device, Program, "_end", EndLaunch);
+ }
int Ret;
OFFLOAD_ERR(olMemcpy(Queue, &Ret, Host, DevRet, Device, sizeof(int)));
More information about the llvm-commits
mailing list