Skip to content

[libc] Refactor _build_gpu_objects cmake function. #80631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ set(TARGET_ENTRYPOINT_NAME_LIST "")
foreach(entrypoint IN LISTS TARGET_LLVMLIBC_ENTRYPOINTS)
string(FIND ${entrypoint} "." last_dot_loc REVERSE)
if(${last_dot_loc} EQUAL -1)
message(FATAL "Invalid entrypoint target name ${entrypoint}; Expected a '.' "
"(dot) in the name.")
message(FATAL_ERROR "Invalid entrypoint target name ${entrypoint}; Expected"
" a '.' (dot) in the name.")
endif()
math(EXPR name_loc "${last_dot_loc} + 1")
string(SUBSTRING ${entrypoint} ${name_loc} -1 entrypoint_name)
Expand Down
183 changes: 107 additions & 76 deletions libc/cmake/modules/LLVMLibCObjectRules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -145,21 +145,78 @@ function(get_nvptx_compile_options output_var gpu_arch)
set(${output_var} ${nvptx_options} PARENT_SCOPE)
endfunction()

# Builds the object target for the GPU.
# Build the object target for a single GPU arch.
# Usage:
# _build_gpu_object_for_single_arch(
# <target_name>
# <gpu_arch>
# SRCS <list of .cpp files>
# HDRS <list of .h files>
# DEPENDS <list of dependencies>
# COMPILE_OPTIONS <optional list of special compile options for this target>
# FLAGS <optional list of flags>
# )
function(_build_gpu_object_for_single_arch fq_target_name gpu_arch)
cmake_parse_arguments(
"ADD_GPU_OBJ"
"" # No optional arguments
"NAME;CXX_STANDARD" # Single value arguments
"SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
${ARGN}
)

