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