[libc-commits] [libc] [llvm] [libc][GPU] Use CMAKE_CROSSCOMPILING_EMULATOR instead of custom GPU loader (PR #189417)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Mon Mar 30 08:55:40 PDT 2026
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/189417
>From af0c4d3eb8aadaa6cf6fa9c73f796d113aeb39de Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 30 Mar 2026 10:52:51 -0500
Subject: [PATCH] [libc][GPU] Use CMAKE_CROSSCOMPILING_EMULATOR instead of
custom GPU loader
Replace the custom `libc.utils.gpu.loader` target and
`LIBC_GPU_LOADER_EXECUTABLE` cache variable with the standard CMake
`CMAKE_CROSSCOMPILING_EMULATOR` mechanism.
For GPU runtime targets (amdgcn, nvptx64), the runtimes build now
automatically passes `-DCMAKE_CROSSCOMPILING_EMULATOR=.../llvm-gpu-loader`
to the sub-build. The libc test rules already expanded
`${CMAKE_CROSSCOMPILING_EMULATOR}` in their command lines, so the GPU
loader is picked up without any GPU-specific conditional logic.
This works because libc uses `add_custom_target`/`add_custom_command`
for test execution rather than `add_test()`, so the variable is a plain
string expansion that does not depend on `CMAKE_CROSSCOMPILING` being
true.
Made-with: Cursor
---
libc/cmake/modules/LLVMLibCTestRules.cmake | 15 +--------------
.../cmake/modules/prepare_libc_gpu_build.cmake | 18 ------------------
libc/docs/gpu/building.rst | 7 ++++---
libc/docs/gpu/testing.rst | 2 +-
libc/test/CMakeLists.txt | 9 ++-------
libc/test/lit.site.cfg.py.in | 8 ++++----
llvm/runtimes/CMakeLists.txt | 10 +++++++++-
7 files changed, 21 insertions(+), 48 deletions(-)
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index e25f739408b99..6d381194d5ed9 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -625,12 +625,6 @@ function(add_integration_test test_name)
libc.test.IntegrationTest.test
${INTEGRATION_TEST_DEPENDS})
- # Tests on the GPU require an external loader utility to launch the kernel.
- if(TARGET libc.utils.gpu.loader)
- add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
- get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
- endif()
-
# We have to use a separate var to store the command as a list because
# the COMMAND option of `add_custom_target` cannot handle empty vars in the
# command. For example, if INTEGRATION_TEST_ENV is empty, the actual
@@ -640,7 +634,6 @@ function(add_integration_test test_name)
set(test_cmd
${INTEGRATION_TEST_ENV}
$<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>:LIBOMPTARGET_STACK_SIZE=3072>
- $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}>
${CMAKE_CROSSCOMPILING_EMULATOR}
${INTEGRATION_TEST_LOADER_ARGS}
$<TARGET_FILE:${fq_build_target_name}> ${INTEGRATION_TEST_ARGS})
@@ -878,12 +871,6 @@ function(add_libc_hermetic test_name)
)
endif()
- # Tests on the GPU require an external loader utility to launch the kernel.
- if(TARGET libc.utils.gpu.loader)
- add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
- get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
- endif()
-
if(NOT HERMETIC_TEST_NO_RUN_POSTBUILD)
if (LIBC_TEST_CMD)
# In the form of "<command> binary=@BINARY@", e.g. "qemu-system-arm -loader$<COMMA>file=@BINARY@"
@@ -892,7 +879,7 @@ function(add_libc_hermetic test_name)
else()
set(test_cmd ${HERMETIC_TEST_ENV}
$<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>:LIBOMPTARGET_STACK_SIZE=3072>
- $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}> ${CMAKE_CROSSCOMPILING_EMULATOR} ${HERMETIC_TEST_LOADER_ARGS}
+ ${CMAKE_CROSSCOMPILING_EMULATOR} ${HERMETIC_TEST_LOADER_ARGS}
$<TARGET_FILE:${fq_build_target_name}> ${HERMETIC_TEST_ARGS})
endif()
diff --git a/libc/cmake/modules/prepare_libc_gpu_build.cmake b/libc/cmake/modules/prepare_libc_gpu_build.cmake
index fcf0e38db81af..c87a1df926c85 100644
--- a/libc/cmake/modules/prepare_libc_gpu_build.cmake
+++ b/libc/cmake/modules/prepare_libc_gpu_build.cmake
@@ -66,24 +66,6 @@ else()
endif()
set(LIBC_GPU_TARGET_ARCHITECTURE "${gpu_test_architecture}")
-# Identify the GPU loader utility used to run tests.
-set(LIBC_GPU_LOADER_EXECUTABLE "" CACHE STRING "Executable for the GPU loader.")
-if(LIBC_GPU_LOADER_EXECUTABLE)
- set(gpu_loader_executable ${LIBC_GPU_LOADER_EXECUTABLE})
-else()
- find_program(gpu_loader_executable
- NAMES llvm-gpu-loader NO_DEFAULT_PATH
- PATHS ${LLVM_BINARY_DIR}/bin ${compiler_path})
-endif()
-if(NOT TARGET libc.utils.gpu.loader AND gpu_loader_executable)
- add_custom_target(libc.utils.gpu.loader)
- set_target_properties(
- libc.utils.gpu.loader
- PROPERTIES
- EXECUTABLE "${gpu_loader_executable}"
- )
-endif()
-
# The AMDGPU environment uses different code objects to encode the ABI for
# kernel calls and intrinsic functions. We want to expose this to conform to
# whatever the test suite was built to handle.
diff --git a/libc/docs/gpu/building.rst b/libc/docs/gpu/building.rst
index d80ad0c0ff540..b8f5e79a430e3 100644
--- a/libc/docs/gpu/building.rst
+++ b/libc/docs/gpu/building.rst
@@ -195,6 +195,7 @@ standard runtime build.
commonly run out of resources if this is not constrained so it is recommended
to keep it low. The default value is a single thread.
-**LIBC_GPU_LOADER_EXECUTABLE**:STRING
- Overrides the default loader used for running GPU tests. If this is not
- provided the standard one will be built.
+**CMAKE_CROSSCOMPILING_EMULATOR**:STRING
+ Overrides the default loader used for running GPU tests. This is set
+ automatically to ``llvm-gpu-loader`` for GPU runtime targets when building
+ via the runtimes build.
diff --git a/libc/docs/gpu/testing.rst b/libc/docs/gpu/testing.rst
index 4115e68e5225a..c34467346b798 100644
--- a/libc/docs/gpu/testing.rst
+++ b/libc/docs/gpu/testing.rst
@@ -94,7 +94,7 @@ Running tests
Tests will only be built and run if a GPU target architecture is set and the
corresponding loader utility was built. These can be overridden with the
-``LIBC_GPU_TEST_ARCHITECTURE`` and ``LIBC_GPU_LOADER_EXECUTABLE`` :ref:`CMake
+``LIBC_GPU_TEST_ARCHITECTURE`` and ``CMAKE_CROSSCOMPILING_EMULATOR`` :ref:`CMake
options <gpu_cmake_options>`. Once built, they can be run like any other tests.
The CMake target depends on how the library was built.
diff --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index 60478739aced4..374756e77260e 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -16,11 +16,6 @@ add_custom_target(libc-hermetic-tests-build)
add_custom_target(libc-integration-tests-build)
add_custom_target(libc_include_tests-build)
-# Resolve the GPU loader executable path for the lit site config.
-if(TARGET libc.utils.gpu.loader)
- get_target_property(LIBC_GPU_LOADER_EXECUTABLE libc.utils.gpu.loader "EXECUTABLE")
-endif()
-
# Configure the site config file for lit
configure_lit_site_cfg(
${LIBC_SOURCE_DIR}/test/lit.site.cfg.py.in
@@ -34,7 +29,7 @@ configure_lit_site_cfg(
"LLVM_LIBS_DIR"
"LIBC_SOURCE_DIR"
"LIBC_BUILD_DIR"
- "LIBC_GPU_LOADER_EXECUTABLE"
+ "CMAKE_CROSSCOMPILING_EMULATOR"
)
add_lit_testsuite(check-libc-lit
@@ -46,7 +41,7 @@ add_lit_testsuite(check-libc-lit
add_subdirectory(UnitTest)
if(LIBC_TARGET_OS_IS_GPU)
- if(NOT TARGET libc.utils.gpu.loader)
+ if(NOT CMAKE_CROSSCOMPILING_EMULATOR)
message(WARNING "Cannot build libc GPU tests, missing loader.")
return()
elseif(LIBC_GPU_TESTS_DISABLED)
diff --git a/libc/test/lit.site.cfg.py.in b/libc/test/lit.site.cfg.py.in
index 7773bdfdf0e9c..7727f16956d73 100644
--- a/libc/test/lit.site.cfg.py.in
+++ b/libc/test/lit.site.cfg.py.in
@@ -8,11 +8,11 @@ config.llvm_tools_dir = lit_config.substitute(path(r"@LLVM_TOOLS_DIR@"))
config.libc_src_root = path(r"@LIBC_SOURCE_DIR@")
config.libc_obj_root = path(r"@LIBC_BUILD_DIR@")
config.libc_test_cmd = "@LIBC_TEST_CMD@"
-config.libc_gpu_loader = path(r"@LIBC_GPU_LOADER_EXECUTABLE@")
+config.libc_crosscompiling_emulator = path(r"@CMAKE_CROSSCOMPILING_EMULATOR@")
-# If running GPU tests and no explicit test command is set, use the GPU loader.
-if not config.libc_test_cmd and config.libc_gpu_loader:
- config.libc_test_cmd = config.libc_gpu_loader + " @BINARY@"
+# If no explicit test command is set, use the cross-compiling emulator.
+if not config.libc_test_cmd and config.libc_crosscompiling_emulator:
+ config.libc_test_cmd = config.libc_crosscompiling_emulator + " @BINARY@"
# Add libc's utils directory to the path so we can import the test format.
site.addsitedir(os.path.join(config.libc_src_root, "utils"))
diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index f22b551b89aca..a6e209a7ab204 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -674,9 +674,17 @@ if(build_runtimes)
check_apple_target(${name} runtime)
+ set(per_target_cmake_args)
+ if(LLVM_LIBC_GPU_BUILD AND TARGET llvm-gpu-loader
+ AND "${name}" MATCHES "^(amdgcn|nvptx64)")
+ list(APPEND per_target_cmake_args
+ "-DCMAKE_CROSSCOMPILING_EMULATOR=${LLVM_TOOLS_BINARY_DIR}/llvm-gpu-loader${CMAKE_EXECUTABLE_SUFFIX}")
+ endif()
+
runtime_register_target(${name}
DEPENDS ${builtins_dep_name} ${extra_deps}
- CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${extra_cmake_args}
+ CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name}
+ ${extra_cmake_args} ${per_target_cmake_args}
EXTRA_ARGS TARGET_TRIPLE ${name} ${extra_args})
endforeach()
More information about the libc-commits
mailing list