include( CheckCCompilerFlag ) include( CheckCSourceCompiles ) include( CheckCXXSourceCompiles ) function( set_if_compiler_supports_flag output_var flag ) string( REGEX REPLACE "[-.]" "_" SUPPORTED_flag_var "SUPPORTED${flag}" ) check_c_compiler_flag( -Werror=unused-command-line-argument SUPPORTED_Werror_unused_command_line_argument ) if( SUPPORTED_Werror_unused_command_line_argument ) set( FLAGS_CHECK_STR "${flag} -Werror=unused-command-line-argument" ) else() set( FLAGS_CHECK_STR "${flag}" ) endif() # if building WASM -msimd128 needs to be added to all checks for supported simd-compiler flags _emscripten_enable_wasm_simd128() check_c_compiler_flag( ${FLAGS_CHECK_STR} ${SUPPORTED_flag_var} ) if( ${SUPPORTED_flag_var} ) set( ${output_var} "${flag}" PARENT_SCOPE ) endif() endfunction() function( check_missing_intrinsics ) # if building WASM -msimd128 needs to be added to all checks for supported simd-compiler flags _emscripten_enable_wasm_simd128() if( NOT MSVC ) set_if_compiler_supports_flag( FLAG_msse41 -msse4.1 ) set_if_compiler_supports_flag( FLAG_mavx -mavx ) else() set_if_compiler_supports_flag( FLAG_mavx /arch:AVX2 ) endif() # SSE2 _check_intrinsic( _mm_storeu_si16 "${FLAG_msse41}" "int16_t a = 0; _mm_storeu_si16( &a, _mm_setzero_si128() );" ) _check_intrinsic( _mm_storeu_si32 "${FLAG_msse41}" "int32_t a = 0; _mm_storeu_si32( &a, _mm_setzero_si128() );" ) _check_intrinsic( _mm_storeu_si64 "${FLAG_msse41}" "int64_t a = 0; _mm_storeu_si64( &a, _mm_setzero_si128() );" ) _check_intrinsic( _mm_loadu_si32 "${FLAG_msse41}" "int32_t a = 0; __m128i x = _mm_loadu_si32( &a );" ) _check_intrinsic( _mm_loadu_si64 "${FLAG_msse41}" "int64_t a = 0; __m128i x = _mm_loadu_si64( &a );" ) _check_intrinsic( _mm_cvtsi128_si64 "${FLAG_msse41}" "int64_t a = 0; a = _mm_cvtsi128_si64( _mm_setzero_si128() );" ) _check_intrinsic( _mm_cvtsi64_si128 "${FLAG_msse41}" "int64_t a = 0; __m128i x = _mm_cvtsi64_si128( a );" ) _check_intrinsic( _mm_extract_epi64 "${FLAG_msse41}" "int64_t a = 0; a = _mm_extract_epi64( _mm_setzero_si128(), 0 );" ) # AVX _check_intrinsic( _mm256_zeroupper "${FLAG_mavx}" "_mm256_zeroupper();" ) _check_intrinsic( _mm256_loadu2_m128i "${FLAG_mavx}" "int a[4] = { 0, }; \ __m256i x = _mm256_loadu2_m128i( (const __m128i*)a, (const __m128i*)a );" ) _check_intrinsic( _mm256_set_m128i "${FLAG_mavx}" "__m256i x = _mm256_set_m128i( _mm_setzero_si128(), _mm_setzero_si128() );" ) endfunction() function( _check_intrinsic symbol_name compiler_flags code ) set( CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${compiler_flags}") set( CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/" ) check_c_source_compiles(" #include #if defined(SIMDE_ARCH_AMD64) || defined(SIMDE_ARCH_X86) || defined(SIMDE_ARCH_WASM) # include // need this first, otherwise we get linker-errors on windows #else # define SIMDE_ENABLE_NATIVE_ALIASES #endif #include #include int main() { ${code} return 0; }" HAVE_INTRIN${symbol_name} ) if( NOT HAVE_INTRIN${symbol_name} ) add_compile_definitions( MISSING_INTRIN${symbol_name} ) endif() endfunction() function( _emscripten_enable_wasm_simd128 ) if( ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten" ) # this is only used by try_compile(), check_c_compiler_flag(), and related functions, # but not by the actual build. set( CMAKE_REQUIRED_FLAGS -msimd128 PARENT_SCOPE ) endif() endfunction() function( _set_if_compiler_supports_sve_flag output_var sve_flag ) set_if_compiler_supports_flag( tmp_var "${sve_flag}" ) if( NOT tmp_var ) return() endif() set( OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ) set( OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE} ) set( CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${sve_flag}" ) set( CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY ) # Check whether the compiler can compile SVE functions that require # backup/restore of SVE registers according to AAPCS. # https://github.com/llvm/llvm-project/issues/80009. set( SVE_COMPILATION_TEST " #include void other(); svfloat32_t func(svfloat32_t a) { other(); return a; } int main() { return 0; }" ) check_c_source_compiles( "${SVE_COMPILATION_TEST}" SVE_COMPILATION_C_TEST_COMPILED ) check_cxx_source_compiles( "${SVE_COMPILATION_TEST}" SVE_COMPILATION_CXX_TEST_COMPILED ) # Check if arm_neon_sve_bridge.h is available. set( SVE_HEADER_TEST " #ifndef __ARM_NEON_SVE_BRIDGE #error 1 #endif #include #include int main() { return 0; }") check_c_source_compiles( "${SVE_HEADER_TEST}" SVE_HEADER_C_TEST_COMPILED ) check_cxx_source_compiles( "${SVE_HEADER_TEST}" SVE_HEADER_CXX_TEST_COMPILED ) set( CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS} ) set( CMAKE_TRY_COMPILE_TARGET_TYPE ${OLD_CMAKE_TRY_COMPILE_TARGET_TYPE} ) if( SVE_COMPILATION_C_TEST_COMPILED AND SVE_COMPILATION_CXX_TEST_COMPILED AND SVE_HEADER_C_TEST_COMPILED AND SVE_HEADER_CXX_TEST_COMPILED ) set( ${output_var} "${tmp_var}" PARENT_SCOPE ) endif() endfunction() # Check if the compiler supports the AArch64 SVE and SVE2 extensions, and set # variables for flags used to enable them to avoid duplication. function( set_if_compiler_supports_arm_extensions output_flag_sve output_flag_sve2 ) if( NOT(( ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64" ) OR ( ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64" ))) return() endif() if( UNIX OR MINGW ) # SVE is an optional feature from Armv8.2-A. set( _flag_sve "-march=armv8.2-a+sve" ) _set_if_compiler_supports_sve_flag( _sve_supported "${_flag_sve}" ) set( ${output_flag_sve} "${_sve_supported}" PARENT_SCOPE ) # SVE2 is an optional feature from Armv9.0-A. set( _flag_sve2 "-march=armv9-a+sve2" ) _set_if_compiler_supports_sve_flag( _sve2_supported "${_flag_sve2}" ) set( ${output_flag_sve2} "${_sve2_supported}" PARENT_SCOPE ) endif() endfunction() function( check_problematic_compiler output_var compiler_id first_bad_version first_fixed_version ) if( CMAKE_CXX_COMPILER_ID STREQUAL "${compiler_id}" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "${first_bad_version}" AND ( NOT "${first_fixed_version}" OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${first_fixed_version}" ) ) set( ${output_var} TRUE PARENT_SCOPE ) if( "${first_fixed_version}" ) set( ${output_var}_VERSION_RANGE "(${first_bad_version}...${first_fixed_version}]" PARENT_SCOPE ) else() set( ${output_var}_VERSION_RANGE "(${first_bad_version}...)" PARENT_SCOPE ) endif() endif() endfunction() function( detect_target_architecture output_var ) # try to detect the actual target architecture if( ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten" ) message( DEBUG "Emscripten" ) # Emscripten doesn't set the CMAKE_SYSTEM_PROCESSOR list( PREPEND target_arch_list "WASM" ) elseif( NOT CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR ) message( DEBUG "sys != host ${CMAKE_SYSTEM_PROCESSOR} STREQUAL ${CMAKE_HOST_SYSTEM_PROCESSOR} " ) # cross compiling: CMAKE_SYSTEM_PROCESSOR was set explicitly, so we use that as first guess _append_cpu_type_guess( target_arch_list CMAKE_SYSTEM_PROCESSOR ) endif() # build list of architectures in order of probability _append_cpu_type_guess( target_arch_list CMAKE_VS_PLATFORM_NAME ) _append_cpu_type_guess( target_arch_list CMAKE_OSX_ARCHITECTURES ) _append_cpu_type_guess( target_arch_list CMAKE_CXX_COMPILER_ARCHITECTURE_ID ) # set by msvc, wen not using msbuild _append_cpu_type_guess( target_arch_list CMAKE_ANDROID_ARCH_ABI ) _append_cpu_type_guess( target_arch_list CMAKE_C_LIBRARY_ARCHITECTURE ) _append_cpu_type_guess( target_arch_list CMAKE_SYSTEM_PROCESSOR ) _append_cpu_type_guess( target_arch_list CMAKE_HOST_SYSTEM_PROCESSOR ) list( APPEND target_arch_list "UNKNOWN" ) # no architecture for which we have specific optimizations message( DEBUG "target_arch_list: ${target_arch_list}" ) # get most probable architecture list( POP_FRONT target_arch_list detected_arch ) message( STATUS "normalized target architecture: ${detected_arch}" ) set( ${output_var} "${detected_arch}" PARENT_SCOPE ) endfunction() function( _append_cpu_type_guess output_list input_var ) message( DEBUG "cpu_type_guess: input ${input_var}=${${input_var}}" ) set( input_str ${${input_var}} ) set( ret ${${output_list}} ) string( TOLOWER "${input_str}" input_lower ) if( ${input_lower} MATCHES "x86\|i.86\|x64\|win32\|amd64" ) list( APPEND ret "X86" ) elseif( ${input_lower} MATCHES "aarch64\|arm64") list( APPEND ret "AARCH64" ) elseif( ${input_lower} MATCHES "arm") list( APPEND ret "ARM" ) elseif( ${input_lower} MATCHES "loongarch64") list( APPEND ret "LOONGARCH64" ) endif() set( ${output_list} ${ret} PARENT_SCOPE ) endfunction()