if(NOT ADD_GPU_OBJ_CXX_STANDARD)
set(ADD_GPU_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
endif()

set(compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
# Derive the triple from the specified architecture.
if("${gpu_arch}" IN_LIST all_amdgpu_architectures)
set(gpu_target_triple ${AMDGPU_TARGET_TRIPLE})
list(APPEND compile_options "-mcpu=${gpu_arch}")
list(APPEND compile_options "SHELL:-Xclang -mcode-object-version=none")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what does SHELL: prefix do here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally CMake deduplicates command line arguments, that's bad for things like -Xclang or -mllvm that need to precede another argument. SHELL: make it not do that.

list(APPEND compile_options "-emit-llvm")
elseif("${gpu_arch}" IN_LIST all_nvptx_architectures)
set(gpu_target_triple ${NVPTX_TARGET_TRIPLE})
get_nvptx_compile_options(nvptx_options ${gpu_arch})
list(APPEND compile_options "${nvptx_options}")
else()
message(FATAL_ERROR "Unknown GPU architecture '${gpu_arch}'")
endif()
list(APPEND compile_options "--target=${gpu_target_triple}")

# Build the library for this target architecture. We always emit LLVM-IR for
# packaged GPU binaries.
add_library(${fq_target_name}
EXCLUDE_FROM_ALL
OBJECT
${ADD_GPU_OBJ_SRCS}
${ADD_GPU_OBJ_HDRS}
)

target_compile_options(${fq_target_name} PRIVATE ${compile_options})
target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
set_target_properties(${fq_target_name} PROPERTIES CXX_STANDARD ${ADD_GPU_OBJ_CXX_STANDARD})
if(ADD_GPU_OBJ_DEPENDS)
add_dependencies(${fq_target_name} ${ADD_GPU_OBJ_DEPENDS})
set_target_properties(${fq_target_name} PROPERTIES DEPS "${ADD_GPU_OBJ_DEPENDS}")
endif()
endfunction(_build_gpu_object_for_single_arch)

# Build the object target for the GPU.
# This compiles the target for all supported architectures and embeds it into
# host binary for installing. The internal target contains the GPU code directly
# compiled for a single architecture used internally.
# host binary for installing.
# Usage:
# _build_gpu_objects(
# _build_gpu_object_bundle(
# <target_name>
# <internal_target_name>
# SRCS <list of .cpp files>
# HDRS <list of .h files>
# DEPENDS <list of dependencies>
# COMPILE_OPTIONS <optional list of special compile options for this target>
# FLAGS <optional list of flags>
# )
function(_build_gpu_objects fq_target_name internal_target_name)
function(_build_gpu_object_bundle fq_target_name)
cmake_parse_arguments(
"ADD_GPU_OBJ"
"" # No optional arguments
Expand All @@ -168,7 +225,6 @@ function(_build_gpu_objects fq_target_name internal_target_name)
${ARGN}
)

set(common_compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
if(NOT ADD_GPU_OBJ_CXX_STANDARD)
set(ADD_GPU_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
endif()
Expand All @@ -179,49 +235,28 @@ function(_build_gpu_objects fq_target_name internal_target_name)
foreach(gpu_arch ${LIBC_GPU_ARCHITECTURES})
get_filename_component(src_name ${add_gpu_obj_src} NAME)
set(gpu_target_name ${fq_target_name}.${src_name}.${gpu_arch})
set(compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
# Derive the triple from the specified architecture.
if("${gpu_arch}" IN_LIST all_amdgpu_architectures)
set(gpu_target_triple "amdgcn-amd-amdhsa")
list(APPEND compile_options "-mcpu=${gpu_arch}")
list(APPEND compile_options "SHELL:-Xclang -mcode-object-version=none")
elseif("${gpu_arch}" IN_LIST all_nvptx_architectures)
set(gpu_target_triple "nvptx64-nvidia-cuda")
get_nvptx_compile_options(nvptx_options ${gpu_arch})
list(APPEND compile_options "${nvptx_options}")
else()
message(FATAL_ERROR "Unknown GPU architecture '${gpu_arch}'")
endif()
list(APPEND compile_options "--target=${gpu_target_triple}")
list(APPEND compile_options "-emit-llvm")

# Build the library for this target architecture. We always emit LLVM-IR for
# packaged GPU binaries.
add_library(${gpu_target_name}
EXCLUDE_FROM_ALL
OBJECT
${add_gpu_obj_src}
${ADD_GPU_OBJ_HDRS}
)

target_compile_options(${gpu_target_name} PRIVATE ${compile_options})
target_include_directories(${gpu_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
target_include_directories(${gpu_target_name} PRIVATE ${LIBC_SOURCE_DIR})
target_compile_definitions(${gpu_target_name} PRIVATE LIBC_COPT_PUBLIC_PACKAGING)
set_target_properties(${gpu_target_name} PROPERTIES CXX_STANDARD ${ADD_GPU_OBJ_CXX_STANDARD})
if(ADD_GPU_OBJ_DEPENDS)
add_dependencies(${gpu_target_name} ${ADD_GPU_OBJ_DEPENDS})
endif()

_build_gpu_object_for_single_arch(
${gpu_target_name}
${gpu_arch}
CXX_STANDARD ${ADD_GPU_OBJ_CXX_STANDARD}
HDRS ${ADD_GPU_OBJ_HDRS}
SRCS ${add_gpu_obj_src}
COMPILE_OPTIONS
${ADD_GPU_OBJ_COMPILE_OPTIONS}
"-emit-llvm"
DEPENDS ${ADD_GPU_OBJ_DEPENDS}
)
# Append this target to a list of images to package into a single binary.
set(input_file $<TARGET_OBJECTS:${gpu_target_name}>)
if("${gpu_arch}" IN_LIST all_nvptx_architectures)
get_nvptx_compile_options(nvptx_options ${gpu_arch})
string(REGEX MATCH "\\+ptx[0-9]+" nvptx_ptx_feature ${nvptx_options})
list(APPEND packager_images
--image=file=${input_file},arch=${gpu_arch},triple=${gpu_target_triple},feature=${nvptx_ptx_feature})
--image=file=${input_file},arch=${gpu_arch},triple=${NVPTX_TARGET_TRIPLE},feature=${nvptx_ptx_feature})
else()
list(APPEND packager_images
--image=file=${input_file},arch=${gpu_arch},triple=${gpu_target_triple})
--image=file=${input_file},arch=${gpu_arch},triple=${AMDGPU_TARGET_TRIPLE})
endif()
list(APPEND gpu_target_objects ${input_file})
endforeach()
Expand Down Expand Up @@ -269,7 +304,7 @@ function(_build_gpu_objects fq_target_name internal_target_name)
${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}
)
target_compile_options(${fq_target_name} BEFORE PRIVATE
${common_compile_options} -nostdlib)
${ADD_GPU_OBJ_COMPILE_OPTIONS} -nostdlib)
foreach(packaged_gpu_binary ${packaged_gpu_binaries})
target_compile_options(${fq_target_name} PRIVATE
"SHELL:-Xclang -fembed-offload-object=${packaged_gpu_binary}")
Expand All @@ -278,33 +313,6 @@ function(_build_gpu_objects fq_target_name internal_target_name)
target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
add_dependencies(${fq_target_name}
${full_deps_list} ${packaged_gpu_names} ${stub_target_name})

# We only build the internal target for a single supported architecture.
if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU OR
LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
add_library(
${internal_target_name}
EXCLUDE_FROM_ALL
OBJECT
${ADD_GPU_OBJ_SRCS}
${ADD_GPU_OBJ_HDRS}
)
target_compile_options(${internal_target_name} BEFORE PRIVATE
${common_compile_options} --target=${LIBC_GPU_TARGET_TRIPLE})
if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
target_compile_options(${internal_target_name} PRIVATE
"SHELL:-Xclang -mcode-object-version=none"
-mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto)
elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
target_compile_options(${internal_target_name} PRIVATE ${nvptx_options})
endif()
target_include_directories(${internal_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
target_include_directories(${internal_target_name} PRIVATE ${LIBC_SOURCE_DIR})
if(full_deps_list)
add_dependencies(${internal_target_name} ${full_deps_list})
endif()
endif()
endfunction()

# Rule which is essentially a wrapper over add_library to compile a set of
Expand Down Expand Up @@ -354,24 +362,38 @@ function(create_object_library fq_target_name)
# The GPU build uses a separate internal file.
if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
set(internal_target_name ${fq_target_name}.__internal__)
set(public_packaging_for_internal "")
else()
set(internal_target_name ${fq_target_name})
set(public_packaging_for_internal "-DLIBC_COPT_PUBLIC_PACKAGING")
endif()

_get_common_compile_options(compile_options "${ADD_OBJECT_FLAGS}")
list(APPEND compile_options ${ADD_OBJECT_COMPILE_OPTIONS})

# GPU builds require special handling for the objects because we want to
# export several different targets at once, e.g. for both Nvidia and AMD.
if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
_build_gpu_objects(
${fq_target_name}
if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
if(NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
_build_gpu_object_bundle(
${fq_target_name}
SRCS ${ADD_OBJECT_SRCS}
HDRS ${ADD_OBJECT_HDRS}
CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
COMPILE_OPTIONS ${compile_options} "-DLIBC_COPT_PUBLIC_PACKAGING"
DEPENDS ${fq_deps_list}
)
endif()
# When the target for GPU is not bundled, internal_target_name is the same
# as fq_targetname
_build_gpu_object_for_single_arch(
${internal_target_name}
${LIBC_GPU_TARGET_ARCHITECTURE}
SRCS ${ADD_OBJECT_SRCS}
HDRS ${ADD_OBJECT_HDRS}
DEPENDS ${fq_deps_list}
CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
COMPILE_OPTIONS ${compile_options}
COMPILE_OPTIONS ${compile_options} ${public_packaging_for_internal}
DEPENDS ${fq_deps_list}
)
else()
add_library(
Expand Down Expand Up @@ -567,9 +589,18 @@ function(create_entrypoint_object fq_target_name)
# GPU builds require special handling for the objects because we want to
# export several different targets at once, e.g. for both Nvidia and AMD.
if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
_build_gpu_objects(
_build_gpu_object_bundle(
${fq_target_name}
SRCS ${ADD_ENTRYPOINT_OBJ_SRCS}
HDRS ${ADD_ENTRYPOINT_OBJ_HDRS}
COMPILE_OPTIONS ${common_compile_options} "-DLIBC_COPT_PUBLIC_PACKAGING"
CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
DEPENDS ${full_deps_list}
FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
)
_build_gpu_object_for_single_arch(
${internal_target_name}
${LIBC_GPU_TARGET_ARCHITECTURE}
SRCS ${ADD_ENTRYPOINT_OBJ_SRCS}
HDRS ${ADD_ENTRYPOINT_OBJ_HDRS}
COMPILE_OPTIONS ${common_compile_options}
Expand Down
19 changes: 14 additions & 5 deletions libc/cmake/modules/prepare_libc_gpu_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ set(all_gpu_architectures
"${all_amdgpu_architectures};${all_nvptx_architectures}")
set(LIBC_GPU_ARCHITECTURES "all" CACHE STRING
"List of GPU architectures to build the libc for.")
set(AMDGPU_TARGET_TRIPLE "amdgcn-amd-amdhsa")
set(NVPTX_TARGET_TRIPLE "nvptx64-nvidia-cuda")

# Ensure the compiler is a valid clang when building the GPU target.
set(req_ver "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
Expand Down Expand Up @@ -96,18 +98,25 @@ elseif(detected_gpu_architectures)
message(STATUS "Using GPU architecture detected on the system for testing: "
"'${gpu_test_architecture}'")
else()
message(STATUS "No GPU architecture set for testing. GPU tests will not be "
"availibe. Set 'LIBC_GPU_TEST_ARCHITECTURE' to override.")
return()
list(LENGTH LIBC_GPU_ARCHITECTURES n_gpu_archs)
if (${n_gpu_archs} EQUAL 1)
set(gpu_test_architecture ${LIBC_GPU_ARCHITECTURES})
message(STATUS "Using user-specified GPU architecture for testing: "
"'${gpu_test_architecture}'")
else()
message(STATUS "No GPU architecture set for testing. GPU tests will not be "
"availibe. Set 'LIBC_GPU_TEST_ARCHITECTURE' to override.")
return()
endif()
endif()

if("${gpu_test_architecture}" IN_LIST all_amdgpu_architectures)
set(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU TRUE)
set(LIBC_GPU_TARGET_TRIPLE "amdgcn-amd-amdhsa")
set(LIBC_GPU_TARGET_TRIPLE ${AMDGPU_TARGET_TRIPLE})
set(LIBC_GPU_TARGET_ARCHITECTURE "${gpu_test_architecture}")
elseif("${gpu_test_architecture}" IN_LIST all_nvptx_architectures)
set(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX TRUE)
set(LIBC_GPU_TARGET_TRIPLE "nvptx64-nvidia-cuda")
set(LIBC_GPU_TARGET_TRIPLE ${NVPTX_TARGET_TRIPLE})
set(LIBC_GPU_TARGET_ARCHITECTURE "${gpu_test_architecture}")
else()
message(FATAL_ERROR "Unknown GPU architecture '${gpu_test_architecture}'")
Expand Down
3 changes: 2 additions & 1 deletion libc/startup/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ function(add_startup_object name)
add_object_library(
${name}
SRCS ${ADD_STARTUP_OBJECT_SRC}
DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS}
${ADD_STARTUP_OBJECT_UNPARSED_ARGUMENTS}
DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
)
set_target_properties(
${fq_target_name}
Expand Down
6 changes: 1 addition & 5 deletions libc/startup/gpu/amdgpu/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_startup_object(
crt1
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
SRC
start.cpp
DEPENDS
Expand All @@ -10,12 +11,7 @@ add_startup_object(
COMPILE_OPTIONS
-ffreestanding # To avoid compiler warnings about calling the main function.
-fno-builtin
-nogpulib # Do not include any GPU vendor libraries.
-mcpu=${LIBC_GPU_TARGET_ARCHITECTURE}
-emit-llvm # AMDGPU's intermediate object file format is bitcode.
-mcode-object-version=${LIBC_GPU_CODE_OBJECT_VERSION} # Manually set the ABI.
--target=${LIBC_GPU_TARGET_TRIPLE}
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
)
get_fq_target_name(crt1 fq_name)

Expand Down
6 changes: 1 addition & 5 deletions libc/startup/gpu/nvptx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
add_startup_object(
crt1
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
SRC
start.cpp
DEPENDS
Expand All @@ -11,10 +11,6 @@ add_startup_object(
COMPILE_OPTIONS
-ffreestanding # To avoid compiler warnings about calling the main function.
-fno-builtin
-nogpulib # Do not include any GPU vendor libraries.
--target=${LIBC_GPU_TARGET_TRIPLE}
${nvptx_options}
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
)
get_fq_target_name(crt1 fq_name)

Expand Down
2 changes: 1 addition & 1 deletion libc/test/IntegrationTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ endif()

add_object_library(
test
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
SRCS
test.cpp
COMPILE_OPTIONS
Expand All @@ -23,5 +24,4 @@ add_object_library(
test.h
DEPENDS
libc.src.__support.OSUtil.osutil
NO_GPU_BUNDLE # Compile this file directly without special GPU handling.
)
2 changes: 1 addition & 1 deletion libc/test/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function(add_fp_unittest name)
endif()
if(MATH_UNITTEST_NEED_MPFR)
if(MATH_UNITTEST_HERMETIC_TEST_ONLY)
message(FATAL "Hermetic math test cannot require MPFR.")
message(FATAL_ERROR "Hermetic math test cannot require MPFR.")
endif()
set(test_type UNIT_TEST_ONLY)
list(APPEND MATH_UNITTEST_LINK_LIBRARIES libcMPFRWrapper libc_math_test_utils -lmpfr -lgmp)
Expand Down