diff --git a/libc/startup/gpu/CMakeLists.txt b/libc/startup/gpu/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/startup/gpu/CMakeLists.txt @@ -0,0 +1,93 @@ +function(add_startup_object name) + cmake_parse_arguments( + "ADD_STARTUP_OBJECT" + "ALIAS" # Option argument + "SRC" # Single value arguments + "DEPENDS;COMPILE_OPTIONS" # Multi value arguments + ${ARGN} + ) + + get_fq_target_name(${name} fq_target_name) + get_fq_deps_list(fq_deps_list ${ADD_STARTUP_OBJECT_DEPENDS}) + if(ADD_STARTUP_OBJECT_ALIAS) + list(LENGTH ADD_STARTUP_OBJECT_DEPENDS deps_size) + if(NOT (${deps_size} EQUAL "1")) + message(FATAL_ERROR "A startup object alias should have exactly one dependency.") + endif() + list(GET ADD_STARTUP_OBJECT_DEPENDS 0 dep) + get_fq_dep_name(fq_dep_name ${dep}) + + add_custom_target(${fq_target_name}) + add_dependencies(${fq_target_name} ${fq_dep_name}) + get_target_property(startup_object ${fq_dep_name} STARTUP_OBJECT) + set_target_properties( + ${fq_target_name} + PROPERTIES + "TARGET_TYPE" "${OBJECT_LIBRARY_TARGET_TYPE}" + "STARTUP_OBJECT" "${startup_object}" + "OBJECT_FILES" "" + "DEPS" "${fq_dep_name}" + ) + return() + endif() + + add_object_library( + ${name}.__objects__ + SRCS ${ADD_STARTUP_OBJECT_SRC} + DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS} + COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS} + ) + set(objfile ${LIBC_BUILD_DIR}/lib/${name}.o) + add_custom_command( + OUTPUT ${objfile} + COMMAND cp $ ${objfile} + DEPENDS $ + ) + add_custom_target( + ${fq_target_name} + DEPENDS ${objfile} + ) + set_target_properties( + ${fq_target_name} + PROPERTIES + "TARGET_TYPE" "${OBJECT_LIBRARY_TARGET_TYPE}" + "STARTUP_OBJECT" "${objfile}" + "OBJECT_FILES" "" + "DEPS" "${fq_target_name}.__objects__" + ) +endfunction() + +if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU) + add_subdirectory(amdgpu) + + add_startup_object( + crt1 + ALIAS + DEPENDS + amdgpu.crt1 + ) +elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX) + add_subdirectory(nvptx) + + add_startup_object( + crt1 + ALIAS + DEPENDS + .nvptx.crt1 + ) +else() + # Skip building the startup code if there are no supported GPUs. + message(STATUS "Skipping startup for gpu target, no GPUs were detected") + return() +endif() + +add_custom_target(libc-startup) +set(startup_components crt1) +foreach(target IN LISTS startup_components) + set(fq_target_name libc.startup.gpu.${target}) + add_dependencies(libc-startup ${fq_target_name}) + get_target_property(startup_object ${fq_target_name} STARTUP_OBJECT) + install(FILES ${startup_object} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT libc) +endforeach() diff --git a/libc/startup/gpu/amdgpu/CMakeLists.txt b/libc/startup/gpu/amdgpu/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/startup/gpu/amdgpu/CMakeLists.txt @@ -0,0 +1,13 @@ +add_startup_object( + crt1 + SRC + start.cpp + COMPILE_OPTIONS + -ffreestanding # To avoid compiler warnings about calling the main function. + -fno-builtin + -nogpulib # Do not include any GPU vendor libraries. + -nostdinc + -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} + -emit-llvm # AMDGPU's intermediate object file format is bitcode. + --target=${LIBC_GPU_TARGET_TRIPLE} +) diff --git a/libc/startup/gpu/amdgpu/start.cpp b/libc/startup/gpu/amdgpu/start.cpp new file mode 100644 --- /dev/null +++ b/libc/startup/gpu/amdgpu/start.cpp @@ -0,0 +1,14 @@ +//===-- Implementation of crt for amdgpu ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +extern "C" int main(int argc, char **argv); + +extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void +_start(int argc, char **argv, int *ret) { + __atomic_fetch_or(ret, main(argc, argv), __ATOMIC_RELAXED); +} diff --git a/libc/startup/gpu/nvptx/CMakeLists.txt b/libc/startup/gpu/nvptx/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/startup/gpu/nvptx/CMakeLists.txt @@ -0,0 +1,13 @@ +add_startup_object( + crt1 + SRC + start.cpp + COMPILE_OPTIONS + -ffreestanding # To avoid compiler warnings about calling the main function. + -fno-builtin + -nogpulib # Do not include any GPU vendor libraries. + -nostdinc + -x cuda # Use the CUDA toolchain to emit the `_start` kernel. + --offload-device-only + --offload-arch=${LIBC_GPU_TARGET_ARCHITECTURE} +) diff --git a/libc/startup/gpu/nvptx/start.cpp b/libc/startup/gpu/nvptx/start.cpp new file mode 100644 --- /dev/null +++ b/libc/startup/gpu/nvptx/start.cpp @@ -0,0 +1,15 @@ +//===-- Implementation of crt for amdgpu ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +extern "C" __attribute__((device)) int main(int argc, char **argv); + +// TODO: We shouldn't need to use the CUDA language to emit a kernel for NVPTX. +extern "C" [[gnu::visibility("protected")]] __attribute__((global)) void +_start(int argc, char **argv, int *ret) { + __atomic_fetch_or(ret, main(argc, argv), __ATOMIC_RELAXED); +}