/src/libwebp/src/dsp/cpu.h
Line | Count | Source (jump to first uncovered line) |
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(HAVE_CONFIG_H) || 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 | 0 | do { \ |
197 | 0 | static volatile VP8CPUInfo func##_last_cpuinfo_used = \ |
198 | 0 | (VP8CPUInfo)&func##_last_cpuinfo_used; \ |
199 | 0 | static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \ |
200 | 0 | if (pthread_mutex_lock(&func##_lock)) break; \ |
201 | 0 | if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \ |
202 | 0 | func##_last_cpuinfo_used = VP8GetCPUInfo; \ |
203 | 0 | (void)pthread_mutex_unlock(&func##_lock); \ |
204 | 0 | } 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 | 0 | WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \ Unexecuted instantiation: vp8_dec.c:InitGetCoeffs Unexecuted instantiation: WebPInitAlphaProcessing Unexecuted instantiation: VP8EncDspCostInit Unexecuted instantiation: VP8DspInit Unexecuted instantiation: VP8EncDspInit Unexecuted instantiation: VP8FiltersInit Unexecuted instantiation: VP8LDspInit Unexecuted instantiation: WebPRescalerDspInit Unexecuted instantiation: WebPInitYUV444Converters Unexecuted instantiation: WebPInitUpsamplers Unexecuted instantiation: WebPInitSamplers Unexecuted instantiation: WebPInitConvertARGBToYUV Unexecuted instantiation: picture_csp_enc.c:InitGammaTables Unexecuted instantiation: VP8LEncDspInit Unexecuted instantiation: VP8SSIMDspInit |
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 | 0 | #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_ |