| 1 | // Copyright 2022 Google Inc. All Rights Reserved. |
| 2 | // |
| 3 | // Use of this source code is governed by a BSD-style license |
| 4 | // that can be found in the COPYING 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 | // |
| 10 | // CPU detection functions and macros. |
| 11 | // |
| 12 | // Author: Skal (pascal.massimino@gmail.com) |
| 13 | |
| 14 | #ifndef WEBP_DSP_CPU_H_ |
| 15 | #define WEBP_DSP_CPU_H_ |
| 16 | |
| 17 | #include <stddef.h> |
| 18 | |
| 19 | #ifdef HAVE_CONFIG_H |
| 20 | #include "src/webp/config.h" |
| 21 | #endif |
| 22 | |
| 23 | #include "src/webp/types.h" |
| 24 | |
| 25 | #if defined(__GNUC__) |
| 26 | #define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__) |
| 27 | #define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min))) |
| 28 | #else |
| 29 | #define LOCAL_GCC_VERSION 0 |
| 30 | #define LOCAL_GCC_PREREQ(maj, min) 0 |
| 31 | #endif |
| 32 | |
| 33 | #if defined(__clang__) |
| 34 | #define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__) |
| 35 | #define LOCAL_CLANG_PREREQ(maj, min) \ |
| 36 | (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min))) |
| 37 | #else |
| 38 | #define LOCAL_CLANG_VERSION 0 |
| 39 | #define LOCAL_CLANG_PREREQ(maj, min) 0 |
| 40 | #endif |
| 41 | |
| 42 | #ifndef __has_builtin |
| 43 | #define __has_builtin(x) 0 |
| 44 | #endif |
| 45 | |
| 46 | //------------------------------------------------------------------------------ |
| 47 | // x86 defines. |
| 48 | |
| 49 | #if !defined(HAVE_CONFIG_H) |
| 50 | #if defined(_MSC_VER) && _MSC_VER > 1310 && \ |
| 51 | (defined(_M_X64) || defined(_M_IX86)) |
| 52 | #define WEBP_MSC_SSE2 // Visual C++ SSE2 targets |
| 53 | #endif |
| 54 | |
| 55 | #if defined(_MSC_VER) && _MSC_VER >= 1500 && \ |
| 56 | (defined(_M_X64) || defined(_M_IX86)) |
| 57 | #define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets |
| 58 | #endif |
| 59 | #endif |
| 60 | |
| 61 | // WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp |
| 62 | // files without intrinsics, allowing the corresponding Init() to be called. |
| 63 | // Files containing intrinsics will need to be built targeting the instruction |
| 64 | // set so should succeed on one of the earlier tests. |
| 65 | #if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \ |
| 66 | (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2)) |
| 67 | #define WEBP_USE_SSE2 |
| 68 | #endif |
| 69 | |
| 70 | #if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2) |
| 71 | #define WEBP_HAVE_SSE2 |
| 72 | #endif |
| 73 | |
| 74 | #if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \ |
| 75 | (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41)) |
| 76 | #define WEBP_USE_SSE41 |
| 77 | #endif |
| 78 | |
| 79 | #if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41) |
| 80 | #define WEBP_HAVE_SSE41 |
| 81 | #endif |
| 82 | |
| 83 | #undef WEBP_MSC_SSE41 |
| 84 | #undef WEBP_MSC_SSE2 |
| 85 | |
| 86 | //------------------------------------------------------------------------------ |
| 87 | // Arm defines. |
| 88 | |
| 89 | // The intrinsics currently cause compiler errors with arm-nacl-gcc and the |
| 90 | // inline assembly would need to be modified for use with Native Client. |
| 91 | #if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \ |
| 92 | (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \ |
| 93 | !defined(__native_client__) |
| 94 | #define WEBP_USE_NEON |
| 95 | #endif |
| 96 | |
| 97 | #if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \ |
| 98 | defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H) |
| 99 | #define WEBP_ANDROID_NEON // Android targets that may have NEON |
| 100 | #define WEBP_USE_NEON |
| 101 | #endif |
| 102 | |
| 103 | // Note: ARM64 is supported in Visual Studio 2017, but requires the direct |
| 104 | // inclusion of arm64_neon.h; Visual Studio 2019 includes this file in |
| 105 | // arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with |
| 106 | // vtbl4_u8(); a fix was made in 16.6. |
| 107 | #if defined(_MSC_VER) && \ |
| 108 | ((_MSC_VER >= 1700 && defined(_M_ARM)) || \ |
| 109 | (_MSC_VER >= 1926 && (defined(_M_ARM64) || defined(_M_ARM64EC)))) |
| 110 | #define WEBP_USE_NEON |
| 111 | #define WEBP_USE_INTRINSICS |
| 112 | #endif |
| 113 | |
| 114 | #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) |
| 115 | #define WEBP_AARCH64 1 |
| 116 | #else |
| 117 | #define WEBP_AARCH64 0 |
| 118 | #endif |
| 119 | |
| 120 | #if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON) |
| 121 | #define WEBP_HAVE_NEON |
| 122 | #endif |
| 123 | |
| 124 | //------------------------------------------------------------------------------ |
| 125 | // MIPS defines. |
| 126 | |
| 127 | #if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \ |
| 128 | (__mips_isa_rev >= 1) && (__mips_isa_rev < 6) |
| 129 | #define WEBP_USE_MIPS32 |
| 130 | #if (__mips_isa_rev >= 2) |
| 131 | #define WEBP_USE_MIPS32_R2 |
| 132 | #if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2) |
| 133 | #define WEBP_USE_MIPS_DSP_R2 |
| 134 | #endif |
| 135 | #endif |
| 136 | #endif |
| 137 | |
| 138 | #if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) |
| 139 | #define WEBP_USE_MSA |
| 140 | #endif |
| 141 | |
| 142 | //------------------------------------------------------------------------------ |
| 143 | |
| 144 | #ifndef WEBP_DSP_OMIT_C_CODE |
| 145 | #define WEBP_DSP_OMIT_C_CODE 1 |
| 146 | #endif |
| 147 | |
| 148 | #if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE |
| 149 | #define WEBP_NEON_OMIT_C_CODE 1 |
| 150 | #else |
| 151 | #define WEBP_NEON_OMIT_C_CODE 0 |
| 152 | #endif |
| 153 | |
| 154 | #if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || WEBP_AARCH64) |
| 155 | #define WEBP_NEON_WORK_AROUND_GCC 1 |
| 156 | #else |
| 157 | #define WEBP_NEON_WORK_AROUND_GCC 0 |
| 158 | #endif |
| 159 | |
| 160 | //------------------------------------------------------------------------------ |
| 161 | |
| 162 | // This macro prevents thread_sanitizer from reporting known concurrent writes. |
| 163 | #define WEBP_TSAN_IGNORE_FUNCTION |
| 164 | #if defined(__has_feature) |
| 165 | #if __has_feature(thread_sanitizer) |
| 166 | #undef WEBP_TSAN_IGNORE_FUNCTION |
| 167 | #define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread)) |
| 168 | #endif |
| 169 | #endif |
| 170 | |
| 171 | #if defined(__has_feature) |
| 172 | #if __has_feature(memory_sanitizer) |
| 173 | #define WEBP_MSAN |
| 174 | #endif |
| 175 | #endif |
| 176 | |
| 177 | #if defined(WEBP_USE_THREAD) && !defined(_WIN32) |
| 178 | #include <pthread.h> // NOLINT |
| 179 | |
| 180 | #define WEBP_DSP_INIT(func) \ |
| 181 | do { \ |
| 182 | static volatile VP8CPUInfo func##_last_cpuinfo_used = \ |
| 183 | (VP8CPUInfo)&func##_last_cpuinfo_used; \ |
| 184 | static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \ |
| 185 | if (pthread_mutex_lock(&func##_lock)) break; \ |
| 186 | if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \ |
| 187 | func##_last_cpuinfo_used = VP8GetCPUInfo; \ |
| 188 | (void)pthread_mutex_unlock(&func##_lock); \ |
| 189 | } while (0) |
| 190 | #else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) |
| 191 | #define WEBP_DSP_INIT(func) \ |
| 192 | do { \ |
| 193 | static volatile VP8CPUInfo func##_last_cpuinfo_used = \ |
| 194 | (VP8CPUInfo)&func##_last_cpuinfo_used; \ |
| 195 | if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \ |
| 196 | func(); \ |
| 197 | func##_last_cpuinfo_used = VP8GetCPUInfo; \ |
| 198 | } while (0) |
| 199 | #endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) |
| 200 | |
| 201 | // Defines an Init + helper function that control multiple initialization of |
| 202 | // function pointers / tables. |
| 203 | /* Usage: |
| 204 | WEBP_DSP_INIT_FUNC(InitFunc) { |
| 205 | ...function body |
| 206 | } |
| 207 | */ |
| 208 | #define WEBP_DSP_INIT_FUNC(name) \ |
| 209 | static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \ |
| 210 | WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \ |
| 211 | static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void) |
| 212 | |
| 213 | #define WEBP_UBSAN_IGNORE_UNDEF |
| 214 | #define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW |
| 215 | #if defined(__clang__) && defined(__has_attribute) |
| 216 | #if __has_attribute(no_sanitize) |
| 217 | // This macro prevents the undefined behavior sanitizer from reporting |
| 218 | // failures. This is only meant to silence unaligned loads on platforms that |
| 219 | // are known to support them. |
| 220 | #undef WEBP_UBSAN_IGNORE_UNDEF |
| 221 | #define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined"))) |
| 222 | |
| 223 | // This macro prevents the undefined behavior sanitizer from reporting |
| 224 | // failures related to unsigned integer overflows. This is only meant to |
| 225 | // silence cases where this well defined behavior is expected. |
| 226 | #undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW |
| 227 | #define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \ |
| 228 | __attribute__((no_sanitize("unsigned-integer-overflow"))) |
| 229 | #endif |
| 230 | #endif |
| 231 | |
| 232 | // If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'. |
| 233 | // Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning. |
| 234 | #if !defined(WEBP_OFFSET_PTR) |
| 235 | #define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off))) |
| 236 | #endif |
| 237 | |
| 238 | // Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility) |
| 239 | #if !defined(WEBP_SWAP_16BIT_CSP) |
| 240 | #define WEBP_SWAP_16BIT_CSP 0 |
| 241 | #endif |
| 242 | |
| 243 | // some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) |
| 244 | #if !defined(WORDS_BIGENDIAN) && \ |
| 245 | (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ |
| 246 | (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
| 247 | #define WORDS_BIGENDIAN |
| 248 | #endif |
| 249 | |
| 250 | typedef enum { |
| 251 | kSSE2, |
| 252 | kSSE3, |
| 253 | kSlowSSSE3, // special feature for slow SSSE3 architectures |
| 254 | kSSE4_1, |
| 255 | kAVX, |
| 256 | kAVX2, |
| 257 | kNEON, |
| 258 | kMIPS32, |
| 259 | kMIPSdspR2, |
| 260 | kMSA |
| 261 | } CPUFeature; |
| 262 | |
| 263 | // returns true if the CPU supports the feature. |
| 264 | typedef int (*VP8CPUInfo)(CPUFeature feature); |
| 265 | |
| 266 | #endif // WEBP_DSP_CPU_H_ |
| 267 | |