SDL 3.0
SDL_intrin.h
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2026 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 ARM SVE2 intrinsics.
90 *
91 * If this macro is defined, `<arm_sve.h>` (providing SVE intrinsics) will
92 * only be included if the target architecture supports SVE
93 * (`__ARM_FEATURE_SVE` feature macro). Some toolchains do not support
94 * `SDL_TARGETING("arch=armv8-a+sve2")`, so for best portability you need to
95 * write all SVE code in a separate translation unit and add appropriate
96 * compile flags.
97 *
98 * \since This macro is available since SDL 3.6.0.
99 */
100#define SDL_SVE2_INTRINSICS 1
101
102/**
103 * Defined if (and only if) the compiler supports PowerPC Altivec intrinsics.
104 *
105 * If this macro is defined, SDL will have already included `<altivec.h>`
106 *
107 * \since This macro is available since SDL 3.2.0.
108 */
109#define SDL_ALTIVEC_INTRINSICS 1
110
111/**
112 * Defined if (and only if) the compiler supports Intel MMX intrinsics.
113 *
114 * If this macro is defined, SDL will have already included `<mmintrin.h>`
115 *
116 * \since This macro is available since SDL 3.2.0.
117 *
118 * \sa SDL_SSE_INTRINSICS
119 */
120#define SDL_MMX_INTRINSICS 1
121
122/**
123 * Defined if (and only if) the compiler supports Intel SSE intrinsics.
124 *
125 * If this macro is defined, SDL will have already included `<xmmintrin.h>`
126 *
127 * \since This macro is available since SDL 3.2.0.
128 *
129 * \sa SDL_SSE2_INTRINSICS
130 * \sa SDL_SSE3_INTRINSICS
131 * \sa SDL_SSE4_1_INTRINSICS
132 * \sa SDL_SSE4_2_INTRINSICS
133 */
134#define SDL_SSE_INTRINSICS 1
135
136/**
137 * Defined if (and only if) the compiler supports Intel SSE2 intrinsics.
138 *
139 * If this macro is defined, SDL will have already included `<emmintrin.h>`
140 *
141 * \since This macro is available since SDL 3.2.0.
142 *
143 * \sa SDL_SSE_INTRINSICS
144 * \sa SDL_SSE3_INTRINSICS
145 * \sa SDL_SSE4_1_INTRINSICS
146 * \sa SDL_SSE4_2_INTRINSICS
147 */
148#define SDL_SSE2_INTRINSICS 1
149
150/**
151 * Defined if (and only if) the compiler supports Intel SSE3 intrinsics.
152 *
153 * If this macro is defined, SDL will have already included `<pmmintrin.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_SSE4_1_INTRINSICS
160 * \sa SDL_SSE4_2_INTRINSICS
161 */
162#define SDL_SSE3_INTRINSICS 1
163
164/**
165 * Defined if (and only if) the compiler supports Intel SSE4.1 intrinsics.
166 *
167 * If this macro is defined, SDL will have already included `<smmintrin.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_2_INTRINSICS
175 */
176#define SDL_SSE4_1_INTRINSICS 1
177
178/**
179 * Defined if (and only if) the compiler supports Intel SSE4.2 intrinsics.
180 *
181 * If this macro is defined, SDL will have already included `<nmmintrin.h>`
182 *
183 * \since This macro is available since SDL 3.2.0.
184 *
185 * \sa SDL_SSE_INTRINSICS
186 * \sa SDL_SSE2_INTRINSICS
187 * \sa SDL_SSE3_INTRINSICS
188 * \sa SDL_SSE4_1_INTRINSICS
189 */
190#define SDL_SSE4_2_INTRINSICS 1
191
192/**
193 * Defined if (and only if) the compiler supports Intel AVX intrinsics.
194 *
195 * If this macro is defined, SDL will have already included `<immintrin.h>`
196 *
197 * \since This macro is available since SDL 3.2.0.
198 *
199 * \sa SDL_AVX2_INTRINSICS
200 * \sa SDL_AVX512F_INTRINSICS
201 */
202#define SDL_AVX_INTRINSICS 1
203
204/**
205 * Defined if (and only if) the compiler supports Intel AVX2 intrinsics.
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_AVX512F_INTRINSICS
213 */
214#define SDL_AVX2_INTRINSICS 1
215
216/**
217 * Defined if (and only if) the compiler supports Intel AVX-512F intrinsics.
218 *
219 * AVX-512F is also sometimes referred to as "AVX-512 Foundation."
220 *
221 * If this macro is defined, SDL will have already included `<immintrin.h>`
222 *
223 * \since This macro is available since SDL 3.2.0.
224 *
225 * \sa SDL_AVX_INTRINSICS
226 * \sa SDL_AVX2_INTRINSICS
227 */
228#define SDL_AVX512F_INTRINSICS 1
229#endif
230
231/* Need to do this here because intrin.h has C++ code in it */
232/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
233#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64))
234/* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
235 so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
236#if defined(__clang__) && !SDL_HAS_BUILTIN(_m_prefetch)
237#ifndef __PRFCHWINTRIN_H
238#define __PRFCHWINTRIN_H
239static __inline__ void __attribute__((__always_inline__, __nodebug__))
240_m_prefetch(void *__P)
241{
242 __builtin_prefetch (__P, 0, 3 /* _MM_HINT_T0 */);
243}
244#endif /* __PRFCHWINTRIN_H */
245#endif /* __clang__ */
246#include <intrin.h>
247
248#elif defined(__MINGW64_VERSION_MAJOR)
249#include <intrin.h>
250#if defined(__ARM_NEON) && !defined(SDL_DISABLE_NEON)
251# define SDL_NEON_INTRINSICS 1
252# include <arm_neon.h>
253#endif
254#if !defined(SDL_DISABLE_SVE2)
255# define SDL_SVE2_INTRINSICS 1
256# if defined(__ARM_FEATURE_SVE)
257# include <arm_sve.h>
258# endif
259#endif
260
261#else
262/* 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. */
263#if defined(__ALTIVEC__) && defined(SDL_ENABLE_ALTIVEC)
264#define SDL_ALTIVEC_INTRINSICS 1
265#include <altivec.h>
266#endif
267#ifndef SDL_DISABLE_NEON
268# ifdef __ARM_NEON
269# define SDL_NEON_INTRINSICS 1
270# include <arm_neon.h>
271# elif defined(SDL_PLATFORM_WINDOWS)
272/* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
273# ifdef _M_ARM
274# define SDL_NEON_INTRINSICS 1
275# include <armintr.h>
276# include <arm_neon.h>
277# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
278# endif
279# if defined (_M_ARM64)
280# define SDL_NEON_INTRINSICS 1
281# include <arm64intr.h>
282# include <arm64_neon.h>
283# define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
284# define __ARM_ARCH 8
285# endif
286# endif
287#endif
288#ifndef SDL_DISABLE_SVE2
289# if defined(SDL_PLATFORM_WINDOWS)
290/* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
291# if defined (_M_ARM64) && 0 /* Please only remove this 0 when MSVC releasing support for SVE2 officially. */
292# define SDL_SVE2_INTRINSICS 1
293# define __ARM_FEATURE_SVE2 1 /* Set __ARM_FEATURE_SVE2 so that it can be used elsewhere, at compile time */
294# define __ARM_FEATURE_SVE 1 /* Set __ARM_FEATURE_SVE so that it can be used elsewhere, at compile time */
295# define __ARM_ARCH 8
296# include <arm_sve.h>
297# endif
298# elif defined(SDL_PLATFORM_APPLE)
299/* Apple has no AArch64 device supporting SVE2 */
300# elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) && (defined(__aarch64__) || defined(_M_ARM64)) && \
301 defined(__has_include)
302# if __has_include(<arm_sve.h>)
303# define SDL_SVE2_INTRINSICS 1
304# if defined(__ARM_FEATURE_SVE)
305# include <arm_sve.h>
306# endif
307# endif
308# endif
309#endif
310#endif /* compiler version */
311
312#ifdef SDL_WIKI_DOCUMENTATION_SECTION
313
314/**
315 * A macro to decide if the compiler supports `__attribute__((target))`.
316 *
317 * Even though this is defined in SDL's public headers, it is generally not
318 * used directly by apps. Apps should probably just use SDL_TARGETING
319 * directly, instead.
320 *
321 * \since This macro is available since SDL 3.2.0.
322 *
323 * \sa SDL_TARGETING
324 */
325#define SDL_HAS_TARGET_ATTRIBS
326#elif defined(__loongarch64) && defined(__GNUC__) && (__GNUC__ >= 15)
327/* LoongArch requires GCC 15+ for target attribute support */
328# define SDL_HAS_TARGET_ATTRIBS
329#elif defined(__clang__) && defined(__has_attribute)
330# if __has_attribute(target)
331# define SDL_HAS_TARGET_ATTRIBS
332# endif
333#elif defined(__GNUC__) && !defined(__loongarch64) && (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) /* gcc >= 4.9 */
334# define SDL_HAS_TARGET_ATTRIBS
335#elif defined(__ICC) && __ICC >= 1600
336# define SDL_HAS_TARGET_ATTRIBS
337#endif
338
339
340#ifdef SDL_WIKI_DOCUMENTATION_SECTION
341
342/**
343 * A macro to tag a function as targeting a specific CPU architecture.
344 *
345 * This is a hint to the compiler that a function should be built with support
346 * for a CPU instruction set that might be different than the rest of the
347 * program.
348 *
349 * The particulars of this are explained in the GCC documentation:
350 *
351 * https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-target-function-attribute
352 *
353 * An example of using this feature is to turn on SSE2 support for a specific
354 * function, even if the rest of the source code is not compiled to use SSE2
355 * code:
356 *
357 * ```c
358 * #ifdef SDL_SSE2_INTRINSICS
359 * static void SDL_TARGETING("sse2") DoSomethingWithSSE2(char *x) {
360 * ...use SSE2 intrinsic functions, etc...
361 * }
362 * #endif
363 *
364 * // later...
365 * #ifdef SDL_SSE2_INTRINSICS
366 * if (SDL_HasSSE2()) {
367 * DoSomethingWithSSE2(str);
368 * }
369 * #endif
370 * ```
371 *
372 * The application is, on a whole, built without SSE2 instructions, so it will
373 * run on Intel machines that don't support SSE2. But then at runtime, it
374 * checks if the system supports the instructions, and then calls into a
375 * function that uses SSE2 opcodes. The ifdefs make sure that this code isn't
376 * used on platforms that don't have SSE2 at all.
377 *
378 * On compilers without target support, this is defined to nothing.
379 *
380 * This symbol is used by SDL internally, but apps and other libraries are
381 * welcome to use it for their own interfaces as well.
382 *
383 * \since This macro is available since SDL 3.2.0.
384 */
385#define SDL_TARGETING(x) __attribute__((target(x)))
386
387#elif defined(SDL_HAS_TARGET_ATTRIBS)
388# define SDL_TARGETING(x) __attribute__((target(x)))
389#else
390# define SDL_TARGETING(x)
391#endif
392
393#ifdef __loongarch64
394# ifndef SDL_DISABLE_LSX
395# define SDL_LSX_INTRINSICS 1
396# include <lsxintrin.h>
397# endif
398# ifndef SDL_DISABLE_LASX
399# define SDL_LASX_INTRINSICS 1
400# include <lasxintrin.h>
401# endif
402#endif
403
404#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
405# if ((defined(_MSC_VER) && !defined(_M_X64)) || defined(__MMX__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_MMX)
406# define SDL_MMX_INTRINSICS 1
407# include <mmintrin.h>
408# endif
409# if (defined(_MSC_VER) || defined(__SSE__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE)
410# define SDL_SSE_INTRINSICS 1
411# include <xmmintrin.h>
412# endif
413# if (defined(_MSC_VER) || defined(__SSE2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE2)
414# define SDL_SSE2_INTRINSICS 1
415# include <emmintrin.h>
416# endif
417# if (defined(_MSC_VER) || defined(__SSE3__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE3)
418# define SDL_SSE3_INTRINSICS 1
419# include <pmmintrin.h>
420# endif
421# if (defined(_MSC_VER) || defined(__SSE4_1__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE4_1)
422# define SDL_SSE4_1_INTRINSICS 1
423# include <smmintrin.h>
424# endif
425# if (defined(_MSC_VER) || defined(__SSE4_2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(SDL_DISABLE_SSE4_2)
426# define SDL_SSE4_2_INTRINSICS 1
427# include <nmmintrin.h>
428# endif
429# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX__) && !defined(SDL_DISABLE_AVX)
430# define SDL_DISABLE_AVX /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
431# endif
432# if (defined(_MSC_VER) || defined(__AVX__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX)
433# define SDL_AVX_INTRINSICS 1
434# include <immintrin.h>
435# endif
436# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX2__) && !defined(SDL_DISABLE_AVX2)
437# define SDL_DISABLE_AVX2 /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
438# endif
439# if (defined(_MSC_VER) || defined(__AVX2__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX2)
440# define SDL_AVX2_INTRINSICS 1
441# include <immintrin.h>
442# endif
443# if defined(__clang__) && (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX512F__) && !defined(SDL_DISABLE_AVX512F)
444# define SDL_DISABLE_AVX512F /* see https://reviews.llvm.org/D20291 and https://reviews.llvm.org/D79194 */
445# endif
446# if (defined(_MSC_VER) || defined(__AVX512F__) || defined(SDL_HAS_TARGET_ATTRIBS)) && !defined(_M_ARM64EC) && !defined(SDL_DISABLE_AVX512F)
447# define SDL_AVX512F_INTRINSICS 1
448# include <immintrin.h>
449# endif
450#endif /* defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) */
451
452#endif /* SDL_intrin_h_ */
#define __inline__