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