1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# ------------------------------------------------------------------------------
# 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 host supports the provided set of features.
# Usage:
# host_supports(
# <output variable>
# <list of cpu features>
# )
function(host_supports output_var features)
_intersection(a "${HOST_CPU_FEATURES}" "${features}")
if("${a}" 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(${compile_result} AND ("${run_result}" EQUAL 0))
set(${output_var}
"${run_output}"
PARENT_SCOPE)
else()
message(FATAL_ERROR "${compile_output}")
endif()
endfunction()
# Populates the HOST_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(HOST_CPU_FEATURES MARCH native)
else()
_check_defined_cpu_feature(HOST_CPU_FEATURES)
endif()
|