--- /dev/null
+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)
+ if(ADD_STARTUP_OBJECT_ALIAS)
+ get_fq_deps_list(fq_dep_list ${ADD_STARTUP_OBJECT_DEPENDS})
+ add_library(${fq_target_name} ALIAS ${fq_dep_list})
+ return()
+ endif()
+
+ add_object_library(
+ ${name}
+ SRCS ${ADD_STARTUP_OBJECT_SRC}
+ DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
+ COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS}
+ )
+ set_target_properties(
+ ${fq_target_name}
+ PROPERTIES
+ OUTPUT_NAME ${name}.o
+ )
+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})
+ install(FILES $<TARGET_OBJECTS:${fq_target_name}>
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RENAME $<TARGET_PROPERTY:${fq_target_name},OUTPUT_NAME>
+ COMPONENT libc)
+endforeach()
--- /dev/null
+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}
+)
+get_fq_target_name(crt1 fq_name)
+
+# Ensure that clang uses the correct linker for this object type.
+target_link_libraries(${fq_name} PUBLIC "--target=${LIBC_GPU_TARGET_TRIPLE}")
--- /dev/null
+//===-- 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);
+}
--- /dev/null
+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}
+)
+get_fq_target_name(crt1 fq_name)
+
+# Ensure that clang uses the correct linker for this object type.
+target_link_libraries(${fq_name} PUBLIC "--target=${LIBC_GPU_TARGET_TRIPLE}")
--- /dev/null
+//===-- 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);
+}