llvm-project/libc/cmake/modules/LLVMLibCCheckCpuFeatures.cmake
Petr Hosek c4819eec1a [CMake][libc] Don't do CPU feature detection when cross-compiling
We won't be able to run the compiled program since it will be compiled
for different system. We instead allow passing the CPU features via
CMake option in that case.

Differential Revision: https://reviews.llvm.org/D95203
2021-01-28 12:54:37 -08:00

148 lines
4.9 KiB
CMake

# ------------------------------------------------------------------------------
# Cpu features definition and flags
# ------------------------------------------------------------------------------
if(${LIBC_TARGET_MACHINE} MATCHES "x86|x86_64")
set(ALL_CPU_FEATURES SSE SSE2 AVX AVX2 AVX512F)
list(SORT ALL_CPU_FEATURES)
endif()
# Function to check whether the target CPU supports the provided set of features.
# Usage:
# cpu_supports(
# <output variable>
# <list of cpu features>
# )
function(cpu_supports output_var features)
_intersection(var "${LIBC_CPU_FEATURES}" "${features}")
if("${var}" STREQUAL "${features}")
set(${output_var} TRUE PARENT_SCOPE)
else()
unset(${output_var} PARENT_SCOPE)
endif()
endfunction()
# Function to compute the flags to pass down to the compiler.
# Usage:
# compute_flags(
# <output variable>
# MARCH <arch name or "native">
# REQUIRE <list of mandatory features to enable>
# REJECT <list of features to disable>
# )
function(compute_flags output_var)
cmake_parse_arguments(
"COMPUTE_FLAGS"
"" # Optional arguments
"MARCH" # Single value arguments
"REQUIRE;REJECT" # Multi value arguments
${ARGN})
# Check that features are not required and rejected at the same time.
if(COMPUTE_FLAGS_REQUIRE AND COMPUTE_FLAGS_REJECT)
_intersection(var ${COMPUTE_FLAGS_REQUIRE} ${COMPUTE_FLAGS_REJECT})
if(var)
message(FATAL_ERROR "Cpu Features REQUIRE and REJECT ${var}")
endif()
endif()
# Generate the compiler flags in `current`.
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang|GNU")
if(COMPUTE_FLAGS_MARCH)
list(APPEND current "-march=${COMPUTE_FLAGS_MARCH}")
endif()
foreach(feature IN LISTS COMPUTE_FLAGS_REQUIRE)
string(TOLOWER ${feature} lowercase_feature)
list(APPEND current "-m${lowercase_feature}")
endforeach()
foreach(feature IN LISTS COMPUTE_FLAGS_REJECT)
string(TOLOWER ${feature} lowercase_feature)
list(APPEND current "-mno-${lowercase_feature}")
endforeach()
else()
# In future, we can extend for other compilers.
message(FATAL_ERROR "Unkown compiler ${CMAKE_CXX_COMPILER_ID}.")
endif()
# Export the list of flags.
set(${output_var} "${current}" PARENT_SCOPE)
endfunction()
# ------------------------------------------------------------------------------
# Internal helpers and utilities.
# ------------------------------------------------------------------------------
# Computes the intersection between two lists.
function(_intersection output_var list1 list2)
foreach(element IN LISTS list1)
if("${list2}" MATCHES "(^|;)${element}(;|$)")
list(APPEND tmp "${element}")
endif()
endforeach()
set(${output_var} ${tmp} PARENT_SCOPE)
endfunction()
# Generates a cpp file to introspect the compiler defined flags.
function(_generate_check_code)
foreach(feature IN LISTS ALL_CPU_FEATURES)
set(DEFINITIONS
"${DEFINITIONS}
#ifdef __${feature}__
\"${feature}\",
#endif")
endforeach()
configure_file(
"${LIBC_SOURCE_DIR}/cmake/modules/cpu_features/check_cpu_features.cpp.in"
"cpu_features/check_cpu_features.cpp" @ONLY)
endfunction()
_generate_check_code()
# Compiles and runs the code generated above with the specified requirements.
# This is helpful to infer which features a particular target supports or if
# a specific features implies other features (e.g. BMI2 implies SSE2 and SSE).
function(_check_defined_cpu_feature output_var)
cmake_parse_arguments(
"CHECK_DEFINED"
"" # Optional arguments
"MARCH" # Single value arguments
"REQUIRE;REJECT" # Multi value arguments
${ARGN})
compute_flags(
flags
MARCH ${CHECK_DEFINED_MARCH}
REQUIRE ${CHECK_DEFINED_REQUIRE}
REJECT ${CHECK_DEFINED_REJECT})
try_run(
run_result compile_result "${CMAKE_CURRENT_BINARY_DIR}/check_${feature}"
"${CMAKE_CURRENT_BINARY_DIR}/cpu_features/check_cpu_features.cpp"
COMPILE_DEFINITIONS ${flags}
COMPILE_OUTPUT_VARIABLE compile_output
RUN_OUTPUT_VARIABLE run_output)
if("${run_result}" EQUAL 0)
set(${output_var}
"${run_output}"
PARENT_SCOPE)
elseif(NOT ${compile_result})
message(FATAL_ERROR "Failed to compile: ${compile_output}")
else()
message(FATAL_ERROR "Failed to run: ${run_output}")
endif()
endfunction()
set(LIBC_CPU_FEATURES "" CACHE PATH "supported CPU features")
if(CMAKE_CROSSCOMPILING)
_intersection(cpu_features "${ALL_CPU_FEATURES}" "${LIBC_CPU_FEATURES}")
if(NOT "${cpu_features}" STREQUAL "${LIBC_CPU_FEATURES}")
message(FATAL_ERROR "Unsupported CPU features: ${cpu_features}")
endif()
set(LIBC_CPU_FEATURES "${cpu_features}")
else()
# Populates the LIBC_CPU_FEATURES list.
# Use -march=native only when the compiler supports it.
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE)
_check_defined_cpu_feature(LIBC_CPU_FEATURES MARCH native)
else()
_check_defined_cpu_feature(LIBC_CPU_FEATURES)
endif()
endif()