summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/cpuinfo
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/cpuinfo
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/cpuinfo')
-rw-r--r--contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo.c1193
-rw-r--r--contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo_c.h27
2 files changed, 1220 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo.c b/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo.c
new file mode 100644
index 0000000..bf425a3
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo.c
@@ -0,0 +1,1193 @@
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#include "SDL_internal.h"
23
24#include "SDL_cpuinfo_c.h"
25
26#if defined(SDL_PLATFORM_WINDOWS)
27#include "../core/windows/SDL_windows.h"
28#endif
29
30// CPU feature detection for SDL
31
32#ifdef HAVE_SYSCONF
33#include <unistd.h>
34#endif
35#ifdef HAVE_SYSCTLBYNAME
36#include <sys/types.h>
37#include <sys/sysctl.h>
38#endif
39#if defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))
40#include <sys/sysctl.h> // For AltiVec check
41#elif defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__)
42#include <sys/types.h>
43#include <sys/sysctl.h> // For AltiVec check
44#include <machine/cpu.h>
45#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)
46#include <machine/cpu.h>
47#include <sys/auxv.h>
48#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
49#include <signal.h>
50#include <setjmp.h>
51#endif
52
53#if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(__arm__)
54#include <unistd.h>
55#include <sys/types.h>
56#include <sys/stat.h>
57#include <fcntl.h>
58#include <elf.h>
59
60// #include <asm/hwcap.h>
61#ifndef AT_HWCAP
62#define AT_HWCAP 16
63#endif
64#ifndef AT_PLATFORM
65#define AT_PLATFORM 15
66#endif
67#ifndef HWCAP_NEON
68#define HWCAP_NEON (1 << 12)
69#endif
70#endif
71
72#if defined (SDL_PLATFORM_FREEBSD)
73#include <sys/param.h>
74#endif
75
76#if defined(SDL_PLATFORM_ANDROID) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
77#include <cpu-features.h>
78#endif
79
80#if defined(HAVE_GETAUXVAL) || defined(HAVE_ELF_AUX_INFO)
81#include <sys/auxv.h>
82#endif
83
84#ifdef SDL_PLATFORM_RISCOS
85#include <kernel.h>
86#include <swis.h>
87#endif
88
89#ifdef SDL_PLATFORM_PS2
90#include <kernel.h>
91#endif
92
93#ifdef SDL_PLATFORM_HAIKU
94#include <kernel/OS.h>
95#endif
96
97#define CPU_HAS_ALTIVEC (1 << 0)
98#define CPU_HAS_MMX (1 << 1)
99#define CPU_HAS_SSE (1 << 2)
100#define CPU_HAS_SSE2 (1 << 3)
101#define CPU_HAS_SSE3 (1 << 4)
102#define CPU_HAS_SSE41 (1 << 5)
103#define CPU_HAS_SSE42 (1 << 6)
104#define CPU_HAS_AVX (1 << 7)
105#define CPU_HAS_AVX2 (1 << 8)
106#define CPU_HAS_NEON (1 << 9)
107#define CPU_HAS_AVX512F (1 << 10)
108#define CPU_HAS_ARM_SIMD (1 << 11)
109#define CPU_HAS_LSX (1 << 12)
110#define CPU_HAS_LASX (1 << 13)
111
112#define CPU_CFG2 0x2
113#define CPU_CFG2_LSX (1 << 6)
114#define CPU_CFG2_LASX (1 << 7)
115
116#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
117/* This is the brute force way of detecting instruction sets...
118 the idea is borrowed from the libmpeg2 library - thanks!
119 */
120static jmp_buf jmpbuf;
121static void illegal_instruction(int sig)
122{
123 longjmp(jmpbuf, 1);
124}
125#endif // HAVE_SETJMP
126
127static int CPU_haveCPUID(void)
128{
129 int has_CPUID = 0;
130
131/* *INDENT-OFF* */ // clang-format off
132#ifndef SDL_PLATFORM_EMSCRIPTEN
133#if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
134 __asm__ (
135" pushfl # Get original EFLAGS \n"
136" popl %%eax \n"
137" movl %%eax,%%ecx \n"
138" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
139" pushl %%eax # Save new EFLAGS value on stack \n"
140" popfl # Replace current EFLAGS value \n"
141" pushfl # Get new EFLAGS \n"
142" popl %%eax # Store new EFLAGS in EAX \n"
143" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
144" jz 1f # Processor=80486 \n"
145" movl $1,%0 # We have CPUID support \n"
146"1: \n"
147 : "=m" (has_CPUID)
148 :
149 : "%eax", "%ecx"
150 );
151#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__)
152/* Technically, if this is being compiled under __x86_64__ then it has
153 CPUid by definition. But it's nice to be able to prove it. :) */
154 __asm__ (
155" pushfq # Get original EFLAGS \n"
156" popq %%rax \n"
157" movq %%rax,%%rcx \n"
158" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
159" pushq %%rax # Save new EFLAGS value on stack \n"
160" popfq # Replace current EFLAGS value \n"
161" pushfq # Get new EFLAGS \n"
162" popq %%rax # Store new EFLAGS in EAX \n"
163" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
164" jz 1f # Processor=80486 \n"
165" movl $1,%0 # We have CPUID support \n"
166"1: \n"
167 : "=m" (has_CPUID)
168 :
169 : "%rax", "%rcx"
170 );
171#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
172 __asm {
173 pushfd ; Get original EFLAGS
174 pop eax
175 mov ecx, eax
176 xor eax, 200000h ; Flip ID bit in EFLAGS
177 push eax ; Save new EFLAGS value on stack
178 popfd ; Replace current EFLAGS value
179 pushfd ; Get new EFLAGS
180 pop eax ; Store new EFLAGS in EAX
181 xor eax, ecx ; Can not toggle ID bit,
182 jz done ; Processor=80486
183 mov has_CPUID,1 ; We have CPUID support
184done:
185 }
186#elif defined(_MSC_VER) && defined(_M_X64)
187 has_CPUID = 1;
188#elif defined(__sun) && defined(__i386)
189 __asm (
190" pushfl \n"
191" popl %eax \n"
192" movl %eax,%ecx \n"
193" xorl $0x200000,%eax \n"
194" pushl %eax \n"
195" popfl \n"
196" pushfl \n"
197" popl %eax \n"
198" xorl %ecx,%eax \n"
199" jz 1f \n"
200" movl $1,-8(%ebp) \n"
201"1: \n"
202 );
203#elif defined(__sun) && defined(__amd64)
204 __asm (
205" pushfq \n"
206" popq %rax \n"
207" movq %rax,%rcx \n"
208" xorl $0x200000,%eax \n"
209" pushq %rax \n"
210" popfq \n"
211" pushfq \n"
212" popq %rax \n"
213" xorl %ecx,%eax \n"
214" jz 1f \n"
215" movl $1,-8(%rbp) \n"
216"1: \n"
217 );
218#endif
219#endif // !SDL_PLATFORM_EMSCRIPTEN
220/* *INDENT-ON* */ // clang-format on
221 return has_CPUID;
222}
223
224#if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
225#define cpuid(func, a, b, c, d) \
226 __asm__ __volatile__( \
227 " pushl %%ebx \n" \
228 " xorl %%ecx,%%ecx \n" \
229 " cpuid \n" \
230 " movl %%ebx, %%esi \n" \
231 " popl %%ebx \n" \
232 : "=a"(a), "=S"(b), "=c"(c), "=d"(d) \
233 : "a"(func))
234#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__)
235#define cpuid(func, a, b, c, d) \
236 __asm__ __volatile__( \
237 " pushq %%rbx \n" \
238 " xorq %%rcx,%%rcx \n" \
239 " cpuid \n" \
240 " movq %%rbx, %%rsi \n" \
241 " popq %%rbx \n" \
242 : "=a"(a), "=S"(b), "=c"(c), "=d"(d) \
243 : "a"(func))
244#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
245#define cpuid(func, a, b, c, d) \
246 __asm { \
247 __asm mov eax, func \
248 __asm xor ecx, ecx \
249 __asm cpuid \
250 __asm mov a, eax \
251 __asm mov b, ebx \
252 __asm mov c, ecx \
253 __asm mov d, edx \
254 }
255#elif (defined(_MSC_VER) && defined(_M_X64))
256// Use __cpuidex instead of __cpuid because ICL does not clear ecx register
257#define cpuid(func, a, b, c, d) \
258 { \
259 int CPUInfo[4]; \
260 __cpuidex(CPUInfo, func, 0); \
261 a = CPUInfo[0]; \
262 b = CPUInfo[1]; \
263 c = CPUInfo[2]; \
264 d = CPUInfo[3]; \
265 }
266#else
267#define cpuid(func, a, b, c, d) \
268 do { \
269 a = b = c = d = 0; \
270 (void)a; \
271 (void)b; \
272 (void)c; \
273 (void)d; \
274 } while (0)
275#endif
276
277static int CPU_CPUIDFeatures[4];
278static int CPU_CPUIDMaxFunction = 0;
279static bool CPU_OSSavesYMM = false;
280static bool CPU_OSSavesZMM = false;
281
282static void CPU_calcCPUIDFeatures(void)
283{
284 static bool checked = false;
285 if (!checked) {
286 checked = true;
287 if (CPU_haveCPUID()) {
288 int a, b, c, d;
289 cpuid(0, a, b, c, d);
290 CPU_CPUIDMaxFunction = a;
291 if (CPU_CPUIDMaxFunction >= 1) {
292 cpuid(1, a, b, c, d);
293 CPU_CPUIDFeatures[0] = a;
294 CPU_CPUIDFeatures[1] = b;
295 CPU_CPUIDFeatures[2] = c;
296 CPU_CPUIDFeatures[3] = d;
297
298 // Check to make sure we can call xgetbv
299 if (c & 0x08000000) {
300 // Call xgetbv to see if YMM (etc) register state is saved
301#if (defined(__GNUC__) || defined(__llvm__)) && (defined(__i386__) || defined(__x86_64__))
302 __asm__(".byte 0x0f, 0x01, 0xd0"
303 : "=a"(a)
304 : "c"(0)
305 : "%edx");
306#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) // VS2010 SP1
307 a = (int)_xgetbv(0);
308#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
309 __asm
310 {
311 xor ecx, ecx
312 _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
313 mov a, eax
314 }
315#endif
316 CPU_OSSavesYMM = ((a & 6) == 6) ? true : false;
317 CPU_OSSavesZMM = (CPU_OSSavesYMM && ((a & 0xe0) == 0xe0)) ? true : false;
318 }
319 }
320 }
321 }
322}
323
324static int CPU_haveAltiVec(void)
325{
326 volatile int altivec = 0;
327#ifndef SDL_CPUINFO_DISABLED
328#if (defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))
329#ifdef SDL_PLATFORM_OPENBSD
330 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
331#else
332 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
333#endif
334 int hasVectorUnit = 0;
335 size_t length = sizeof(hasVectorUnit);
336 int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
337 if (0 == error) {
338 altivec = (hasVectorUnit != 0);
339 }
340#elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)
341 unsigned long cpufeatures = 0;
342 elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
343 altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
344 return altivec;
345#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
346 void (*handler)(int sig);
347 handler = signal(SIGILL, illegal_instruction);
348 if (setjmp(jmpbuf) == 0) {
349 asm volatile("mtspr 256, %0\n\t"
350 "vand %%v0, %%v0, %%v0" ::"r"(-1));
351 altivec = 1;
352 }
353 signal(SIGILL, handler);
354#endif
355#endif
356 return altivec;
357}
358
359#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 6)) || defined(__aarch64__)
360static int CPU_haveARMSIMD(void)
361{
362 return 1;
363}
364
365#elif !defined(__arm__)
366static int CPU_haveARMSIMD(void)
367{
368 return 0;
369}
370
371#elif defined(SDL_PLATFORM_LINUX)
372static int CPU_haveARMSIMD(void)
373{
374 int arm_simd = 0;
375 int fd;
376
377 fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
378 if (fd >= 0) {
379 Elf32_auxv_t aux;
380 while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
381 if (aux.a_type == AT_PLATFORM) {
382 const char *plat = (const char *)aux.a_un.a_val;
383 if (plat) {
384 arm_simd = SDL_strncmp(plat, "v6l", 3) == 0 ||
385 SDL_strncmp(plat, "v7l", 3) == 0;
386 }
387 }
388 }
389 close(fd);
390 }
391 return arm_simd;
392}
393
394#elif defined(SDL_PLATFORM_RISCOS)
395static int CPU_haveARMSIMD(void)
396{
397 _kernel_swi_regs regs;
398 regs.r[0] = 0;
399 if (_kernel_swi(OS_PlatformFeatures, &regs, &regs) != NULL) {
400 return 0;
401 }
402
403 if (!(regs.r[0] & (1 << 31))) {
404 return 0;
405 }
406
407 regs.r[0] = 34;
408 regs.r[1] = 29;
409 if (_kernel_swi(OS_PlatformFeatures, &regs, &regs) != NULL) {
410 return 0;
411 }
412
413 return regs.r[0];
414}
415
416#else
417static int CPU_haveARMSIMD(void)
418{
419#warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me.
420 return 0;
421}
422#endif
423
424#if defined(SDL_PLATFORM_LINUX) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
425static int readProcAuxvForNeon(void)
426{
427 int neon = 0;
428 int fd;
429
430 fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
431 if (fd >= 0) {
432 Elf32_auxv_t aux;
433 while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
434 if (aux.a_type == AT_HWCAP) {
435 neon = (aux.a_un.a_val & HWCAP_NEON) == HWCAP_NEON;
436 break;
437 }
438 }
439 close(fd);
440 }
441 return neon;
442}
443#endif
444
445static int CPU_haveNEON(void)
446{
447/* The way you detect NEON is a privileged instruction on ARM, so you have
448 query the OS kernel in a platform-specific way. :/ */
449#if defined(SDL_PLATFORM_WINDOWS) && (defined(_M_ARM) || defined(_M_ARM64))
450// Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first.
451// Seems to have been removed
452#ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
453#define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
454#endif
455 // All WinRT ARM devices are required to support NEON, but just in case.
456 return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
457#elif (defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) || defined(__aarch64__)
458 return 1; // ARMv8 always has non-optional NEON support.
459#elif defined(SDL_PLATFORM_VITA)
460 return 1;
461#elif defined(SDL_PLATFORM_3DS)
462 return 0;
463#elif defined(SDL_PLATFORM_APPLE) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
464 // (note that sysctlbyname("hw.optional.neon") doesn't work!)
465 return 1; // all Apple ARMv7 chips and later have NEON.
466#elif defined(SDL_PLATFORM_APPLE)
467 return 0; // assume anything else from Apple doesn't have NEON.
468#elif !defined(__arm__)
469 return 0; // not an ARM CPU at all.
470#elif defined(SDL_PLATFORM_OPENBSD)
471 return 1; // OpenBSD only supports ARMv7 CPUs that have NEON.
472#elif defined(HAVE_ELF_AUX_INFO)
473 unsigned long hasneon = 0;
474 if (elf_aux_info(AT_HWCAP, (void *)&hasneon, (int)sizeof(hasneon)) != 0) {
475 return 0;
476 }
477 return (hasneon & HWCAP_NEON) == HWCAP_NEON;
478#elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_GETAUXVAL)
479 return (getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON;
480#elif defined(SDL_PLATFORM_LINUX)
481 return readProcAuxvForNeon();
482#elif defined(SDL_PLATFORM_ANDROID)
483 // Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo
484 {
485 AndroidCpuFamily cpu_family = android_getCpuFamily();
486 if (cpu_family == ANDROID_CPU_FAMILY_ARM) {
487 uint64_t cpu_features = android_getCpuFeatures();
488 if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) {
489 return 1;
490 }
491 }
492 return 0;
493 }
494#elif defined(SDL_PLATFORM_RISCOS)
495 // Use the VFPSupport_Features SWI to access the MVFR registers
496 {
497 _kernel_swi_regs regs;
498 regs.r[0] = 0;
499 if (_kernel_swi(VFPSupport_Features, &regs, &regs) == NULL) {
500 if ((regs.r[2] & 0xFFF000) == 0x111000) {
501 return 1;
502 }
503 }
504 return 0;
505 }
506#elif defined(SDL_PLATFORM_EMSCRIPTEN)
507 return 0;
508#else
509#warning SDL_HasNEON is not implemented for this ARM platform. Write me.
510 return 0;
511#endif
512}
513
514static int CPU_readCPUCFG(void)
515{
516 uint32_t cfg2 = 0;
517#if defined __loongarch__
518 __asm__ volatile(
519 "cpucfg %0, %1 \n\t"
520 : "+&r"(cfg2)
521 : "r"(CPU_CFG2));
522#endif
523 return cfg2;
524}
525
526#define CPU_haveLSX() (CPU_readCPUCFG() & CPU_CFG2_LSX)
527#define CPU_haveLASX() (CPU_readCPUCFG() & CPU_CFG2_LASX)
528
529#ifdef __e2k__
530#ifdef __MMX__
531#define CPU_haveMMX() (1)
532#else
533#define CPU_haveMMX() (0)
534#endif
535#ifdef __SSE__
536#define CPU_haveSSE() (1)
537#else
538#define CPU_haveSSE() (0)
539#endif
540#ifdef __SSE2__
541#define CPU_haveSSE2() (1)
542#else
543#define CPU_haveSSE2() (0)
544#endif
545#ifdef __SSE3__
546#define CPU_haveSSE3() (1)
547#else
548#define CPU_haveSSE3() (0)
549#endif
550#ifdef __SSE4_1__
551#define CPU_haveSSE41() (1)
552#else
553#define CPU_haveSSE41() (0)
554#endif
555#ifdef __SSE4_2__
556#define CPU_haveSSE42() (1)
557#else
558#define CPU_haveSSE42() (0)
559#endif
560#ifdef __AVX__
561#define CPU_haveAVX() (1)
562#else
563#define CPU_haveAVX() (0)
564#endif
565#else
566#define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
567#define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
568#define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
569#define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
570#define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
571#define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
572#define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
573#endif
574
575#ifdef __e2k__
576inline int
577CPU_haveAVX2(void)
578{
579#ifdef __AVX2__
580 return 1;
581#else
582 return 0;
583#endif
584}
585#else
586static int CPU_haveAVX2(void)
587{
588 if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
589 int a, b, c, d;
590 (void)a;
591 (void)b;
592 (void)c;
593 (void)d; // compiler warnings...
594 cpuid(7, a, b, c, d);
595 return b & 0x00000020;
596 }
597 return 0;
598}
599#endif
600
601#ifdef __e2k__
602inline int
603CPU_haveAVX512F(void)
604{
605 return 0;
606}
607#else
608static int CPU_haveAVX512F(void)
609{
610 if (CPU_OSSavesZMM && (CPU_CPUIDMaxFunction >= 7)) {
611 int a, b, c, d;
612 (void)a;
613 (void)b;
614 (void)c;
615 (void)d; // compiler warnings...
616 cpuid(7, a, b, c, d);
617 return b & 0x00010000;
618 }
619 return 0;
620}
621#endif
622
623static int SDL_NumLogicalCPUCores = 0;
624
625int SDL_GetNumLogicalCPUCores(void)
626{
627 if (!SDL_NumLogicalCPUCores) {
628#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
629 if (SDL_NumLogicalCPUCores <= 0) {
630 SDL_NumLogicalCPUCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
631 }
632#endif
633#ifdef HAVE_SYSCTLBYNAME
634 if (SDL_NumLogicalCPUCores <= 0) {
635 size_t size = sizeof(SDL_NumLogicalCPUCores);
636 sysctlbyname("hw.ncpu", &SDL_NumLogicalCPUCores, &size, NULL, 0);
637 }
638#endif
639#if defined(SDL_PLATFORM_WINDOWS)
640 if (SDL_NumLogicalCPUCores <= 0) {
641 SYSTEM_INFO info;
642 GetSystemInfo(&info);
643 SDL_NumLogicalCPUCores = info.dwNumberOfProcessors;
644 }
645#endif
646 // There has to be at least 1, right? :)
647 if (SDL_NumLogicalCPUCores <= 0) {
648 SDL_NumLogicalCPUCores = 1;
649 }
650 }
651 return SDL_NumLogicalCPUCores;
652}
653
654#ifdef __e2k__
655inline const char *
656SDL_GetCPUType(void)
657{
658 static char SDL_CPUType[13];
659
660 SDL_strlcpy(SDL_CPUType, "E2K MACHINE", sizeof(SDL_CPUType));
661
662 return SDL_CPUType;
663}
664#else
665// Oh, such a sweet sweet trick, just not very useful. :)
666static const char *SDL_GetCPUType(void)
667{
668 static char SDL_CPUType[13];
669
670 if (!SDL_CPUType[0]) {
671 int i = 0;
672
673 CPU_calcCPUIDFeatures();
674 if (CPU_CPUIDMaxFunction > 0) { // do we have CPUID at all?
675 int a, b, c, d;
676 cpuid(0x00000000, a, b, c, d);
677 (void)a;
678 SDL_CPUType[i++] = (char)(b & 0xff);
679 b >>= 8;
680 SDL_CPUType[i++] = (char)(b & 0xff);
681 b >>= 8;
682 SDL_CPUType[i++] = (char)(b & 0xff);
683 b >>= 8;
684 SDL_CPUType[i++] = (char)(b & 0xff);
685
686 SDL_CPUType[i++] = (char)(d & 0xff);
687 d >>= 8;
688 SDL_CPUType[i++] = (char)(d & 0xff);
689 d >>= 8;
690 SDL_CPUType[i++] = (char)(d & 0xff);
691 d >>= 8;
692 SDL_CPUType[i++] = (char)(d & 0xff);
693
694 SDL_CPUType[i++] = (char)(c & 0xff);
695 c >>= 8;
696 SDL_CPUType[i++] = (char)(c & 0xff);
697 c >>= 8;
698 SDL_CPUType[i++] = (char)(c & 0xff);
699 c >>= 8;
700 SDL_CPUType[i++] = (char)(c & 0xff);
701 }
702 if (!SDL_CPUType[0]) {
703 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
704 }
705 }
706 return SDL_CPUType;
707}
708#endif
709
710#if 0
711!!! FIXME: Not used at the moment. */
712#ifdef __e2k__
713inline const char *
714SDL_GetCPUName(void)
715{
716 static char SDL_CPUName[48];
717
718 SDL_strlcpy(SDL_CPUName, __builtin_cpu_name(), sizeof(SDL_CPUName));
719
720 return SDL_CPUName;
721}
722#else
723static const char *SDL_GetCPUName(void)
724{
725 static char SDL_CPUName[48];
726
727 if (!SDL_CPUName[0]) {
728 int i = 0;
729 int a, b, c, d;
730
731 CPU_calcCPUIDFeatures();
732 if (CPU_CPUIDMaxFunction > 0) { // do we have CPUID at all?
733 cpuid(0x80000000, a, b, c, d);
734 if (a >= 0x80000004) {
735 cpuid(0x80000002, a, b, c, d);
736 SDL_CPUName[i++] = (char)(a & 0xff);
737 a >>= 8;
738 SDL_CPUName[i++] = (char)(a & 0xff);
739 a >>= 8;
740 SDL_CPUName[i++] = (char)(a & 0xff);
741 a >>= 8;
742 SDL_CPUName[i++] = (char)(a & 0xff);
743 a >>= 8;
744 SDL_CPUName[i++] = (char)(b & 0xff);
745 b >>= 8;
746 SDL_CPUName[i++] = (char)(b & 0xff);
747 b >>= 8;
748 SDL_CPUName[i++] = (char)(b & 0xff);
749 b >>= 8;
750 SDL_CPUName[i++] = (char)(b & 0xff);
751 b >>= 8;
752 SDL_CPUName[i++] = (char)(c & 0xff);
753 c >>= 8;
754 SDL_CPUName[i++] = (char)(c & 0xff);
755 c >>= 8;
756 SDL_CPUName[i++] = (char)(c & 0xff);
757 c >>= 8;
758 SDL_CPUName[i++] = (char)(c & 0xff);
759 c >>= 8;
760 SDL_CPUName[i++] = (char)(d & 0xff);
761 d >>= 8;
762 SDL_CPUName[i++] = (char)(d & 0xff);
763 d >>= 8;
764 SDL_CPUName[i++] = (char)(d & 0xff);
765 d >>= 8;
766 SDL_CPUName[i++] = (char)(d & 0xff);
767 d >>= 8;
768 cpuid(0x80000003, a, b, c, d);
769 SDL_CPUName[i++] = (char)(a & 0xff);
770 a >>= 8;
771 SDL_CPUName[i++] = (char)(a & 0xff);
772 a >>= 8;
773 SDL_CPUName[i++] = (char)(a & 0xff);
774 a >>= 8;
775 SDL_CPUName[i++] = (char)(a & 0xff);
776 a >>= 8;
777 SDL_CPUName[i++] = (char)(b & 0xff);
778 b >>= 8;
779 SDL_CPUName[i++] = (char)(b & 0xff);
780 b >>= 8;
781 SDL_CPUName[i++] = (char)(b & 0xff);
782 b >>= 8;
783 SDL_CPUName[i++] = (char)(b & 0xff);
784 b >>= 8;
785 SDL_CPUName[i++] = (char)(c & 0xff);
786 c >>= 8;
787 SDL_CPUName[i++] = (char)(c & 0xff);
788 c >>= 8;
789 SDL_CPUName[i++] = (char)(c & 0xff);
790 c >>= 8;
791 SDL_CPUName[i++] = (char)(c & 0xff);
792 c >>= 8;
793 SDL_CPUName[i++] = (char)(d & 0xff);
794 d >>= 8;
795 SDL_CPUName[i++] = (char)(d & 0xff);
796 d >>= 8;
797 SDL_CPUName[i++] = (char)(d & 0xff);
798 d >>= 8;
799 SDL_CPUName[i++] = (char)(d & 0xff);
800 d >>= 8;
801 cpuid(0x80000004, a, b, c, d);
802 SDL_CPUName[i++] = (char)(a & 0xff);
803 a >>= 8;
804 SDL_CPUName[i++] = (char)(a & 0xff);
805 a >>= 8;
806 SDL_CPUName[i++] = (char)(a & 0xff);
807 a >>= 8;
808 SDL_CPUName[i++] = (char)(a & 0xff);
809 a >>= 8;
810 SDL_CPUName[i++] = (char)(b & 0xff);
811 b >>= 8;
812 SDL_CPUName[i++] = (char)(b & 0xff);
813 b >>= 8;
814 SDL_CPUName[i++] = (char)(b & 0xff);
815 b >>= 8;
816 SDL_CPUName[i++] = (char)(b & 0xff);
817 b >>= 8;
818 SDL_CPUName[i++] = (char)(c & 0xff);
819 c >>= 8;
820 SDL_CPUName[i++] = (char)(c & 0xff);
821 c >>= 8;
822 SDL_CPUName[i++] = (char)(c & 0xff);
823 c >>= 8;
824 SDL_CPUName[i++] = (char)(c & 0xff);
825 c >>= 8;
826 SDL_CPUName[i++] = (char)(d & 0xff);
827 d >>= 8;
828 SDL_CPUName[i++] = (char)(d & 0xff);
829 d >>= 8;
830 SDL_CPUName[i++] = (char)(d & 0xff);
831 d >>= 8;
832 SDL_CPUName[i++] = (char)(d & 0xff);
833 d >>= 8;
834 }
835 }
836 if (!SDL_CPUName[0]) {
837 SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
838 }
839 }
840 return SDL_CPUName;
841}
842#endif
843#endif
844
845int SDL_GetCPUCacheLineSize(void)
846{
847 const char *cpuType = SDL_GetCPUType();
848 int cacheline_size = SDL_CACHELINE_SIZE; // initial guess
849 int a, b, c, d;
850 (void)a;
851 (void)b;
852 (void)c;
853 (void)d;
854 if (SDL_strcmp(cpuType, "GenuineIntel") == 0 || SDL_strcmp(cpuType, "CentaurHauls") == 0 || SDL_strcmp(cpuType, " Shanghai ") == 0) {
855 cpuid(0x00000001, a, b, c, d);
856 cacheline_size = ((b >> 8) & 0xff) * 8;
857 } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0 || SDL_strcmp(cpuType, "HygonGenuine") == 0) {
858 cpuid(0x80000005, a, b, c, d);
859 cacheline_size = c & 0xff;
860 } else {
861#if defined(HAVE_SYSCONF) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
862 if ((cacheline_size = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE)) > 0) {
863 return cacheline_size;
864 } else {
865 cacheline_size = SDL_CACHELINE_SIZE;
866 }
867#endif
868#if defined(SDL_PLATFORM_LINUX)
869 {
870 FILE *f = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
871 if (f) {
872 int size;
873 if (fscanf(f, "%d", &size) == 1) {
874 cacheline_size = size;
875 }
876 fclose(f);
877 }
878 }
879#elif defined(__FREEBSD__) && defined(CACHE_LINE_SIZE)
880 cacheline_size = CACHE_LINE_SIZE;
881#endif
882 }
883 return cacheline_size;
884}
885
886#define SDL_CPUFEATURES_RESET_VALUE 0xFFFFFFFF
887
888static Uint32 SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
889static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
890
891static bool ref_string_equals(const char *ref, const char *test, const char *end_test) {
892 size_t len_test = end_test - test;
893 return SDL_strncmp(ref, test, len_test) == 0 && ref[len_test] == '\0' && (test[len_test] == '\0' || test[len_test] == ',');
894}
895
896static Uint32 SDLCALL SDL_CPUFeatureMaskFromHint(void)
897{
898 Uint32 result_mask = SDL_CPUFEATURES_RESET_VALUE;
899
900 const char *hint = SDL_GetHint(SDL_HINT_CPU_FEATURE_MASK);
901
902 if (hint) {
903 for (const char *spot = hint, *next; *spot; spot = next) {
904 const char *end = SDL_strchr(spot, ',');
905 Uint32 spot_mask;
906 bool add_spot_mask = true;
907 if (end) {
908 next = end + 1;
909 } else {
910 size_t len = SDL_strlen(spot);
911 end = spot + len;
912 next = end;
913 }
914 if (spot[0] == '+') {
915 add_spot_mask = true;
916 spot += 1;
917 } else if (spot[0] == '-') {
918 add_spot_mask = false;
919 spot += 1;
920 }
921 if (ref_string_equals("all", spot, end)) {
922 spot_mask = SDL_CPUFEATURES_RESET_VALUE;
923 } else if (ref_string_equals("altivec", spot, end)) {
924 spot_mask= CPU_HAS_ALTIVEC;
925 } else if (ref_string_equals("mmx", spot, end)) {
926 spot_mask = CPU_HAS_MMX;
927 } else if (ref_string_equals("sse", spot, end)) {
928 spot_mask = CPU_HAS_SSE;
929 } else if (ref_string_equals("sse2", spot, end)) {
930 spot_mask = CPU_HAS_SSE2;
931 } else if (ref_string_equals("sse3", spot, end)) {
932 spot_mask = CPU_HAS_SSE3;
933 } else if (ref_string_equals("sse41", spot, end)) {
934 spot_mask = CPU_HAS_SSE41;
935 } else if (ref_string_equals("sse42", spot, end)) {
936 spot_mask = CPU_HAS_SSE42;
937 } else if (ref_string_equals("avx", spot, end)) {
938 spot_mask = CPU_HAS_AVX;
939 } else if (ref_string_equals("avx2", spot, end)) {
940 spot_mask = CPU_HAS_AVX2;
941 } else if (ref_string_equals("avx512f", spot, end)) {
942 spot_mask = CPU_HAS_AVX512F;
943 } else if (ref_string_equals("arm-simd", spot, end)) {
944 spot_mask = CPU_HAS_ARM_SIMD;
945 } else if (ref_string_equals("neon", spot, end)) {
946 spot_mask = CPU_HAS_NEON;
947 } else if (ref_string_equals("lsx", spot, end)) {
948 spot_mask = CPU_HAS_LSX;
949 } else if (ref_string_equals("lasx", spot, end)) {
950 spot_mask = CPU_HAS_LASX;
951 } else {
952 // Ignore unknown/incorrect cpu feature(s)
953 continue;
954 }
955 if (add_spot_mask) {
956 result_mask |= spot_mask;
957 } else {
958 result_mask &= ~spot_mask;
959 }
960 }
961 }
962 return result_mask;
963}
964
965static Uint32 SDL_GetCPUFeatures(void)
966{
967 if (SDL_CPUFeatures == SDL_CPUFEATURES_RESET_VALUE) {
968 CPU_calcCPUIDFeatures();
969 SDL_CPUFeatures = 0;
970 SDL_SIMDAlignment = sizeof(void *); // a good safe base value
971 if (CPU_haveAltiVec()) {
972 SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
973 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
974 }
975 if (CPU_haveMMX()) {
976 SDL_CPUFeatures |= CPU_HAS_MMX;
977 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 8);
978 }
979 if (CPU_haveSSE()) {
980 SDL_CPUFeatures |= CPU_HAS_SSE;
981 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
982 }
983 if (CPU_haveSSE2()) {
984 SDL_CPUFeatures |= CPU_HAS_SSE2;
985 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
986 }
987 if (CPU_haveSSE3()) {
988 SDL_CPUFeatures |= CPU_HAS_SSE3;
989 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
990 }
991 if (CPU_haveSSE41()) {
992 SDL_CPUFeatures |= CPU_HAS_SSE41;
993 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
994 }
995 if (CPU_haveSSE42()) {
996 SDL_CPUFeatures |= CPU_HAS_SSE42;
997 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
998 }
999 if (CPU_haveAVX()) {
1000 SDL_CPUFeatures |= CPU_HAS_AVX;
1001 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
1002 }
1003 if (CPU_haveAVX2()) {
1004 SDL_CPUFeatures |= CPU_HAS_AVX2;
1005 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
1006 }
1007 if (CPU_haveAVX512F()) {
1008 SDL_CPUFeatures |= CPU_HAS_AVX512F;
1009 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 64);
1010 }
1011 if (CPU_haveARMSIMD()) {
1012 SDL_CPUFeatures |= CPU_HAS_ARM_SIMD;
1013 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
1014 }
1015 if (CPU_haveNEON()) {
1016 SDL_CPUFeatures |= CPU_HAS_NEON;
1017 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
1018 }
1019 if (CPU_haveLSX()) {
1020 SDL_CPUFeatures |= CPU_HAS_LSX;
1021 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
1022 }
1023 if (CPU_haveLASX()) {
1024 SDL_CPUFeatures |= CPU_HAS_LASX;
1025 SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
1026 }
1027 SDL_CPUFeatures &= SDL_CPUFeatureMaskFromHint();
1028 }
1029 return SDL_CPUFeatures;
1030}
1031
1032void SDL_QuitCPUInfo(void) {
1033 SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
1034}
1035
1036#define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & (f)) ? true : false)
1037
1038bool SDL_HasAltiVec(void)
1039{
1040 return CPU_FEATURE_AVAILABLE(CPU_HAS_ALTIVEC);
1041}
1042
1043bool SDL_HasMMX(void)
1044{
1045 return CPU_FEATURE_AVAILABLE(CPU_HAS_MMX);
1046}
1047
1048bool SDL_HasSSE(void)
1049{
1050 return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE);
1051}
1052
1053bool SDL_HasSSE2(void)
1054{
1055 return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE2);
1056}
1057
1058bool SDL_HasSSE3(void)
1059{
1060 return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE3);
1061}
1062
1063bool SDL_HasSSE41(void)
1064{
1065 return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE41);
1066}
1067
1068bool SDL_HasSSE42(void)
1069{
1070 return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE42);
1071}
1072
1073bool SDL_HasAVX(void)
1074{
1075 return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX);
1076}
1077
1078bool SDL_HasAVX2(void)
1079{
1080 return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX2);
1081}
1082
1083bool SDL_HasAVX512F(void)
1084{
1085 return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX512F);
1086}
1087
1088bool SDL_HasARMSIMD(void)
1089{
1090 return CPU_FEATURE_AVAILABLE(CPU_HAS_ARM_SIMD);
1091}
1092
1093bool SDL_HasNEON(void)
1094{
1095 return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON);
1096}
1097
1098bool SDL_HasLSX(void)
1099{
1100 return CPU_FEATURE_AVAILABLE(CPU_HAS_LSX);
1101}
1102
1103bool SDL_HasLASX(void)
1104{
1105 return CPU_FEATURE_AVAILABLE(CPU_HAS_LASX);
1106}
1107
1108static int SDL_SystemRAM = 0;
1109
1110int SDL_GetSystemRAM(void)
1111{
1112 if (!SDL_SystemRAM) {
1113#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
1114 if (SDL_SystemRAM <= 0) {
1115 SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024 * 1024));
1116 }
1117#endif
1118#ifdef HAVE_SYSCTLBYNAME
1119 if (SDL_SystemRAM <= 0) {
1120#ifdef HW_PHYSMEM64
1121 // (64-bit): NetBSD since 2003, OpenBSD
1122 int mib[2] = { CTL_HW, HW_PHYSMEM64 };
1123#elif defined(HW_REALMEM)
1124 // (64-bit): FreeBSD since 2005, DragonFly
1125 int mib[2] = { CTL_HW, HW_REALMEM };
1126#elif defined(HW_MEMSIZE)
1127 // (64-bit): Darwin
1128 int mib[2] = { CTL_HW, HW_MEMSIZE };
1129#else
1130 // (32-bit): very old BSD, might only report up to 2 GiB
1131 int mib[2] = { CTL_HW, HW_PHYSMEM };
1132#endif // HW_PHYSMEM64
1133 Uint64 memsize = 0;
1134 size_t len = sizeof(memsize);
1135
1136 if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
1137 SDL_SystemRAM = (int)(memsize / (1024 * 1024));
1138 }
1139 }
1140#endif
1141#if defined(SDL_PLATFORM_WINDOWS)
1142 if (SDL_SystemRAM <= 0) {
1143 MEMORYSTATUSEX stat;
1144 stat.dwLength = sizeof(stat);
1145 if (GlobalMemoryStatusEx(&stat)) {
1146 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
1147 }
1148 }
1149#endif
1150#ifdef SDL_PLATFORM_RISCOS
1151 if (SDL_SystemRAM <= 0) {
1152 _kernel_swi_regs regs;
1153 regs.r[0] = 0x108;
1154 if (_kernel_swi(OS_Memory, &regs, &regs) == NULL) {
1155 SDL_SystemRAM = (int)(regs.r[1] * regs.r[2] / (1024 * 1024));
1156 }
1157 }
1158#endif
1159#ifdef SDL_PLATFORM_VITA
1160 if (SDL_SystemRAM <= 0) {
1161 /* Vita has 512MiB on SoC, that's split into 256MiB(+109MiB in extended memory mode) for app
1162 +26MiB of physically continuous memory, +112MiB of CDRAM(VRAM) + system reserved memory. */
1163 SDL_SystemRAM = 536870912;
1164 }
1165#endif
1166#ifdef SDL_PLATFORM_PS2
1167 if (SDL_SystemRAM <= 0) {
1168 // PlayStation 2 has 32MiB however there are some special models with 64 and 128
1169 SDL_SystemRAM = GetMemorySize();
1170 }
1171#endif
1172#ifdef SDL_PLATFORM_HAIKU
1173 if (SDL_SystemRAM <= 0) {
1174 system_info info;
1175 if (get_system_info(&info) == B_OK) {
1176 /* To have an accurate amount, we also take in account the inaccessible pages (aka ignored)
1177 which is a bit handier compared to the legacy system's api (i.e. used_pages).*/
1178 SDL_SystemRAM = (int)SDL_round((info.max_pages + info.ignored_pages > 0 ? info.ignored_pages : 0) * B_PAGE_SIZE / 1048576.0);
1179 }
1180 }
1181#endif
1182 }
1183 return SDL_SystemRAM;
1184}
1185
1186size_t SDL_GetSIMDAlignment(void)
1187{
1188 if (SDL_SIMDAlignment == 0xFFFFFFFF) {
1189 SDL_GetCPUFeatures(); // make sure this has been calculated
1190 }
1191 SDL_assert(SDL_SIMDAlignment != 0);
1192 return SDL_SIMDAlignment;
1193}
diff --git a/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo_c.h b/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo_c.h
new file mode 100644
index 0000000..9da31a9
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/cpuinfo/SDL_cpuinfo_c.h
@@ -0,0 +1,27 @@
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#ifndef SDL_cpuinfo_c_h_
23#define SDL_cpuinfo_c_h_
24
25extern void SDL_QuitCPUInfo(void);
26
27#endif // SDL_cpuinfo_c_h_