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
250typedef 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.
264typedef int (*VP8CPUInfo)(CPUFeature feature);
265
266#endif // WEBP_DSP_CPU_H_
267