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