xref: /aosp_15_r20/external/webp/cmake/cpu.cmake (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
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