/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 | | #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 | 0 | do { \ |
182 | 0 | static volatile VP8CPUInfo func##_last_cpuinfo_used = \ |
183 | 0 | (VP8CPUInfo)&func##_last_cpuinfo_used; \ |
184 | 0 | static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \ |
185 | 0 | if (pthread_mutex_lock(&func##_lock)) break; \ |
186 | 0 | if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \ |
187 | 0 | func##_last_cpuinfo_used = VP8GetCPUInfo; \ |
188 | 0 | (void)pthread_mutex_unlock(&func##_lock); \ |
189 | 0 | } 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 | 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 |
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 | 0 | #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_ |