# Copyright (c) 2021 Google LLC. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. # Check for SIMD extensions. include(CMakePushCheckState) function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD) if(NOT ENABLE_SIMD) message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.") set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) return() endif() unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE) cmake_push_check_state() set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) check_c_source_compiles(" #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\" int main(void) { #if !defined(WEBP_USE_${WEBP_SIMD_FLAG}) this is not valid code #endif return 0; } " WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) cmake_pop_check_state() if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE) else() set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) endif() endfunction() # those are included in the names of WEBP_USE_* in c++ code. set(WEBP_SIMD_FLAGS "WASM_SIMD;SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA") set(WEBP_SIMD_FILE_EXTENSIONS "_wasm.c;_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c") if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") # With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2 # or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4 # flag, but an AVX one. Using that with SSE4 code risks generating illegal # instructions when used on machines with SSE4 only. The flags are left for # older (untested) versions to avoid any potential compatibility issues. if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:") set(SIMD_ENABLE_FLAGS) else() set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;") endif() set(SIMD_DISABLE_FLAGS) else() set(SIMD_ENABLE_FLAGS "-msimd128;-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa") set(SIMD_DISABLE_FLAGS "-mno-simd128;-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa") endif() set(WEBP_SIMD_FILES_TO_NOT_INCLUDE) set(WEBP_SIMD_FILES_TO_INCLUDE) set(WEBP_SIMD_FLAGS_TO_INCLUDE) if(${ANDROID}) if(${ANDROID_ABI} STREQUAL "armeabi-v7a") # This is because Android studio uses the configuration "-march=armv7-a # -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon # optimizations but should (as this configuration does not exist anymore). set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ") endif() endif() list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH) math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1") foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE}) # With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the # source will fail to compile. if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 5) break() endif() # Emscripten supports SSE via compat headers, if WEBP_ENABLED_WASM_SIMD is # specified skip testing those (because it will succeed). if (EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 1 AND ${WEBP_ENABLE_WASM_SIMD}) break() endif() list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG) # First try with no extra flag added as the compiler might have default flags # (especially on Android). unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE) cmake_push_check_state() set(CMAKE_REQUIRED_FLAGS) webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG}) list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) # This enables using Emscripten's SSE compatibility headers. if(EMSCRIPTEN) set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}") endif() set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG}) webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) else() if(MSVC AND SIMD_ENABLE_FLAGS) # The detection for SSE2/SSE4 support under MSVC is based on the compiler # version so e.g., clang-cl will require flags to enable the assembly. list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) else() set(SIMD_COMPILE_FLAG " ") endif() endif() # Check which files we should include or not. list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION) file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../" "src/dsp/*${WEBP_SIMD_FILE_EXTENSION}") if(WEBP_HAVE_${WEBP_SIMD_FLAG}) # Memorize the file and flags. foreach(FILE ${SIMD_FILES}) list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE}) list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG}) endforeach() else() # Remove the file from the list. foreach(FILE ${SIMD_FILES}) list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE}) endforeach() # Explicitly disable SIMD. if(SIMD_DISABLE_FLAGS) list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) include(CheckCCompilerFlag) if(SIMD_COMPILE_FLAG) # Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal # variable at parent scope while check_cxx_source_compiles() continues # to set an internal cache variable, so we unset both to avoid the # failure / success state persisting between checks. See # https://gitlab.kitware.com/cmake/cmake/-/issues/21207. unset(HAS_COMPILE_FLAG) unset(HAS_COMPILE_FLAG CACHE) check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG) if(HAS_COMPILE_FLAG) # Do one more check for Clang to circumvent CMake issue 13194. if(COMMAND check_compiler_flag_common_patterns) # Only in CMake 3.0 and above. check_compiler_flag_common_patterns(COMMON_PATTERNS) else() set(COMMON_PATTERNS) endif() set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG}) check_c_source_compiles("int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX "warning: argument unused during compilation:" ${COMMON_PATTERNS}) if(NOT FLAG_${SIMD_COMPILE_FLAG}) unset(HAS_COMPILE_FLAG) unset(HAS_COMPILE_FLAG CACHE) endif() endif() if(HAS_COMPILE_FLAG) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}") endif() endif() endif() endif() cmake_pop_check_state() endforeach()