1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/* WIKI CATEGORY: Intrinsics */
23
24/**
25 * # CategoryIntrinsics
26 *
27 * SDL does some preprocessor gymnastics to determine if any CPU-specific
28 * compiler intrinsics are available, as this is not necessarily an easy thing
29 * to calculate, and sometimes depends on quirks of a system, versions of
30 * build tools, and other external forces.
31 *
32 * Apps including SDL's headers will be able to check consistent preprocessor
33 * definitions to decide if it's safe to use compiler intrinsics for a
34 * specific CPU architecture. This check only tells you that the compiler is
35 * capable of using those intrinsics; at runtime, you should still check if
36 * they are available on the current system with the
37 * [CPU info functions](https://wiki.libsdl.org/SDL3/CategoryCPUInfo)
38 * , such as SDL_HasSSE() or SDL_HasNEON(). Otherwise, the process might crash
39 * for using an unsupported CPU instruction.
40 *
41 * SDL only sets preprocessor defines for CPU intrinsics if they are
42 * supported, so apps should check with `#ifdef` and not `#if`.
43 *
44 * SDL will also include the appropriate instruction-set-specific support
45 * headers, so if SDL decides to define SDL_SSE2_INTRINSICS, it will also
46 * `#include <emmintrin.h>` as well.
47 */
48
49#ifndef SDL_intrin_h_
50#define SDL_intrin_h_
51
52#include <SDL3/SDL_stdinc.h>
53
54#ifdef SDL_WIKI_DOCUMENTATION_SECTION
55
56/**
57 * Defined if (and only if) the compiler supports Loongarch LSX intrinsics.
58 *
59 * If this macro is defined, SDL will have already included `<lsxintrin.h>`
60 *
61 * \since This macro is available since SDL 3.2.0.
62 *
63 * \sa SDL_LASX_INTRINSICS
64 */
65#define SDL_LSX_INTRINSICS 1
66
67/**
68 * Defined if (and only if) the compiler supports Loongarch LSX intrinsics.
69 *
70 * If this macro is defined, SDL will have already included `<lasxintrin.h>`
71 *
72 * \since This macro is available since SDL 3.2.0.
73 *
74 * \sa SDL_LASX_INTRINSICS
75 */
76#define SDL_LASX_INTRINSICS 1
77
78/**
79 * Defined if (and only if) the compiler supports ARM NEON intrinsics.
80 *
81 * If this macro is defined, SDL will have already included `<armintr.h>`
82 * `<arm_neon.h>`, `<arm64intr.h>`, and `<arm64_neon.h>`, as appropriate.
83 *
84 * \since This macro is available since SDL 3.2.0.
85 */
86#define SDL_NEON_INTRINSICS 1
87
88/**
89 * Defined if (and only if) the compiler supports PowerPC Altivec intrinsics.
90 *
91 * If this macro is defined, SDL will have already included `<altivec.h>`
92 *
93 * \since This macro is available since SDL 3.2.0.
94 */
95#define SDL_ALTIVEC_INTRINSICS 1
96
97/**
98 * Defined if (and only if) the compiler supports Intel MMX intrinsics.
99 *
100 * If this macro is defined, SDL will have already included `<mmintrin.h>`
101 *
102 * \since This macro is available since SDL 3.2.0.
103 *
104 * \sa SDL_SSE_INTRINSICS
105 */
106#define SDL_MMX_INTRINSICS 1
107
108/**
109 * Defined if (and only if) the compiler supports Intel SSE intrinsics.
110 *
111 * If this macro is defined, SDL will have already included `<xmmintrin.h>`
112 *
113 * \since This macro is available since SDL 3.2.0.
114 *
115 * \sa SDL_SSE2_INTRINSICS
116 * \sa SDL_SSE3_INTRINSICS
117 * \sa SDL_SSE4_1_INTRINSICS
118 * \sa SDL_SSE4_2_INTRINSICS
119 */
120#define SDL_SSE_INTRINSICS 1
121
122/**
123 * Defined if (and only if) the compiler supports Intel SSE2 intrinsics.
124 *
125 * If this macro is defined, SDL will have already included `<emmintrin.h>`
126 *
127 * \since This macro is available since SDL 3.2.0.
128 *
129 * \sa SDL_SSE_INTRINSICS
130 * \sa SDL_SSE3_INTRINSICS
131 * \sa SDL_SSE4_1_INTRINSICS
132 * \sa SDL_SSE4_2_INTRINSICS
133 */
134#define SDL_SSE2_INTRINSICS 1
135
136/**
137 * Defined if (and only if) the compiler supports Intel SSE3 intrinsics.
138 *
139 * If this macro is defined, SDL will have already included `<pmmintrin.h>`
140 *
141 * \since This macro is available since SDL 3.2.0.
142 *
143 * \sa SDL_SSE_INTRINSICS
144 * \sa SDL_SSE2_INTRINSICS
145 * \sa SDL_SSE4_1_INTRINSICS
146 * \sa SDL_SSE4_2_INTRINSICS
147 */
148#define SDL_SSE3_INTRINSICS 1
149
150/**
151 * Defined if (and only if) the compiler supports Intel SSE4.1 intrinsics.
152 *
153 * If this macro is defined, SDL will have already included `<smmintrin.h>`
154 *
155 * \since This macro is available since SDL 3.2.0.
156 *
157 * \sa SDL_SSE_INTRINSICS
158 * \sa SDL_SSE2_INTRINSICS
159 * \sa SDL_SSE3_INTRINSICS
160 * \sa SDL_SSE4_2_INTRINSICS
161 */
162#define SDL_SSE4_1_INTRINSICS 1
163
164/**
165 * Defined if (and only if) the compiler supports Intel SSE4.2 intrinsics.
166 *
167 * If this macro is defined, SDL will have already included `<nmmintrin.h>`
168 *
169 * \since This macro is available since SDL 3.2.0.
170 *
171 * \sa SDL_SSE_INTRINSICS
172 * \sa SDL_SSE2_INTRINSICS
173 * \sa SDL_SSE3_INTRINSICS
174 * \sa SDL_SSE4_1_INTRINSICS
175 */
176#define SDL_SSE4_2_INTRINSICS 1
177
178/**
179 * Defined if (and only if) the compiler supports Intel AVX intrinsics.
180 *
181 * If this macro is defined, SDL will have already included `<immintrin.h>`
182 *
183 * \since This macro is available since SDL 3.2.0.
184 *
185 * \sa SDL_AVX2_INTRINSICS
186 * \sa SDL_AVX512F_INTRINSICS
187 */
188#define SDL_AVX_INTRINSICS 1
189
190/**
191 * Defined if (and only if) the compiler supports Intel AVX2 intrinsics.
192 *
193 * If this macro is defined, SDL will have already included `<immintrin.h>`
194 *
195 * \since This macro is available since SDL 3.2.0.
196 *
197 * \sa SDL_AVX_INTRINSICS
198 * \sa SDL_AVX512F_INTRINSICS
199 */
200#define SDL_AVX2_INTRINSICS 1
201
202/**
203 * Defined if (and only if) the compiler supports Intel AVX-512F intrinsics.
204 *
205 * AVX-512F is also sometimes referred to as "AVX-512 Foundation."
206 *
207 * If this macro is defined, SDL will have already included `<immintrin.h>`
208 *
209 * \since This macro is available since SDL 3.2.0.
210 *
211 * \sa SDL_AVX_INTRINSICS
212 * \sa SDL_AVX2_INTRINSICS
213 */
214#define SDL_AVX512F_INTRINSICS 1
215#endif
216
217/* Need to do this here because intrin.h has C++ code in it */
218/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
219#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64))
220#ifdef __clang__
221/* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
222 so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
223#ifndef __PRFCHWINTRIN_H
224#define __PRFCHWINTRIN_H
225static __inline__ void __attribute__((__always_inline__, __nodebug__))
226_m_prefetch(void *__P)
227{
228 __builtin_prefetch (__P, 0, 3 /* _MM_HINT_T0 */);
229}
230#endif /* __PRFCHWINTRIN_H */
231#endif /* __clang__ */
232#include <intrin.h>
233
234#elif defined(__MINGW64_VERSION_MAJOR)
235#include <intrin.h>
236#if defined(__ARM_NEON) && !defined(SDL_DISABLE_NEON)
237# define SDL_NEON_INTRINSICS 1
238# include <arm_neon.h>
239#endif
240
241#else
242/* altivec.h redefining bool causes a number of problems, see bugs 3993 and 4392, so you need to explicitly define SDL_ENABLE_ALTIVEC to have it included. */
243#if defined(__ALTIVEC__) && defined(SDL_ENABLE_ALTIVEC)
244#define SDL_ALTIVEC_INTRINSICS 1
245#include <altivec.h>
246#endif
247#ifndef SDL_DISABLE_NEON
248# ifdef __ARM_NEON
249# define SDL_NEON_INTRINSICS 1
250# include <arm_neon.h>
251# elif defined(SDL_PLATFORM_WINDOWS)
252/* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
253# ifdef _M_ARM
254# define SDL_NEON_INTRINSICS 1
255# include <armintr.h>
256# include <arm_neon.h>
257# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
258# endif
259# if defined (_M_ARM64)
260# define SDL_NEON_INTRINSICS 1
261# include <arm64intr.h>
262# include <arm64_neon.h>
263# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
264# define __ARM_ARCH 8
265# endif
266# endif
267#endif
268#endif /* compiler version */
269
270#ifdef SDL_WIKI_DOCUMENTATION_SECTION
271/**
272 * A macro to decide if the compiler supports `__attribute__((target))`.
273 *
274 * Even though this is defined in SDL's public headers, it is generally not
275 * used directly by apps. Apps should probably just use SDL_TARGETING
276 * directly, instead.
277 *
278 * \since This macro is available since SDL 3.2.0.
279 *
280 * \sa SDL_TARGETING
281 */
282#define SDL_HAS_TARGET_ATTRIBS
283
284#elif defined(__clang__) && defined(__has_attribute)
285# if __has_attribute(target)
286# define SDL_HAS_TARGET_ATTRIBS
287# endif
288#elif defined(__GNUC__) && (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) /* gcc >= 4.9 */
289# define SDL_HAS_TARGET_ATTRIBS
290#elif defined(__ICC) && __ICC >= 1600
291# define SDL_HAS_TARGET_ATTRIBS
292#endif
293
294
295#ifdef SDL_WIKI_DOCUMENTATION_SECTION
296
297/**
298 * A macro to tag a function as targeting a specific CPU architecture.
299 *
300 * This is a hint to the compiler that a function should be built with support
301 * for a CPU instruction set that might be different than the rest of the
302 * program.
303 *
304 * The particulars of this are explained in the GCC documentation:
305 *
306 * https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-target-function-attribute
307 *
308 * An example of using this feature is to turn on SSE2 support for a specific
309 * function, even if the rest of the source code is not compiled to use SSE2
310 * code:
311 *
312 * ```c
313 * #ifdef SDL_SSE2_INTRINSICS
314 * static void SDL_TARGETING("sse2") DoSomethingWithSSE2(char *x) {
315 * ...use SSE2 intrinsic functions, etc...
316 * }
317 * #endif
318 *
319 * // later...
320 * #ifdef SDL_SSE2_INTRINSICS
321 * if (SDL_HasSSE2()) {
322 * DoSomethingWithSSE2(str);
323 * }
324 * #endif
325 * ```
326 *
327 * The application is, on a whole, built without SSE2 instructions, so it will
328 * run on Intel machines that don't support SSE2. But then at runtime, it
329 * checks if the system supports the instructions, and then calls into a
330 * function that uses SSE2 opcodes. The ifdefs make sure that this code isn't
331 * used on platforms that don't have SSE2 at all.
332 *
333 * On compilers without target support, this is defined to nothing.
334 *
335 * This symbol is used by SDL internally, but apps and other libraries are
336 * welcome to use it for their own interfaces as well.
337 *
338 * \since This macro is available since SDL 3.2.0.
339 */
340#define SDL_TARGETING(x) __attribute__((target(x)))
341
342#elif defined(SDL_HAS_TARGET_ATTRIBS)
343# define SDL_TARGETING(x) __attribute__((target(x)))
344#else
345# define SDL_TARGETING(x)
346#endif
347
348#ifdef __loongarch64
349# ifndef SDL_DISABLE_LSX
350# define SDL_LSX_INTRINSICS 1
351# include <lsxintrin.h>
352# endif
353# ifndef SDL_DISABLE_LASX
354# define SDL_LASX_INTRINSICS 1
355# include <lasxintrin.h>
356# endif
357#endif
358
359#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
360# if ((defined(_MSC_VER) && !defined(_M_X64)) || defined(__MMX__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_MMX)
361# define SDL_MMX_INTRINSICS 1
362# include <mmintrin.h>
363# endif
364# if (defined(_MSC_VER) || defined(__SSE__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE)
365# define SDL_SSE_INTRINSICS 1
366# include <xmmintrin.h>
367# endif
368# if (defined(_MSC_VER) || defined(__SSE2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE2)
369# define SDL_SSE2_INTRINSICS 1
370# include <emmintrin.h>
371# endif
372# if (defined(_MSC_VER) || defined(__SSE3__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE3)
373# define SDL_SSE3_INTRINSICS 1
374# include <pmmintrin.h>
375# endif
376# if (defined(_MSC_VER) || defined(__SSE4_1__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE4_1)
377# define SDL_SSE4_1_INTRINSICS 1
378# include <smmintrin.h>
379# endif
380# if (defined(_MSC_VER) || defined(__SSE4_2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE4_2)
381# define SDL_SSE4_2_INTRINSICS 1
382# include <nmmintrin.h>
383# endif
384# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX__) && !defined(SDL_DISABLE_AVX)
385# define SDL_DISABLE_AVX /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
386# endif
387# if (defined(_MSC_VER) || defined(__AVX__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX)
388# define SDL_AVX_INTRINSICS 1
389# include <immintrin.h>
390# endif
391# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX2__) && !defined(SDL_DISABLE_AVX2)
392# define SDL_DISABLE_AVX2 /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
393# endif
394# if (defined(_MSC_VER) || defined(__AVX2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX2)
395# define SDL_AVX2_INTRINSICS 1
396# include <immintrin.h>
397# endif
398# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX512F__) && !defined(SDL_DISABLE_AVX512F)
399# define SDL_DISABLE_AVX512F /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
400# endif
401# if (defined(_MSC_VER) || defined(__AVX512F__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX512F)
402# define SDL_AVX512F_INTRINSICS 1
403# include <immintrin.h>
404# endif
405#endif /* defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) */
406
407#endif /* SDL_intrin_h_ */
408