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 | |