1# ------------------------------------------------------------------------------ 2# Cpu features definition and flags 3# ------------------------------------------------------------------------------ 4 5if(${LIBC_TARGET_MACHINE} MATCHES "x86|x86_64") 6 set(ALL_CPU_FEATURES SSE SSE2 AVX AVX2 AVX512F) 7endif() 8 9list(SORT ALL_CPU_FEATURES) 10 11# Function to check whether the host supports the provided set of features. 12# Usage: 13# host_supports( 14# <output variable> 15# <list of cpu features> 16# ) 17function(host_supports output_var features) 18 _intersection(a "${HOST_CPU_FEATURES}" "${features}") 19 if("${a}" STREQUAL "${features}") 20 set(${output_var} TRUE PARENT_SCOPE) 21 else() 22 unset(${output_var} PARENT_SCOPE) 23 endif() 24endfunction() 25 26# Function to compute the flags to pass down to the compiler. 27# Usage: 28# compute_flags( 29# <output variable> 30# MARCH <arch name or "native"> 31# REQUIRE <list of mandatory features to enable> 32# REJECT <list of features to disable> 33# ) 34function(compute_flags output_var) 35 cmake_parse_arguments( 36 "COMPUTE_FLAGS" 37 "" # Optional arguments 38 "MARCH" # Single value arguments 39 "REQUIRE;REJECT" # Multi value arguments 40 ${ARGN}) 41 # Check that features are not required and rejected at the same time. 42 if(COMPUTE_FLAGS_REQUIRE AND COMPUTE_FLAGS_REJECT) 43 _intersection(var ${COMPUTE_FLAGS_REQUIRE} ${COMPUTE_FLAGS_REJECT}) 44 if(var) 45 message(FATAL_ERROR "Cpu Features REQUIRE and REJECT ${var}") 46 endif() 47 endif() 48 # Generate the compiler flags in `current`. 49 if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang|GNU") 50 if(COMPUTE_FLAGS_MARCH) 51 list(APPEND current "-march=${COMPUTE_FLAGS_MARCH}") 52 endif() 53 foreach(feature IN LISTS COMPUTE_FLAGS_REQUIRE) 54 string(TOLOWER ${feature} lowercase_feature) 55 list(APPEND current "-m${lowercase_feature}") 56 endforeach() 57 foreach(feature IN LISTS COMPUTE_FLAGS_REJECT) 58 string(TOLOWER ${feature} lowercase_feature) 59 list(APPEND current "-mno-${lowercase_feature}") 60 endforeach() 61 else() 62 # In future, we can extend for other compilers. 63 message(FATAL_ERROR "Unkown compiler ${CMAKE_CXX_COMPILER_ID}.") 64 endif() 65 # Export the list of flags. 66 set(${output_var} "${current}" PARENT_SCOPE) 67endfunction() 68 69# ------------------------------------------------------------------------------ 70# Internal helpers and utilities. 71# ------------------------------------------------------------------------------ 72 73# Computes the intersection between two lists. 74function(_intersection output_var list1 list2) 75 foreach(element IN LISTS list1) 76 if("${list2}" MATCHES "(^|;)${element}(;|$)") 77 list(APPEND tmp "${element}") 78 endif() 79 endforeach() 80 set(${output_var} ${tmp} PARENT_SCOPE) 81endfunction() 82 83# Generates a cpp file to introspect the compiler defined flags. 84function(_generate_check_code) 85 foreach(feature IN LISTS ALL_CPU_FEATURES) 86 set(DEFINITIONS 87 "${DEFINITIONS} 88#ifdef __${feature}__ 89 \"${feature}\", 90#endif") 91 endforeach() 92 configure_file( 93 "${LIBC_SOURCE_DIR}/cmake/modules/cpu_features/check_cpu_features.cpp.in" 94 "cpu_features/check_cpu_features.cpp" @ONLY) 95endfunction() 96_generate_check_code() 97 98# Compiles and runs the code generated above with the specified requirements. 99# This is helpful to infer which features a particular target supports or if 100# a specific features implies other features (e.g. BMI2 implies SSE2 and SSE). 101function(_check_defined_cpu_feature output_var) 102 cmake_parse_arguments( 103 "CHECK_DEFINED" 104 "" # Optional arguments 105 "MARCH" # Single value arguments 106 "REQUIRE;REJECT" # Multi value arguments 107 ${ARGN}) 108 compute_flags( 109 flags 110 MARCH ${CHECK_DEFINED_MARCH} 111 REQUIRE ${CHECK_DEFINED_REQUIRE} 112 REJECT ${CHECK_DEFINED_REJECT}) 113 try_run( 114 run_result compile_result "${CMAKE_CURRENT_BINARY_DIR}/check_${feature}" 115 "${CMAKE_CURRENT_BINARY_DIR}/cpu_features/check_cpu_features.cpp" 116 COMPILE_DEFINITIONS ${flags} 117 COMPILE_OUTPUT_VARIABLE compile_output 118 RUN_OUTPUT_VARIABLE run_output) 119 if(${compile_result} AND ("${run_result}" EQUAL 0)) 120 set(${output_var} 121 "${run_output}" 122 PARENT_SCOPE) 123 else() 124 message(FATAL_ERROR "${compile_output}") 125 endif() 126endfunction() 127 128# Populates the HOST_CPU_FEATURES list. 129_check_defined_cpu_feature(HOST_CPU_FEATURES MARCH native) 130