xref: /aosp_15_r20/external/webp/src/dsp/cpu.h (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
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 ([email protected])
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