1# Copyright (c) 2021 Google LLC. 2# 3# Use of this source code is governed by a BSD-style license 4# that can be found in the LICENSE file in the root of the source 5# tree. An additional intellectual property rights grant can be found 6# in the file PATENTS. All contributing project authors may 7# be found in the AUTHORS file in the root of the source tree. 8 9# Check for SIMD extensions. 10include(CMakePushCheckState) 11 12function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD) 13 if(NOT ENABLE_SIMD) 14 message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.") 15 set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) 16 return() 17 endif() 18 unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE) 19 cmake_push_check_state() 20 set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) 21 check_c_source_compiles( 22 " 23 #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\" 24 int main(void) { 25 #if !defined(WEBP_USE_${WEBP_SIMD_FLAG}) 26 this is not valid code 27 #endif 28 return 0; 29 } 30 " 31 WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) 32 cmake_pop_check_state() 33 if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) 34 set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE) 35 else() 36 set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) 37 endif() 38endfunction() 39 40# those are included in the names of WEBP_USE_* in c++ code. 41set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA") 42set(WEBP_SIMD_FILE_EXTENSIONS 43 "_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c") 44if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") 45 # With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2 46 # or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4 47 # flag, but an AVX one. Using that with SSE4 code risks generating illegal 48 # instructions when used on machines with SSE4 only. The flags are left for 49 # older (untested) versions to avoid any potential compatibility issues. 50 if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:") 51 set(SIMD_ENABLE_FLAGS) 52 else() 53 set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;") 54 endif() 55 set(SIMD_DISABLE_FLAGS) 56else() 57 set(SIMD_ENABLE_FLAGS "-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa") 58 set(SIMD_DISABLE_FLAGS "-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa") 59endif() 60 61set(WEBP_SIMD_FILES_TO_INCLUDE) 62set(WEBP_SIMD_FLAGS_TO_INCLUDE) 63 64if(ANDROID AND ANDROID_ABI) 65 if(${ANDROID_ABI} STREQUAL "armeabi-v7a") 66 # This is because Android studio uses the configuration "-march=armv7-a 67 # -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon 68 # optimizations but should (as this configuration does not exist anymore). 69 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ") 70 endif() 71endif() 72 73list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH) 74math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1") 75 76foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE}) 77 # With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source 78 # will fail to compile. 79 if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2) 80 break() 81 endif() 82 83 list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG) 84 85 # First try with no extra flag added as the compiler might have default flags 86 # (especially on Android). 87 unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE) 88 cmake_push_check_state() 89 set(CMAKE_REQUIRED_FLAGS) 90 webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) 91 if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG}) 92 list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) 93 if(EMSCRIPTEN) 94 set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}") 95 endif() 96 set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG}) 97 webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) 98 else() 99 if(MSVC AND SIMD_ENABLE_FLAGS) 100 # The detection for SSE2/SSE4 support under MSVC is based on the compiler 101 # version so e.g., clang-cl will require flags to enable the assembly. 102 list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) 103 else() 104 set(SIMD_COMPILE_FLAG " ") 105 endif() 106 endif() 107 # Check which files we should include or not. 108 list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION) 109 file(GLOB SIMD_FILES 110 "${CMAKE_CURRENT_LIST_DIR}/../sharpyuv/*${WEBP_SIMD_FILE_EXTENSION}" 111 "${CMAKE_CURRENT_LIST_DIR}/../src/dsp/*${WEBP_SIMD_FILE_EXTENSION}") 112 if(WEBP_HAVE_${WEBP_SIMD_FLAG}) 113 # Memorize the file and flags. 114 foreach(FILE ${SIMD_FILES}) 115 list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE}) 116 list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG}) 117 endforeach() 118 else() 119 # Remove the file from the list. 120 foreach(FILE ${SIMD_FILES}) 121 list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE}) 122 endforeach() 123 # Explicitly disable SIMD. 124 if(SIMD_DISABLE_FLAGS) 125 list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) 126 include(CheckCCompilerFlag) 127 if(SIMD_COMPILE_FLAG) 128 # Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal 129 # variable at parent scope while check_cxx_source_compiles() continues 130 # to set an internal cache variable, so we unset both to avoid the 131 # failure / success state persisting between checks. See 132 # https://gitlab.kitware.com/cmake/cmake/-/issues/21207. 133 unset(HAS_COMPILE_FLAG) 134 unset(HAS_COMPILE_FLAG CACHE) 135 check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG) 136 if(HAS_COMPILE_FLAG) 137 # Do one more check for Clang to circumvent CMake issue 13194. 138 if(COMMAND check_compiler_flag_common_patterns) 139 # Only in CMake 3.0 and above. 140 check_compiler_flag_common_patterns(COMMON_PATTERNS) 141 else() 142 set(COMMON_PATTERNS) 143 endif() 144 set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG}) 145 check_c_source_compiles( 146 "int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX 147 "warning: argument unused during compilation:" ${COMMON_PATTERNS}) 148 if(NOT FLAG_${SIMD_COMPILE_FLAG}) 149 unset(HAS_COMPILE_FLAG) 150 unset(HAS_COMPILE_FLAG CACHE) 151 endif() 152 endif() 153 if(HAS_COMPILE_FLAG) 154 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}") 155 endif() 156 endif() 157 endif() 158 endif() 159 cmake_pop_check_state() 160endforeach() 161