Skip to content

Commit 221b011

Browse files
authored
[LLVM] Make the GPU loader utilities an LLVM tool (#132096)
Summary: These tools `amdhsa-loader` and `nvptx-loader` are used to execute unit tests directly on the GPU. We use this for `libc` and `libcxx` unit tests as well as general GPU experimentation. It looks like this. ```console > clang++ main.cpp --target=amdgcn-amd-amdhsa -mcpu=native -flto -lc ./lib/amdgcn-amd-amdhsa/crt1.o > llvm-gpu-loader a.out Hello World! ``` Currently these are a part of the `libc` project, but this creates issues as `libc` itself depends on them to run tests. Right now we get around this by force-including the `libc` project prior to running the runtimes build so that this dependency can be built first. We should instead just make this a simple LLVM tool so it's always available. This has the effect of installing these by default now instead of just when `libc` was enabled, but they should be relatively small. Right now this only supports a 'static' configuration. That is, we locate the CUDA and HSA dependencies at LLVM compile time. In the future we should be able to provide this by default using `dlopen` and some API. I don't know if it's required to reformat all of these names since they used the `libc` naming convention so I just left it for now.
1 parent 7c11d05 commit 221b011

File tree

12 files changed

+102
-117
lines changed

12 files changed

+102
-117
lines changed

libc/CMakeLists.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,6 @@ set(LIBC_NAMESPACE ${default_namespace}
5959
CACHE STRING "The namespace to use to enclose internal implementations. Must start with '__llvm_libc'."
6060
)
6161

62-
# We will build the GPU utilities if we are not doing a runtimes build.
63-
option(LIBC_BUILD_GPU_LOADER "Always build the GPU loader utilities" OFF)
64-
if(LIBC_BUILD_GPU_LOADER OR ((NOT LLVM_RUNTIMES_BUILD) AND LLVM_LIBC_GPU_BUILD))
65-
add_subdirectory(utils/gpu)
66-
return()
67-
endif()
68-
6962
option(LIBC_CMAKE_VERBOSE_LOGGING
7063
"Log details warnings and notifications during CMake configuration." OFF)
7164

libc/utils/gpu/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

libc/utils/gpu/loader/CMakeLists.txt

Lines changed: 0 additions & 54 deletions
This file was deleted.

libc/utils/gpu/loader/amdgpu/CMakeLists.txt

Lines changed: 0 additions & 10 deletions
This file was deleted.

libc/utils/gpu/loader/nvptx/CMakeLists.txt

Lines changed: 0 additions & 9 deletions
This file was deleted.

llvm/CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,6 @@ if("${LIBC_TARGET_TRIPLE}" STREQUAL "amdgcn-amd-amdhsa" OR
210210
"${LIBC_TARGET_TRIPLE}" STREQUAL "nvptx64-nvidia-cuda")
211211
set(LLVM_LIBC_GPU_BUILD ON)
212212
endif()
213-
if (NOT "libc" IN_LIST LLVM_ENABLE_PROJECTS AND LLVM_LIBC_GPU_BUILD)
214-
message(STATUS "Enabling libc project to build libc testing tools")
215-
list(APPEND LLVM_ENABLE_PROJECTS "libc")
216-
endif()
217213

218214
# LLVM_ENABLE_PROJECTS_USED is `ON` if the user has ever used the
219215
# `LLVM_ENABLE_PROJECTS` CMake cache variable. This exists for

llvm/runtimes/CMakeLists.txt

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -534,20 +534,6 @@ if(build_runtimes)
534534
endif()
535535
if(LLVM_LIBC_GPU_BUILD)
536536
list(APPEND extra_cmake_args "-DLLVM_LIBC_GPU_BUILD=ON")
537-
if("libc" IN_LIST RUNTIMES_amdgcn-amd-amdhsa_LLVM_ENABLE_RUNTIMES)
538-
if(TARGET amdhsa-loader)
539-
list(APPEND extra_cmake_args
540-
"-DRUNTIMES_amdgcn-amd-amdhsa_LIBC_GPU_LOADER_EXECUTABLE=$<TARGET_FILE:amdhsa-loader>")
541-
list(APPEND extra_deps amdhsa-loader)
542-
endif()
543-
endif()
544-
if("libc" IN_LIST RUNTIMES_nvptx64-nvidia-cuda_LLVM_ENABLE_RUNTIMES)
545-
if(TARGET nvptx-loader)
546-
list(APPEND extra_cmake_args
547-
"-DRUNTIMES_nvptx64-nvidia-cuda_LIBC_GPU_LOADER_EXECUTABLE=$<TARGET_FILE:nvptx-loader>")
548-
list(APPEND extra_deps nvptx-loader)
549-
endif()
550-
endif()
551537
if(TARGET clang-offload-packager)
552538
list(APPEND extra_deps clang-offload-packager)
553539
endif()
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
set(LLVM_LINK_COMPONENTS
2+
BinaryFormat
3+
Object
4+
Option
5+
Support
6+
FrontendOffloading
7+
)
8+
9+
add_llvm_tool(llvm-gpu-loader
10+
llvm-gpu-loader.cpp
11+
12+
# TODO: We intentionally split this currently due to statically linking the
13+
# GPU runtimes. Dynamically load the dependencies, possibly using the
14+
# LLVM offloading API when it is complete.
15+
PARTIAL_SOURCES_INTENDED
16+
17+
DEPENDS
18+
intrinsics_gen
19+
)
20+
21+
# Locate the RPC server handling interface.
22+
include(FindLibcCommonUtils)
23+
target_link_libraries(llvm-gpu-loader PUBLIC llvm-libc-common-utilities)
24+
25+
# Check for HSA support for targeting AMD GPUs.
26+
find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
27+
if(hsa-runtime64_FOUND)
28+
target_sources(llvm-gpu-loader PRIVATE amdhsa.cpp)
29+
target_compile_definitions(llvm-gpu-loader PRIVATE AMDHSA_SUPPORT)
30+
target_link_libraries(llvm-gpu-loader PRIVATE hsa-runtime64::hsa-runtime64)
31+
32+
# Compatibility with the old amdhsa-loader name.
33+
add_llvm_tool_symlink(amdhsa-loader llvm-gpu-loader)
34+
endif()
35+
36+
# Check for CUDA support for targeting NVIDIA GPUs.
37+
find_package(CUDAToolkit 11.2 QUIET)
38+
if(CUDAToolkit_FOUND)
39+
target_sources(llvm-gpu-loader PRIVATE nvptx.cpp)
40+
target_compile_definitions(llvm-gpu-loader PRIVATE NVPTX_SUPPORT)
41+
target_link_libraries(llvm-gpu-loader PRIVATE CUDA::cuda_driver)
42+
43+
# Compatibility with the old nvptx-loader name.
44+
add_llvm_tool_symlink(nvptx-loader llvm-gpu-loader)
45+
endif()

libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp renamed to llvm/tools/llvm-gpu-loader/amdhsa.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16-
#include "Loader.h"
16+
#include "llvm-gpu-loader.h"
1717

1818
#include "hsa/hsa.h"
1919
#include "hsa/hsa_ext_amd.h"
@@ -330,9 +330,9 @@ static hsa_status_t hsa_memcpy(void *dst, hsa_agent_t dst_agent,
330330
return HSA_STATUS_SUCCESS;
331331
}
332332

333-
int load(int argc, const char **argv, const char **envp, void *image,
334-
size_t size, const LaunchParameters &params,
335-
bool print_resource_usage) {
333+
int load_amdhsa(int argc, const char **argv, const char **envp, void *image,
334+
size_t size, const LaunchParameters &params,
335+
bool print_resource_usage) {
336336
// Initialize the HSA runtime used to communicate with the device.
337337
if (hsa_status_t err = hsa_init())
338338
handle_error(err);

libc/utils/gpu/loader/Main.cpp renamed to llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@
66
//
77
//===----------------------------------------------------------------------===//
88
//
9-
// This file opens a device image passed on the command line and passes it to
10-
// one of the loader implementations for launch.
9+
// This utility is used to launch standard programs onto the GPU in conjunction
10+
// with the LLVM 'libc' project. It is designed to mimic a standard emulator
11+
// workflow, allowing for unit tests to be run on the GPU directly.
1112
//
1213
//===----------------------------------------------------------------------===//
1314

14-
#include "Loader.h"
15+
#include "llvm-gpu-loader.h"
1516

1617
#include "llvm/BinaryFormat/Magic.h"
18+
#include "llvm/Object/ELF.h"
19+
#include "llvm/Object/ELFObjectFile.h"
1720
#include "llvm/Support/CommandLine.h"
1821
#include "llvm/Support/Error.h"
1922
#include "llvm/Support/FileSystem.h"
2023
#include "llvm/Support/MemoryBuffer.h"
2124
#include "llvm/Support/Path.h"
2225
#include "llvm/Support/Signals.h"
2326
#include "llvm/Support/WithColor.h"
27+
#include "llvm/TargetParser/Triple.h"
2428

2529
#include <cerrno>
2630
#include <cstdio>
@@ -125,12 +129,40 @@ int main(int argc, const char **argv, const char **envp) {
125129
strerror(errno)));
126130
}
127131

128-
// Drop the loader from the program arguments.
129132
LaunchParameters params{threads_x, threads_y, threads_z,
130133
blocks_x, blocks_y, blocks_z};
131-
int ret = load(new_argv.size(), new_argv.data(), envp,
132-
const_cast<char *>(image.getBufferStart()),
133-
image.getBufferSize(), params, print_resource_usage);
134+
135+
Expected<llvm::object::ELF64LEObjectFile> elf_or_err =
136+
llvm::object::ELF64LEObjectFile::create(image);
137+
if (!elf_or_err)
138+
report_error(std::move(elf_or_err.takeError()));
139+
140+
int ret = 1;
141+
if (elf_or_err->getArch() == Triple::amdgcn) {
142+
#ifdef AMDHSA_SUPPORT
143+
ret = load_amdhsa(new_argv.size(), new_argv.data(), envp,
144+
const_cast<char *>(image.getBufferStart()),
145+
image.getBufferSize(), params, print_resource_usage);
146+
#else
147+
report_error(createStringError(
148+
"Unsupported architecture; %s",
149+
Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));
150+
#endif
151+
} else if (elf_or_err->getArch() == Triple::nvptx64) {
152+
#ifdef NVPTX_SUPPORT
153+
ret = load_nvptx(new_argv.size(), new_argv.data(), envp,
154+
const_cast<char *>(image.getBufferStart()),
155+
image.getBufferSize(), params, print_resource_usage);
156+
#else
157+
report_error(createStringError(
158+
"Unsupported architecture; %s",
159+
Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));
160+
#endif
161+
} else {
162+
report_error(createStringError(
163+
"Unsupported architecture; %s",
164+
Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));
165+
}
134166

135167
if (no_parallelism) {
136168
if (flock(fd, LOCK_UN) == -1)

libc/utils/gpu/loader/Loader.h renamed to llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,16 @@ struct end_args_t {
5454
/// Generic interface to load the \p image and launch execution of the _start
5555
/// kernel on the target device. Copies \p argc and \p argv to the device.
5656
/// Returns the final value of the `main` function on the device.
57-
int load(int argc, const char **argv, const char **evnp, void *image,
58-
size_t size, const LaunchParameters &params,
59-
bool print_resource_usage);
57+
#ifdef AMDHSA_SUPPORT
58+
int load_amdhsa(int argc, const char **argv, const char **evnp, void *image,
59+
size_t size, const LaunchParameters &params,
60+
bool print_resource_usage);
61+
#endif
62+
#ifdef NVPTX_SUPPORT
63+
int load_nvptx(int argc, const char **argv, const char **evnp, void *image,
64+
size_t size, const LaunchParameters &params,
65+
bool print_resource_usage);
66+
#endif
6067

6168
/// Return \p V aligned "upwards" according to \p Align.
6269
template <typename V, typename A> inline V align_up(V val, A align) {

libc/utils/gpu/loader/nvptx/nvptx-loader.cpp renamed to llvm/tools/llvm-gpu-loader/nvptx.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16-
#include "Loader.h"
16+
#include "llvm-gpu-loader.h"
1717

1818
#include "cuda.h"
1919

@@ -236,9 +236,9 @@ CUresult launch_kernel(CUmodule binary, CUstream stream, rpc::Server &server,
236236
return CUDA_SUCCESS;
237237
}
238238

239-
int load(int argc, const char **argv, const char **envp, void *image,
240-
size_t size, const LaunchParameters &params,
241-
bool print_resource_usage) {
239+
int load_nvptx(int argc, const char **argv, const char **envp, void *image,
240+
size_t size, const LaunchParameters &params,
241+
bool print_resource_usage) {
242242
if (CUresult err = cuInit(0))
243243
handle_error(err);
244244
// Obtain the first device found on the system.

0 commit comments

Comments
 (0)