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 |
225 | static __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 | |