SDL_intrin.h 15 KB

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