1# Check for SIMD extensions.
2include(CMakePushCheckState)
3
4function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
5  if(NOT ENABLE_SIMD)
6    message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.")
7    set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
8    return()
9  endif()
10  unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
11  cmake_push_check_state()
12  set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
13  check_c_source_compiles("
14      #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
15      int main(void) {
16        #if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
17        this is not valid code
18        #endif
19        return 0;
20      }
21    " WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
22  cmake_pop_check_state()
23  if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
24    set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
25  else()
26    set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
27  endif()
28endfunction()
29
30# those are included in the names of WEBP_USE_* in c++ code.
31set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
32set(WEBP_SIMD_FILE_EXTENSIONS
33    "_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
34if(MSVC)
35  # MSVC does not have a SSE4 flag but AVX support implies SSE4 support.
36  set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;")
37  set(SIMD_DISABLE_FLAGS)
38else()
39  set(SIMD_ENABLE_FLAGS
40      "-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
41  set(SIMD_DISABLE_FLAGS
42      "-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
43endif()
44
45set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
46set(WEBP_SIMD_FILES_TO_INCLUDE)
47set(WEBP_SIMD_FLAGS_TO_INCLUDE)
48
49if(${ANDROID})
50  if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
51    # This is because Android studio uses the configuration "-march=armv7-a
52    # -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
53    # optimizations but should (as this configuration does not exist anymore).
54    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
55  endif()
56endif()
57
58list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
59math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
60unset(HIGHEST_SSE_FLAG)
61
62foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
63  list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
64
65  # First try with no extra flag added as the compiler might have default flags
66  # (especially on Android).
67  unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
68  cmake_push_check_state()
69  set(CMAKE_REQUIRED_FLAGS)
70  webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
71  if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
72    list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
73    set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
74    webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
75  else()
76    if(MSVC)
77      list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
78    else()
79      set(SIMD_COMPILE_FLAG " ")
80    endif()
81  endif()
82  # Check which files we should include or not.
83  list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
84  file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
85            "src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
86  if(WEBP_HAVE_${WEBP_SIMD_FLAG})
87    if(${I_SIMD} LESS 2 AND NOT HIGHEST_SSE_FLAG)
88      set(HIGHEST_SSE_FLAG ${SIMD_COMPILE_FLAG})
89    endif()
90    # Memorize the file and flags.
91    foreach(FILE ${SIMD_FILES})
92      list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
93      if(${I_SIMD} LESS 2)
94        list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${HIGHEST_SSE_FLAG})
95      else()
96        list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG})
97      endif()
98    endforeach()
99  else()
100    # Remove the file from the list.
101    foreach(FILE ${SIMD_FILES})
102      list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
103    endforeach()
104    # Explicitly disable SIMD.
105    if(SIMD_DISABLE_FLAGS)
106      list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
107      include(CheckCCompilerFlag)
108      if(SIMD_COMPILE_FLAG)
109        unset(HAS_COMPILE_FLAG CACHE)
110        check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
111        if(HAS_COMPILE_FLAG)
112          # Do one more check for Clang to circumvent CMake issue 13194.
113          if(COMMAND check_compiler_flag_common_patterns)
114            # Only in CMake 3.0 and above.
115            check_compiler_flag_common_patterns(COMMON_PATTERNS)
116          else()
117            set(COMMON_PATTERNS)
118          endif()
119          set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
120          check_c_source_compiles("int main(void) {return 0;}"
121                                  FLAG_${SIMD_COMPILE_FLAG}
122                                  FAIL_REGEX
123                                  "warning: argument unused during compilation:"
124                                  ${COMMON_PATTERNS})
125          if(NOT FLAG_${SIMD_COMPILE_FLAG})
126            unset(HAS_COMPILE_FLAG CACHE)
127          endif()
128        endif()
129        if(HAS_COMPILE_FLAG)
130          set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
131        endif()
132      endif()
133    endif()
134  endif()
135  cmake_pop_check_state()
136endforeach()
137