SDL  2.0
SDL_cpuinfo.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 #ifdef TEST_MAIN
22 #include "SDL_config.h"
23 #else
24 #include "../SDL_internal.h"
25 #include "SDL_simd.h"
26 #endif
27 
28 #if defined(__WIN32__)
29 #include "../core/windows/SDL_windows.h"
30 #endif
31 #if defined(__OS2__)
32 #define INCL_DOS
33 #include <os2.h>
34 #ifndef QSV_NUMPROCESSORS
35 #define QSV_NUMPROCESSORS 26
36 #endif
37 #endif
38 
39 /* CPU feature detection for SDL */
40 
41 #include "SDL_cpuinfo.h"
42 #include "SDL_assert.h"
43 
44 #ifdef HAVE_SYSCONF
45 #include <unistd.h>
46 #endif
47 #ifdef HAVE_SYSCTLBYNAME
48 #include <sys/types.h>
49 #include <sys/sysctl.h>
50 #endif
51 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
52 #include <sys/sysctl.h> /* For AltiVec check */
53 #elif defined(__OpenBSD__) && defined(__powerpc__)
54 #include <sys/param.h>
55 #include <sys/sysctl.h> /* For AltiVec check */
56 #include <machine/cpu.h>
57 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
58 #include <signal.h>
59 #include <setjmp.h>
60 #endif
61 
62 #if defined(__QNXNTO__)
63 #include <sys/syspage.h>
64 #endif
65 
66 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH)
67 /*#include <asm/hwcap.h>*/
68 #ifndef AT_HWCAP
69 #define AT_HWCAP 16
70 #endif
71 #ifndef HWCAP_NEON
72 #define HWCAP_NEON (1 << 12)
73 #endif
74 #if defined HAVE_GETAUXVAL
75 #include <sys/auxv.h>
76 #else
77 #include <fcntl.h>
78 #endif
79 #endif
80 
81 #define CPU_HAS_RDTSC (1 << 0)
82 #define CPU_HAS_ALTIVEC (1 << 1)
83 #define CPU_HAS_MMX (1 << 2)
84 #define CPU_HAS_3DNOW (1 << 3)
85 #define CPU_HAS_SSE (1 << 4)
86 #define CPU_HAS_SSE2 (1 << 5)
87 #define CPU_HAS_SSE3 (1 << 6)
88 #define CPU_HAS_SSE41 (1 << 7)
89 #define CPU_HAS_SSE42 (1 << 8)
90 #define CPU_HAS_AVX (1 << 9)
91 #define CPU_HAS_AVX2 (1 << 10)
92 #define CPU_HAS_NEON (1 << 11)
93 #define CPU_HAS_AVX512F (1 << 12)
94 #define CPU_HAS_MSA (1 << 13)
95 #define CPU_HAS_LSX (1 << 14)
96 #define CPU_HAS_LASX (1 << 15)
97 
98 #define CPU_CFG2 0x2
99 #define CPU_CFG2_LSX (1 << 6)
100 #define CPU_CFG2_LASX (1 << 7)
101 
102 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
103 /* This is the brute force way of detecting instruction sets...
104  the idea is borrowed from the libmpeg2 library - thanks!
105  */
106 static jmp_buf jmpbuf;
107 static void
108 illegal_instruction(int sig)
109 {
110  longjmp(jmpbuf, 1);
111 }
112 #endif /* HAVE_SETJMP */
113 
114 static int
116 {
117  int has_CPUID = 0;
118 
119 /* *INDENT-OFF* */
120 #ifndef SDL_CPUINFO_DISABLED
121 #if defined(__GNUC__) && defined(i386)
122  __asm__ (
123 " pushfl # Get original EFLAGS \n"
124 " popl %%eax \n"
125 " movl %%eax,%%ecx \n"
126 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
127 " pushl %%eax # Save new EFLAGS value on stack \n"
128 " popfl # Replace current EFLAGS value \n"
129 " pushfl # Get new EFLAGS \n"
130 " popl %%eax # Store new EFLAGS in EAX \n"
131 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
132 " jz 1f # Processor=80486 \n"
133 " movl $1,%0 # We have CPUID support \n"
134 "1: \n"
135  : "=m" (has_CPUID)
136  :
137  : "%eax", "%ecx"
138  );
139 #elif defined(__GNUC__) && defined(__x86_64__)
140 /* Technically, if this is being compiled under __x86_64__ then it has
141  CPUid by definition. But it's nice to be able to prove it. :) */
142  __asm__ (
143 " pushfq # Get original EFLAGS \n"
144 " popq %%rax \n"
145 " movq %%rax,%%rcx \n"
146 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
147 " pushq %%rax # Save new EFLAGS value on stack \n"
148 " popfq # Replace current EFLAGS value \n"
149 " pushfq # Get new EFLAGS \n"
150 " popq %%rax # Store new EFLAGS in EAX \n"
151 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
152 " jz 1f # Processor=80486 \n"
153 " movl $1,%0 # We have CPUID support \n"
154 "1: \n"
155  : "=m" (has_CPUID)
156  :
157  : "%rax", "%rcx"
158  );
159 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
160  __asm {
161  pushfd ; Get original EFLAGS
162  pop eax
163  mov ecx, eax
164  xor eax, 200000h ; Flip ID bit in EFLAGS
165  push eax ; Save new EFLAGS value on stack
166  popfd ; Replace current EFLAGS value
167  pushfd ; Get new EFLAGS
168  pop eax ; Store new EFLAGS in EAX
169  xor eax, ecx ; Can not toggle ID bit,
170  jz done ; Processor=80486
171  mov has_CPUID,1 ; We have CPUID support
172 done:
173  }
174 #elif defined(_MSC_VER) && defined(_M_X64)
175  has_CPUID = 1;
176 #elif defined(__sun) && defined(__i386)
177  __asm (
178 " pushfl \n"
179 " popl %eax \n"
180 " movl %eax,%ecx \n"
181 " xorl $0x200000,%eax \n"
182 " pushl %eax \n"
183 " popfl \n"
184 " pushfl \n"
185 " popl %eax \n"
186 " xorl %ecx,%eax \n"
187 " jz 1f \n"
188 " movl $1,-8(%ebp) \n"
189 "1: \n"
190  );
191 #elif defined(__sun) && defined(__amd64)
192  __asm (
193 " pushfq \n"
194 " popq %rax \n"
195 " movq %rax,%rcx \n"
196 " xorl $0x200000,%eax \n"
197 " pushq %rax \n"
198 " popfq \n"
199 " pushfq \n"
200 " popq %rax \n"
201 " xorl %ecx,%eax \n"
202 " jz 1f \n"
203 " movl $1,-8(%rbp) \n"
204 "1: \n"
205  );
206 #endif
207 #endif
208 /* *INDENT-ON* */
209  return has_CPUID;
210 }
211 
212 #if defined(__GNUC__) && defined(i386)
213 #define cpuid(func, a, b, c, d) \
214  __asm__ __volatile__ ( \
215 " pushl %%ebx \n" \
216 " xorl %%ecx,%%ecx \n" \
217 " cpuid \n" \
218 " movl %%ebx, %%esi \n" \
219 " popl %%ebx \n" : \
220  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
221 #elif defined(__GNUC__) && defined(__x86_64__)
222 #define cpuid(func, a, b, c, d) \
223  __asm__ __volatile__ ( \
224 " pushq %%rbx \n" \
225 " xorq %%rcx,%%rcx \n" \
226 " cpuid \n" \
227 " movq %%rbx, %%rsi \n" \
228 " popq %%rbx \n" : \
229  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
230 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
231 #define cpuid(func, a, b, c, d) \
232  __asm { \
233  __asm mov eax, func \
234  __asm xor ecx, ecx \
235  __asm cpuid \
236  __asm mov a, eax \
237  __asm mov b, ebx \
238  __asm mov c, ecx \
239  __asm mov d, edx \
240 }
241 #elif defined(_MSC_VER) && defined(_M_X64)
242 #define cpuid(func, a, b, c, d) \
243 { \
244  int CPUInfo[4]; \
245  __cpuid(CPUInfo, func); \
246  a = CPUInfo[0]; \
247  b = CPUInfo[1]; \
248  c = CPUInfo[2]; \
249  d = CPUInfo[3]; \
250 }
251 #else
252 #define cpuid(func, a, b, c, d) \
253  do { a = b = c = d = 0; (void) a; (void) b; (void) c; (void) d; } while (0)
254 #endif
255 
256 static int CPU_CPUIDFeatures[4];
257 static int CPU_CPUIDMaxFunction = 0;
260 
261 static void
263 {
264  static SDL_bool checked = SDL_FALSE;
265  if (!checked) {
266  checked = SDL_TRUE;
267  if (CPU_haveCPUID()) {
268  int a, b, c, d;
269  cpuid(0, a, b, c, d);
271  if (CPU_CPUIDMaxFunction >= 1) {
272  cpuid(1, a, b, c, d);
273  CPU_CPUIDFeatures[0] = a;
274  CPU_CPUIDFeatures[1] = b;
275  CPU_CPUIDFeatures[2] = c;
276  CPU_CPUIDFeatures[3] = d;
277 
278  /* Check to make sure we can call xgetbv */
279  if (c & 0x08000000) {
280  /* Call xgetbv to see if YMM (etc) register state is saved */
281 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
282  __asm__(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
283 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
284  a = (int)_xgetbv(0);
285 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
286  __asm
287  {
288  xor ecx, ecx
289  _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
290  mov a, eax
291  }
292 #endif
293  CPU_OSSavesYMM = ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
294  CPU_OSSavesZMM = (CPU_OSSavesYMM && ((a & 0xe0) == 0xe0)) ? SDL_TRUE : SDL_FALSE;
295  }
296  }
297  }
298  }
299 }
300 
301 static int
303 {
304  volatile int altivec = 0;
305 #ifndef SDL_CPUINFO_DISABLED
306 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
307 #ifdef __OpenBSD__
308  int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
309 #else
310  int selectors[2] = { CTL_HW, HW_VECTORUNIT };
311 #endif
312  int hasVectorUnit = 0;
313  size_t length = sizeof(hasVectorUnit);
314  int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
315  if (0 == error)
316  altivec = (hasVectorUnit != 0);
317 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
318  void (*handler) (int sig);
319  handler = signal(SIGILL, illegal_instruction);
320  if (setjmp(jmpbuf) == 0) {
321  asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
322  altivec = 1;
323  }
324  signal(SIGILL, handler);
325 #endif
326 #endif
327  return altivec;
328 }
329 
330 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
331 static int
332 readProcAuxvForNeon(void)
333 {
334  int neon = 0;
335  int kv[2];
336  const int fd = open("/proc/self/auxv", O_RDONLY);
337  if (fd != -1) {
338  while (read(fd, kv, sizeof (kv)) == sizeof (kv)) {
339  if (kv[0] == AT_HWCAP) {
340  neon = ((kv[1] & HWCAP_NEON) == HWCAP_NEON);
341  break;
342  }
343  }
344  close(fd);
345  }
346  return neon;
347 }
348 #endif
349 
350 
351 static int
353 {
354 /* The way you detect NEON is a privileged instruction on ARM, so you have
355  query the OS kernel in a platform-specific way. :/ */
356 #if defined(SDL_CPUINFO_DISABLED) || !defined(__ARM_ARCH)
357  return 0; /* disabled or not an ARM CPU at all. */
358 #elif __ARM_ARCH >= 8
359  return 1; /* ARMv8 always has non-optional NEON support. */
360 #elif defined(__APPLE__) && (__ARM_ARCH >= 7)
361  /* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
362  return 1; /* all Apple ARMv7 chips and later have NEON. */
363 #elif defined(__APPLE__)
364  return 0; /* assume anything else from Apple doesn't have NEON. */
365 #elif defined(__QNXNTO__)
366  return SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_NEON;
367 #elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL)
368  return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON);
369 #elif (defined(__LINUX__) || defined(__ANDROID__))
370  return readProcAuxvForNeon(); /* Android offers a static library for this, but it just parses /proc/self/auxv */
371 #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM)
372  /* All WinRT ARM devices are required to support NEON, but just in case. */
373  return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
374 #else
375 #warning SDL_HasNEON is not implemented for this ARM platform. Write me.
376  return 0;
377 #endif
378 }
379 
380 static int
382 {
383  uint32_t flags = 0;
384  char buf[1024];
385 
386 # ifdef __linux__
387  FILE* fp = fopen("/proc/cpuinfo", "r");
388  if (!fp)
389  return flags;
390 
391  memset(buf, 0, sizeof(buf));
392  while (fgets(buf, sizeof(buf), fp)) {
393  if (!strncmp(buf, "cpu model", strlen("cpu model"))) {
394  /* In case of some kernel havn't add loongson extention in ASEs implemented,
395  * analysis cpu model is still needed.
396  */
397  if (strstr(buf, "Loongson-2K")) {
398  flags = 1;
399  break;
400  }
401  }
402  if (!strncmp(buf, "ASEs implemented", strlen("ASEs implemented"))) {
403  if (strstr(buf, "msa")) {
404  flags = 1;
405  }
406  break;
407  }
408  }
409 
410  fclose(fp);
411 # endif
412  return flags;
413 
414 }
415 
416 static int
418 {
419  uint32_t cfg2 = 0;
420 #if defined __loongarch__
421  __asm__ volatile(
422  "cpucfg %0, %1 \n\t"
423  : "+&r"(cfg2)
424  : "r"(CPU_CFG2)
425  );
426 #endif
427  return cfg2;
428 }
429 
430 #define CPU_haveLSX() (CPU_readCPUCFG() & CPU_CFG2_LSX)
431 #define CPU_haveLASX() (CPU_readCPUCFG() & CPU_CFG2_LASX)
432 
433 static int
435 {
436  if (CPU_CPUIDMaxFunction > 0) { /* that is, do we have CPUID at all? */
437  int a, b, c, d;
438  cpuid(0x80000000, a, b, c, d);
439  if (a >= 0x80000001) {
440  cpuid(0x80000001, a, b, c, d);
441  return (d & 0x80000000);
442  }
443  }
444  return 0;
445 }
446 
447 #define CPU_haveRDTSC() (CPU_CPUIDFeatures[3] & 0x00000010)
448 #define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
449 #define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
450 #define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
451 #define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
452 #define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
453 #define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
454 #define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
455 
456 static int
458 {
459  if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
460  int a, b, c, d;
461  (void) a; (void) b; (void) c; (void) d; /* compiler warnings... */
462  cpuid(7, a, b, c, d);
463  return (b & 0x00000020);
464  }
465  return 0;
466 }
467 
468 static int
470 {
471  if (CPU_OSSavesZMM && (CPU_CPUIDMaxFunction >= 7)) {
472  int a, b, c, d;
473  (void) a; (void) b; (void) c; (void) d; /* compiler warnings... */
474  cpuid(7, a, b, c, d);
475  return (b & 0x00010000);
476  }
477  return 0;
478 }
479 
480 static int SDL_CPUCount = 0;
481 
482 int
484 {
485  if (!SDL_CPUCount) {
486 #ifndef SDL_CPUINFO_DISABLED
487 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
488  if (SDL_CPUCount <= 0) {
489  SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
490  }
491 #endif
492 #ifdef HAVE_SYSCTLBYNAME
493  if (SDL_CPUCount <= 0) {
494  size_t size = sizeof(SDL_CPUCount);
495  sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
496  }
497 #endif
498 #ifdef __WIN32__
499  if (SDL_CPUCount <= 0) {
500  SYSTEM_INFO info;
501  GetSystemInfo(&info);
502  SDL_CPUCount = info.dwNumberOfProcessors;
503  }
504 #endif
505 #ifdef __OS2__
506  if (SDL_CPUCount <= 0) {
507  DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
508  &SDL_CPUCount, sizeof(SDL_CPUCount) );
509  }
510 #endif
511 #endif
512  /* There has to be at least 1, right? :) */
513  if (SDL_CPUCount <= 0) {
514  SDL_CPUCount = 1;
515  }
516  }
517  return SDL_CPUCount;
518 }
519 
520 /* Oh, such a sweet sweet trick, just not very useful. :) */
521 static const char *
523 {
524  static char SDL_CPUType[13];
525 
526  if (!SDL_CPUType[0]) {
527  int i = 0;
528 
530  if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
531  int a, b, c, d;
532  cpuid(0x00000000, a, b, c, d);
533  (void) a;
534  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
535  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
536  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
537  SDL_CPUType[i++] = (char)(b & 0xff);
538 
539  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
540  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
541  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
542  SDL_CPUType[i++] = (char)(d & 0xff);
543 
544  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
545  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
546  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
547  SDL_CPUType[i++] = (char)(c & 0xff);
548  }
549  if (!SDL_CPUType[0]) {
550  SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
551  }
552  }
553  return SDL_CPUType;
554 }
555 
556 
557 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
558 static const char *
559 SDL_GetCPUName(void)
560 {
561  static char SDL_CPUName[48];
562 
563  if (!SDL_CPUName[0]) {
564  int i = 0;
565  int a, b, c, d;
566 
568  if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
569  cpuid(0x80000000, a, b, c, d);
570  if (a >= 0x80000004) {
571  cpuid(0x80000002, a, b, c, d);
572  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
573  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
574  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
575  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
576  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
577  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
578  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
579  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
580  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
581  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
582  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
583  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
584  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
585  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
586  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
587  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
588  cpuid(0x80000003, a, b, c, d);
589  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
590  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
591  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
592  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
593  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
594  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
595  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
596  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
597  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
598  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
599  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
600  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
601  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
602  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
603  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
604  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
605  cpuid(0x80000004, a, b, c, d);
606  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
607  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
608  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
609  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
610  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
611  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
612  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
613  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
614  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
615  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
616  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
617  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
618  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
619  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
620  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
621  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
622  }
623  }
624  if (!SDL_CPUName[0]) {
625  SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
626  }
627  }
628  return SDL_CPUName;
629 }
630 #endif
631 
632 int
634 {
635  const char *cpuType = SDL_GetCPUType();
636  int a, b, c, d;
637  (void) a; (void) b; (void) c; (void) d;
638  if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
639  cpuid(0x00000001, a, b, c, d);
640  return (((b >> 8) & 0xff) * 8);
641  } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
642  cpuid(0x80000005, a, b, c, d);
643  return (c & 0xff);
644  } else {
645  /* Just make a guess here... */
646  return SDL_CACHELINE_SIZE;
647  }
648 }
649 
650 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
651 static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
652 
653 static Uint32
655 {
656  if (SDL_CPUFeatures == 0xFFFFFFFF) {
658  SDL_CPUFeatures = 0;
659  SDL_SIMDAlignment = 4; /* a good safe base value */
660  if (CPU_haveRDTSC()) {
662  }
663  if (CPU_haveAltiVec()) {
666  }
667  if (CPU_haveMMX()) {
670  }
671  if (CPU_have3DNow()) {
674  }
675  if (CPU_haveSSE()) {
678  }
679  if (CPU_haveSSE2()) {
682  }
683  if (CPU_haveSSE3()) {
686  }
687  if (CPU_haveSSE41()) {
690  }
691  if (CPU_haveSSE42()) {
694  }
695  if (CPU_haveAVX()) {
698  }
699  if (CPU_haveAVX2()) {
702  }
703  if (CPU_haveAVX512F()) {
706  }
707  if (CPU_haveNEON()) {
710  }
711  if (CPU_haveMSA()) {
714  }
715  if (CPU_haveLSX()) {
718  }
719  if (CPU_haveLASX()) {
722  }
723  }
724  return SDL_CPUFeatures;
725 }
726 
727 #define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & f) ? SDL_TRUE : SDL_FALSE)
728 
730 {
732 }
733 
734 SDL_bool
736 {
738 }
739 
740 SDL_bool
742 {
744 }
745 
746 SDL_bool
748 {
750 }
751 
752 SDL_bool
754 {
756 }
757 
758 SDL_bool
760 {
762 }
763 
764 SDL_bool
766 {
768 }
769 
770 SDL_bool
772 {
774 }
775 
776 SDL_bool
778 {
780 }
781 
782 SDL_bool
784 {
786 }
787 
788 SDL_bool
790 {
792 }
793 
794 SDL_bool
796 {
798 }
799 
800 SDL_bool
802 {
804 }
805 
806 SDL_bool
808 {
810 }
811 
812 SDL_bool
814 {
816 }
817 
818 SDL_bool
820 {
822 }
823 
824 static int SDL_SystemRAM = 0;
825 
826 int
828 {
829  if (!SDL_SystemRAM) {
830 #ifndef SDL_CPUINFO_DISABLED
831 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
832  if (SDL_SystemRAM <= 0) {
833  SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
834  }
835 #endif
836 #ifdef HAVE_SYSCTLBYNAME
837  if (SDL_SystemRAM <= 0) {
838 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
839 #ifdef HW_REALMEM
840  int mib[2] = {CTL_HW, HW_REALMEM};
841 #else
842  /* might only report up to 2 GiB */
843  int mib[2] = {CTL_HW, HW_PHYSMEM};
844 #endif /* HW_REALMEM */
845 #else
846  int mib[2] = {CTL_HW, HW_MEMSIZE};
847 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
848  Uint64 memsize = 0;
849  size_t len = sizeof(memsize);
850 
851  if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
852  SDL_SystemRAM = (int)(memsize / (1024*1024));
853  }
854  }
855 #endif
856 #ifdef __WIN32__
857  if (SDL_SystemRAM <= 0) {
858  MEMORYSTATUSEX stat;
859  stat.dwLength = sizeof(stat);
860  if (GlobalMemoryStatusEx(&stat)) {
861  SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
862  }
863  }
864 #endif
865 #ifdef __OS2__
866  if (SDL_SystemRAM <= 0) {
867  Uint32 sysram = 0;
868  DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &sysram, 4);
869  SDL_SystemRAM = (int) (sysram / 0x100000U);
870  }
871 #endif
872 #endif
873  }
874  return SDL_SystemRAM;
875 }
876 
877 
878 size_t
880 {
881  if (SDL_SIMDAlignment == 0xFFFFFFFF) {
882  SDL_GetCPUFeatures(); /* make sure this has been calculated */
883  }
885  return SDL_SIMDAlignment;
886 }
887 
888 void *
889 SDL_SIMDAlloc(const size_t len)
890 {
891  const size_t alignment = SDL_SIMDGetAlignment();
892  const size_t padding = alignment - (len % alignment);
893  const size_t padded = (padding != alignment) ? (len + padding) : len;
894  Uint8 *retval = NULL;
895  Uint8 *ptr = (Uint8 *) SDL_malloc(padded + alignment + sizeof (void *));
896  if (ptr) {
897  /* store the actual malloc pointer right before our aligned pointer. */
898  retval = ptr + sizeof (void *);
899  retval += alignment - (((size_t) retval) % alignment);
900  *(((void **) retval) - 1) = ptr;
901  }
902  return retval;
903 }
904 
905 void
906 SDL_SIMDFree(void *ptr)
907 {
908  if (ptr) {
909  void **realptr = (void **) ptr;
910  realptr--;
911  SDL_free(*(((void **) ptr) - 1));
912  }
913 }
914 
915 
916 #ifdef TEST_MAIN
917 
918 #include <stdio.h>
919 
920 int
921 main()
922 {
923  printf("CPU count: %d\n", SDL_GetCPUCount());
924  printf("CPU type: %s\n", SDL_GetCPUType());
925  printf("CPU name: %s\n", SDL_GetCPUName());
926  printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
927  printf("RDTSC: %d\n", SDL_HasRDTSC());
928  printf("Altivec: %d\n", SDL_HasAltiVec());
929  printf("MMX: %d\n", SDL_HasMMX());
930  printf("3DNow: %d\n", SDL_Has3DNow());
931  printf("SSE: %d\n", SDL_HasSSE());
932  printf("SSE2: %d\n", SDL_HasSSE2());
933  printf("SSE3: %d\n", SDL_HasSSE3());
934  printf("SSE4.1: %d\n", SDL_HasSSE41());
935  printf("SSE4.2: %d\n", SDL_HasSSE42());
936  printf("AVX: %d\n", SDL_HasAVX());
937  printf("AVX2: %d\n", SDL_HasAVX2());
938  printf("AVX-512F: %d\n", SDL_HasAVX512F());
939  printf("NEON: %d\n", SDL_HasNEON());
940  printf("MSA: %d\n", SDL_HasMSA());
941  printf("LSX: %d\n", SDL_HasLSX());
942  printf("LASX: %d\n", SDL_HasLASX());
943  printf("RAM: %d MB\n", SDL_GetSystemRAM());
944  return 0;
945 }
946 
947 #endif /* TEST_MAIN */
948 
949 /* vi: set ts=4 sw=4 expandtab: */
#define CPU_haveSSE2()
Definition: SDL_cpuinfo.c:450
#define CPU_haveAVX()
Definition: SDL_cpuinfo.c:454
#define CPU_HAS_SSE41
Definition: SDL_cpuinfo.c:88
#define SDL_strlcpy
#define CPU_CFG2
Definition: SDL_cpuinfo.c:98
#define CPU_HAS_RDTSC
Definition: SDL_cpuinfo.c:81
void SDL_SIMDFree(void *ptr)
Deallocate memory obtained from SDL_SIMDAlloc.
Definition: SDL_cpuinfo.c:906
static SDL_bool CPU_OSSavesYMM
Definition: SDL_cpuinfo.c:258
#define CPU_HAS_SSE3
Definition: SDL_cpuinfo.c:87
#define CPU_HAS_LSX
Definition: SDL_cpuinfo.c:95
SDL_bool SDL_HasSSE41(void)
Definition: SDL_cpuinfo.c:771
static void CPU_calcCPUIDFeatures(void)
Definition: SDL_cpuinfo.c:262
int SDL_GetCPUCount(void)
Definition: SDL_cpuinfo.c:483
static const char * SDL_GetCPUType(void)
Definition: SDL_cpuinfo.c:522
GLfloat GLfloat GLfloat GLfloat h
#define CPU_haveLSX()
Definition: SDL_cpuinfo.c:430
#define CPU_HAS_SSE2
Definition: SDL_cpuinfo.c:86
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define CPU_HAS_AVX512F
Definition: SDL_cpuinfo.c:93
SDL_bool SDL_HasAVX512F(void)
Definition: SDL_cpuinfo.c:795
#define CPU_HAS_MSA
Definition: SDL_cpuinfo.c:94
#define memset
Definition: SDL_malloc.c:619
SDL_bool SDL_HasSSE(void)
Definition: SDL_cpuinfo.c:753
SDL_bool SDL_HasLASX(void)
Definition: SDL_cpuinfo.c:819
SDL_bool SDL_HasSSE3(void)
Definition: SDL_cpuinfo.c:765
static int CPU_CPUIDMaxFunction
Definition: SDL_cpuinfo.c:257
static int CPU_have3DNow(void)
Definition: SDL_cpuinfo.c:434
void * SDL_SIMDAlloc(const size_t len)
Allocate memory in a SIMD-friendly way.
Definition: SDL_cpuinfo.c:889
#define CPU_haveRDTSC()
Definition: SDL_cpuinfo.c:447
SDL_bool SDL_HasAltiVec(void)
Definition: SDL_cpuinfo.c:735
uint32_t Uint32
Definition: SDL_stdinc.h:203
static int CPU_haveMSA(void)
Definition: SDL_cpuinfo.c:381
#define CPU_HAS_ALTIVEC
Definition: SDL_cpuinfo.c:82
static int SDL_SystemRAM
Definition: SDL_cpuinfo.c:824
static int CPU_haveCPUID(void)
Definition: SDL_cpuinfo.c:115
#define CPU_haveMMX()
Definition: SDL_cpuinfo.c:448
uint64_t Uint64
Definition: SDL_stdinc.h:216
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
SDL_bool SDL_HasSSE42(void)
Definition: SDL_cpuinfo.c:777
GLenum GLsizei len
SDL_bool SDL_HasMMX(void)
Definition: SDL_cpuinfo.c:741
SDL_bool SDL_HasAVX2(void)
Definition: SDL_cpuinfo.c:789
static int CPU_haveAltiVec(void)
Definition: SDL_cpuinfo.c:302
static int CPU_haveAVX512F(void)
Definition: SDL_cpuinfo.c:469
static SDL_bool CPU_OSSavesZMM
Definition: SDL_cpuinfo.c:259
#define CPU_HAS_AVX
Definition: SDL_cpuinfo.c:90
static int CPU_readCPUCFG(void)
Definition: SDL_cpuinfo.c:417
#define CPU_FEATURE_AVAILABLE(f)
Definition: SDL_cpuinfo.c:727
unsigned int size_t
SDL_bool retval
SDL_bool SDL_HasLSX(void)
Definition: SDL_cpuinfo.c:813
#define CPU_haveSSE42()
Definition: SDL_cpuinfo.c:453
#define CPU_HAS_NEON
Definition: SDL_cpuinfo.c:92
#define CPU_haveSSE3()
Definition: SDL_cpuinfo.c:451
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
#define SDL_free
#define pop
Definition: SDL_qsort.c:192
int done
Definition: checkkeys.c:28
SDL_bool SDL_HasNEON(void)
Definition: SDL_cpuinfo.c:801
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:107
const GLubyte * c
GLsizei const GLfloat * value
#define cpuid(func, a, b, c, d)
Definition: SDL_cpuinfo.c:252
SDL_bool SDL_HasAVX(void)
Definition: SDL_cpuinfo.c:783
static Uint32 SDL_CPUFeatures
Definition: SDL_cpuinfo.c:650
static Uint32 SDL_GetCPUFeatures(void)
Definition: SDL_cpuinfo.c:654
#define CPU_HAS_SSE
Definition: SDL_cpuinfo.c:85
static int CPU_haveAVX2(void)
Definition: SDL_cpuinfo.c:457
GLenum GLuint GLenum GLsizei const GLchar * buf
GLsizeiptr size
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define CPU_HAS_AVX2
Definition: SDL_cpuinfo.c:91
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_bool SDL_HasMSA(void)
Definition: SDL_cpuinfo.c:807
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:161
static int CPU_haveNEON(void)
Definition: SDL_cpuinfo.c:352
#define CPU_haveSSE()
Definition: SDL_cpuinfo.c:449
unsigned int uint32_t
SDL_bool SDL_HasRDTSC(void)
Definition: SDL_cpuinfo.c:729
#define CPU_HAS_MMX
Definition: SDL_cpuinfo.c:83
GLbitfield flags
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define CPU_haveLASX()
Definition: SDL_cpuinfo.c:431
int SDL_GetSystemRAM(void)
Definition: SDL_cpuinfo.c:827
#define SDL_malloc
#define CPU_haveSSE41()
Definition: SDL_cpuinfo.c:452
static int SDL_CPUCount
Definition: SDL_cpuinfo.c:480
#define main
Definition: SDL_main.h:111
#define CPU_HAS_SSE42
Definition: SDL_cpuinfo.c:89
#define SDL_strcmp
static Uint32 SDL_SIMDAlignment
Definition: SDL_cpuinfo.c:651
size_t SDL_SIMDGetAlignment(void)
Report the alignment this system needs for SIMD allocations.
Definition: SDL_cpuinfo.c:879
int64_t Sint64
Definition: SDL_stdinc.h:210
static int CPU_CPUIDFeatures[4]
Definition: SDL_cpuinfo.c:256
GLuint GLsizei GLsizei * length
GLboolean GLboolean GLboolean GLboolean a
SDL_bool SDL_HasSSE2(void)
Definition: SDL_cpuinfo.c:759
#define CPU_HAS_LASX
Definition: SDL_cpuinfo.c:96
GLuint in
#define CPU_HAS_3DNOW
Definition: SDL_cpuinfo.c:84
GLboolean GLboolean GLboolean b
SDL_bool SDL_Has3DNow(void)
Definition: SDL_cpuinfo.c:747
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
int SDL_GetCPUCacheLineSize(void)
Definition: SDL_cpuinfo.c:633