diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index b264dcb4974c..ad39ff6fbcb1 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -59,6 +59,13 @@ set(LIBC_NAMESPACE ${default_namespace} CACHE STRING "The namespace to use to enclose internal implementations. Must start with '__llvm_libc'." ) +# We will build the GPU utilities if we are not doing a runtimes build. +option(LIBC_BUILD_GPU_LOADER "Always build the GPU loader utilities" OFF) +if(LIBC_BUILD_GPU_LOADER OR ((NOT LLVM_RUNTIMES_BUILD) AND LLVM_LIBC_GPU_BUILD)) + add_subdirectory(utils/gpu) + return() +endif() + option(LIBC_CMAKE_VERBOSE_LOGGING "Log details warnings and notifications during CMake configuration." OFF) diff --git a/libc/utils/gpu/CMakeLists.txt b/libc/utils/gpu/CMakeLists.txt new file mode 100644 index 000000000000..e529646a1206 --- /dev/null +++ b/libc/utils/gpu/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(loader) diff --git a/libc/utils/gpu/loader/CMakeLists.txt b/libc/utils/gpu/loader/CMakeLists.txt new file mode 100644 index 000000000000..9b3bd009dc0f --- /dev/null +++ b/libc/utils/gpu/loader/CMakeLists.txt @@ -0,0 +1,54 @@ +add_library(gpu_loader OBJECT Main.cpp) + +include(FindLibcCommonUtils) +target_link_libraries(gpu_loader PUBLIC llvm-libc-common-utilities) + +target_include_directories(gpu_loader PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBC_SOURCE_DIR}/include + ${LIBC_SOURCE_DIR} + ${LLVM_MAIN_INCLUDE_DIR} + ${LLVM_BINARY_DIR}/include +) +if(NOT LLVM_ENABLE_RTTI) + target_compile_options(gpu_loader PUBLIC -fno-rtti) +endif() + +find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm) +if(hsa-runtime64_FOUND) + add_subdirectory(amdgpu) +endif() + +# The CUDA loader requires LLVM to traverse the ELF image for symbols. +find_package(CUDAToolkit 11.2 QUIET) +if(CUDAToolkit_FOUND) + add_subdirectory(nvptx) +endif() + +if(TARGET amdhsa-loader AND LIBC_TARGET_ARCHITECTURE_IS_AMDGPU) + add_custom_target(libc.utils.gpu.loader) + add_dependencies(libc.utils.gpu.loader amdhsa-loader) + set_target_properties( + libc.utils.gpu.loader + PROPERTIES + TARGET amdhsa-loader + EXECUTABLE "$" + ) +elseif(TARGET nvptx-loader AND LIBC_TARGET_ARCHITECTURE_IS_NVPTX) + add_custom_target(libc.utils.gpu.loader) + add_dependencies(libc.utils.gpu.loader nvptx-loader) + set_target_properties( + libc.utils.gpu.loader + PROPERTIES + TARGET nvptx-loader + EXECUTABLE "$" + ) +endif() + +foreach(gpu_loader_tgt amdhsa-loader nvptx-loader) + if(TARGET ${gpu_loader_tgt}) + install(TARGETS ${gpu_loader_tgt} + DESTINATION ${CMAKE_INSTALL_BINDIR} + COMPONENT libc) + endif() +endforeach() diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h b/libc/utils/gpu/loader/Loader.h similarity index 93% rename from llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h rename to libc/utils/gpu/loader/Loader.h index 29da395e3bc2..ec05117a041a 100644 --- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.h +++ b/libc/utils/gpu/loader/Loader.h @@ -54,16 +54,9 @@ 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 ¶ms, - 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 ¶ms, - bool print_resource_usage); -#endif +int load(int argc, const char **argv, const char **evnp, void *image, + size_t size, const LaunchParameters ¶ms, + bool print_resource_usage); /// Return \p V aligned "upwards" according to \p Align. template inline V align_up(V val, A align) { diff --git a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp b/libc/utils/gpu/loader/Main.cpp similarity index 76% rename from llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp rename to libc/utils/gpu/loader/Main.cpp index 9b157e3f9dcb..c3aeeffd5636 100644 --- a/llvm/tools/llvm-gpu-loader/llvm-gpu-loader.cpp +++ b/libc/utils/gpu/loader/Main.cpp @@ -6,17 +6,14 @@ // //===----------------------------------------------------------------------===// // -// This utility is used to launch standard programs onto the GPU in conjunction -// with the LLVM 'libc' project. It is designed to mimic a standard emulator -// workflow, allowing for unit tests to be run on the GPU directly. +// This file opens a device image passed on the command line and passes it to +// one of the loader implementations for launch. // //===----------------------------------------------------------------------===// -#include "llvm-gpu-loader.h" +#include "Loader.h" #include "llvm/BinaryFormat/Magic.h" -#include "llvm/Object/ELF.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -24,7 +21,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/WithColor.h" -#include "llvm/TargetParser/Triple.h" #include #include @@ -129,40 +125,12 @@ int main(int argc, const char **argv, const char **envp) { strerror(errno))); } + // Drop the loader from the program arguments. LaunchParameters params{threads_x, threads_y, threads_z, blocks_x, blocks_y, blocks_z}; - - Expected elf_or_err = - llvm::object::ELF64LEObjectFile::create(image); - if (!elf_or_err) - report_error(std::move(elf_or_err.takeError())); - - int ret = 1; - if (elf_or_err->getArch() == Triple::amdgcn) { -#ifdef AMDHSA_SUPPORT - ret = load_amdhsa(new_argv.size(), new_argv.data(), envp, - const_cast(image.getBufferStart()), - image.getBufferSize(), params, print_resource_usage); -#else - report_error(createStringError( - "Unsupported architecture; %s", - Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin())); -#endif - } else if (elf_or_err->getArch() == Triple::nvptx64) { -#ifdef NVPTX_SUPPORT - ret = load_nvptx(new_argv.size(), new_argv.data(), envp, - const_cast(image.getBufferStart()), - image.getBufferSize(), params, print_resource_usage); -#else - report_error(createStringError( - "Unsupported architecture; %s", - Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin())); -#endif - } else { - report_error(createStringError( - "Unsupported architecture; %s", - Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin())); - } + int ret = load(new_argv.size(), new_argv.data(), envp, + const_cast(image.getBufferStart()), + image.getBufferSize(), params, print_resource_usage); if (no_parallelism) { if (flock(fd, LOCK_UN) == -1) diff --git a/libc/utils/gpu/loader/amdgpu/CMakeLists.txt b/libc/utils/gpu/loader/amdgpu/CMakeLists.txt new file mode 100644 index 000000000000..17878daf0b6f --- /dev/null +++ b/libc/utils/gpu/loader/amdgpu/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LLVM_LINK_COMPONENTS + BinaryFormat + Object + Option + Support + FrontendOffloading + ) + +add_llvm_executable(amdhsa-loader amdhsa-loader.cpp) +target_link_libraries(amdhsa-loader PRIVATE hsa-runtime64::hsa-runtime64 gpu_loader) diff --git a/llvm/tools/llvm-gpu-loader/amdhsa.cpp b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp similarity index 99% rename from llvm/tools/llvm-gpu-loader/amdhsa.cpp rename to libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp index f3c8f646b642..00fde147b0ab 100644 --- a/llvm/tools/llvm-gpu-loader/amdhsa.cpp +++ b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm-gpu-loader.h" +#include "Loader.h" #include "hsa/hsa.h" #include "hsa/hsa_ext_amd.h" @@ -330,9 +330,9 @@ static hsa_status_t hsa_memcpy(void *dst, hsa_agent_t dst_agent, return HSA_STATUS_SUCCESS; } -int load_amdhsa(int argc, const char **argv, const char **envp, void *image, - size_t size, const LaunchParameters ¶ms, - bool print_resource_usage) { +int load(int argc, const char **argv, const char **envp, void *image, + size_t size, const LaunchParameters ¶ms, + bool print_resource_usage) { // Initialize the HSA runtime used to communicate with the device. if (hsa_status_t err = hsa_init()) handle_error(err); diff --git a/libc/utils/gpu/loader/nvptx/CMakeLists.txt b/libc/utils/gpu/loader/nvptx/CMakeLists.txt new file mode 100644 index 000000000000..42510ac31dad --- /dev/null +++ b/libc/utils/gpu/loader/nvptx/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + BinaryFormat + Object + Option + Support + ) + +add_llvm_executable(nvptx-loader nvptx-loader.cpp) +target_link_libraries(nvptx-loader PRIVATE gpu_loader CUDA::cuda_driver) diff --git a/llvm/tools/llvm-gpu-loader/nvptx.cpp b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp similarity index 98% rename from llvm/tools/llvm-gpu-loader/nvptx.cpp rename to libc/utils/gpu/loader/nvptx/nvptx-loader.cpp index f7495605ecc6..7d6c176c6f36 100644 --- a/llvm/tools/llvm-gpu-loader/nvptx.cpp +++ b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm-gpu-loader.h" +#include "Loader.h" #include "cuda.h" @@ -236,9 +236,9 @@ CUresult launch_kernel(CUmodule binary, CUstream stream, rpc::Server &server, return CUDA_SUCCESS; } -int load_nvptx(int argc, const char **argv, const char **envp, void *image, - size_t size, const LaunchParameters ¶ms, - bool print_resource_usage) { +int load(int argc, const char **argv, const char **envp, void *image, + size_t size, const LaunchParameters ¶ms, + bool print_resource_usage) { if (CUresult err = cuInit(0)) handle_error(err); // Obtain the first device found on the system. diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index e76bc9b9ab77..5639061bea20 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -210,6 +210,10 @@ if("${LIBC_TARGET_TRIPLE}" STREQUAL "amdgcn-amd-amdhsa" OR "${LIBC_TARGET_TRIPLE}" STREQUAL "nvptx64-nvidia-cuda") set(LLVM_LIBC_GPU_BUILD ON) endif() +if (NOT "libc" IN_LIST LLVM_ENABLE_PROJECTS AND LLVM_LIBC_GPU_BUILD) + message(STATUS "Enabling libc project to build libc testing tools") + list(APPEND LLVM_ENABLE_PROJECTS "libc") +endif() # LLVM_ENABLE_PROJECTS_USED is `ON` if the user has ever used the # `LLVM_ENABLE_PROJECTS` CMake cache variable. This exists for diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt index 51433d1ec983..136099dc48ab 100644 --- a/llvm/runtimes/CMakeLists.txt +++ b/llvm/runtimes/CMakeLists.txt @@ -534,6 +534,20 @@ if(build_runtimes) endif() if(LLVM_LIBC_GPU_BUILD) list(APPEND extra_cmake_args "-DLLVM_LIBC_GPU_BUILD=ON") + if("libc" IN_LIST RUNTIMES_amdgcn-amd-amdhsa_LLVM_ENABLE_RUNTIMES) + if(TARGET amdhsa-loader) + list(APPEND extra_cmake_args + "-DRUNTIMES_amdgcn-amd-amdhsa_LIBC_GPU_LOADER_EXECUTABLE=$") + list(APPEND extra_deps amdhsa-loader) + endif() + endif() + if("libc" IN_LIST RUNTIMES_nvptx64-nvidia-cuda_LLVM_ENABLE_RUNTIMES) + if(TARGET nvptx-loader) + list(APPEND extra_cmake_args + "-DRUNTIMES_nvptx64-nvidia-cuda_LIBC_GPU_LOADER_EXECUTABLE=$") + list(APPEND extra_deps nvptx-loader) + endif() + endif() if(TARGET clang-offload-packager) list(APPEND extra_deps clang-offload-packager) endif() diff --git a/llvm/tools/llvm-gpu-loader/CMakeLists.txt b/llvm/tools/llvm-gpu-loader/CMakeLists.txt deleted file mode 100644 index 4b4a6e72e47a..000000000000 --- a/llvm/tools/llvm-gpu-loader/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -set(LLVM_LINK_COMPONENTS - BinaryFormat - Object - Option - Support - FrontendOffloading -) - -add_llvm_tool(llvm-gpu-loader - llvm-gpu-loader.cpp - - # TODO: We intentionally split this currently due to statically linking the - # GPU runtimes. Dynamically load the dependencies, possibly using the - # LLVM offloading API when it is complete. - PARTIAL_SOURCES_INTENDED - - DEPENDS - intrinsics_gen -) - -# Locate the RPC server handling interface. -include(FindLibcCommonUtils) -target_link_libraries(llvm-gpu-loader PUBLIC llvm-libc-common-utilities) - -# Check for HSA support for targeting AMD GPUs. -find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm) -if(hsa-runtime64_FOUND) - target_sources(llvm-gpu-loader PRIVATE amdhsa.cpp) - target_compile_definitions(llvm-gpu-loader PRIVATE AMDHSA_SUPPORT) - target_link_libraries(llvm-gpu-loader PRIVATE hsa-runtime64::hsa-runtime64) - - # Compatibility with the old amdhsa-loader name. - add_llvm_tool_symlink(amdhsa-loader llvm-gpu-loader) -endif() - -# Check for CUDA support for targeting NVIDIA GPUs. -find_package(CUDAToolkit 11.2 QUIET) -if(CUDAToolkit_FOUND) - target_sources(llvm-gpu-loader PRIVATE nvptx.cpp) - target_compile_definitions(llvm-gpu-loader PRIVATE NVPTX_SUPPORT) - target_link_libraries(llvm-gpu-loader PRIVATE CUDA::cuda_driver) - - # Compatibility with the old nvptx-loader name. - add_llvm_tool_symlink(nvptx-loader llvm-gpu-loader) -endif()