src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 17 Nov 2016 01:41:56 -0500
changeset 10623 3b93b7acc1b4
parent 10622 972f7f6dd9b9
child 10624 294ee69a9f11
permissions -rw-r--r--
cpuinfo: silence compiler warnings on non-Intel CPU architectures.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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 #endif
    26 
    27 #if defined(__WIN32__)
    28 #include "../core/windows/SDL_windows.h"
    29 #endif
    30 
    31 /* CPU feature detection for SDL */
    32 
    33 #include "SDL_cpuinfo.h"
    34 
    35 #ifdef HAVE_SYSCONF
    36 #include <unistd.h>
    37 #endif
    38 #ifdef HAVE_SYSCTLBYNAME
    39 #include <sys/types.h>
    40 #include <sys/sysctl.h>
    41 #endif
    42 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
    43 #include <sys/sysctl.h>         /* For AltiVec check */
    44 #elif defined(__OpenBSD__) && defined(__powerpc__)
    45 #include <sys/param.h>
    46 #include <sys/sysctl.h> /* For AltiVec check */
    47 #include <machine/cpu.h>
    48 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
    49 #include <signal.h>
    50 #include <setjmp.h>
    51 #endif
    52 
    53 #if 0  /* !!! FIXME */
    54 #if defined(__ANDROID__) && defined(__ARM_ARCH)
    55 #include <cpu-features.h>
    56 #endif
    57 #endif
    58 
    59 #if defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
    60 #include <sys/auxv.h>
    61 #include <asm/hwcap.h>
    62 #endif
    63 
    64 #define CPU_HAS_RDTSC   0x00000001
    65 #define CPU_HAS_ALTIVEC 0x00000002
    66 #define CPU_HAS_MMX     0x00000004
    67 #define CPU_HAS_3DNOW   0x00000008
    68 #define CPU_HAS_SSE     0x00000010
    69 #define CPU_HAS_SSE2    0x00000020
    70 #define CPU_HAS_SSE3    0x00000040
    71 #define CPU_HAS_SSE41   0x00000100
    72 #define CPU_HAS_SSE42   0x00000200
    73 #define CPU_HAS_AVX     0x00000400
    74 #define CPU_HAS_AVX2    0x00000800
    75 #define CPU_HAS_NEON    0x00001000
    76 
    77 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
    78 /* This is the brute force way of detecting instruction sets...
    79    the idea is borrowed from the libmpeg2 library - thanks!
    80  */
    81 static jmp_buf jmpbuf;
    82 static void
    83 illegal_instruction(int sig)
    84 {
    85     longjmp(jmpbuf, 1);
    86 }
    87 #endif /* HAVE_SETJMP */
    88 
    89 static int
    90 CPU_haveCPUID(void)
    91 {
    92     int has_CPUID = 0;
    93 
    94 /* *INDENT-OFF* */
    95 #ifndef SDL_CPUINFO_DISABLED
    96 #if defined(__GNUC__) && defined(i386)
    97     __asm__ (
    98 "        pushfl                      # Get original EFLAGS             \n"
    99 "        popl    %%eax                                                 \n"
   100 "        movl    %%eax,%%ecx                                           \n"
   101 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
   102 "        pushl   %%eax               # Save new EFLAGS value on stack  \n"
   103 "        popfl                       # Replace current EFLAGS value    \n"
   104 "        pushfl                      # Get new EFLAGS                  \n"
   105 "        popl    %%eax               # Store new EFLAGS in EAX         \n"
   106 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
   107 "        jz      1f                  # Processor=80486                 \n"
   108 "        movl    $1,%0               # We have CPUID support           \n"
   109 "1:                                                                    \n"
   110     : "=m" (has_CPUID)
   111     :
   112     : "%eax", "%ecx"
   113     );
   114 #elif defined(__GNUC__) && defined(__x86_64__)
   115 /* Technically, if this is being compiled under __x86_64__ then it has 
   116    CPUid by definition.  But it's nice to be able to prove it.  :)      */
   117     __asm__ (
   118 "        pushfq                      # Get original EFLAGS             \n"
   119 "        popq    %%rax                                                 \n"
   120 "        movq    %%rax,%%rcx                                           \n"
   121 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
   122 "        pushq   %%rax               # Save new EFLAGS value on stack  \n"
   123 "        popfq                       # Replace current EFLAGS value    \n"
   124 "        pushfq                      # Get new EFLAGS                  \n"
   125 "        popq    %%rax               # Store new EFLAGS in EAX         \n"
   126 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
   127 "        jz      1f                  # Processor=80486                 \n"
   128 "        movl    $1,%0               # We have CPUID support           \n"
   129 "1:                                                                    \n"
   130     : "=m" (has_CPUID)
   131     :
   132     : "%rax", "%rcx"
   133     );
   134 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   135     __asm {
   136         pushfd                      ; Get original EFLAGS
   137         pop     eax
   138         mov     ecx, eax
   139         xor     eax, 200000h        ; Flip ID bit in EFLAGS
   140         push    eax                 ; Save new EFLAGS value on stack
   141         popfd                       ; Replace current EFLAGS value
   142         pushfd                      ; Get new EFLAGS
   143         pop     eax                 ; Store new EFLAGS in EAX
   144         xor     eax, ecx            ; Can not toggle ID bit,
   145         jz      done                ; Processor=80486
   146         mov     has_CPUID,1         ; We have CPUID support
   147 done:
   148     }
   149 #elif defined(_MSC_VER) && defined(_M_X64)
   150     has_CPUID = 1;
   151 #elif defined(__sun) && defined(__i386)
   152     __asm (
   153 "       pushfl                 \n"
   154 "       popl    %eax           \n"
   155 "       movl    %eax,%ecx      \n"
   156 "       xorl    $0x200000,%eax \n"
   157 "       pushl   %eax           \n"
   158 "       popfl                  \n"
   159 "       pushfl                 \n"
   160 "       popl    %eax           \n"
   161 "       xorl    %ecx,%eax      \n"
   162 "       jz      1f             \n"
   163 "       movl    $1,-8(%ebp)    \n"
   164 "1:                            \n"
   165     );
   166 #elif defined(__sun) && defined(__amd64)
   167     __asm (
   168 "       pushfq                 \n"
   169 "       popq    %rax           \n"
   170 "       movq    %rax,%rcx      \n"
   171 "       xorl    $0x200000,%eax \n"
   172 "       pushq   %rax           \n"
   173 "       popfq                  \n"
   174 "       pushfq                 \n"
   175 "       popq    %rax           \n"
   176 "       xorl    %ecx,%eax      \n"
   177 "       jz      1f             \n"
   178 "       movl    $1,-8(%rbp)    \n"
   179 "1:                            \n"
   180     );
   181 #endif
   182 #endif
   183 /* *INDENT-ON* */
   184     return has_CPUID;
   185 }
   186 
   187 #if defined(__GNUC__) && defined(i386)
   188 #define cpuid(func, a, b, c, d) \
   189     __asm__ __volatile__ ( \
   190 "        pushl %%ebx        \n" \
   191 "        xorl %%ecx,%%ecx   \n" \
   192 "        cpuid              \n" \
   193 "        movl %%ebx, %%esi  \n" \
   194 "        popl %%ebx         \n" : \
   195             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   196 #elif defined(__GNUC__) && defined(__x86_64__)
   197 #define cpuid(func, a, b, c, d) \
   198     __asm__ __volatile__ ( \
   199 "        pushq %%rbx        \n" \
   200 "        xorq %%rcx,%%rcx   \n" \
   201 "        cpuid              \n" \
   202 "        movq %%rbx, %%rsi  \n" \
   203 "        popq %%rbx         \n" : \
   204             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   205 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   206 #define cpuid(func, a, b, c, d) \
   207     __asm { \
   208         __asm mov eax, func \
   209         __asm xor ecx, ecx \
   210         __asm cpuid \
   211         __asm mov a, eax \
   212         __asm mov b, ebx \
   213         __asm mov c, ecx \
   214         __asm mov d, edx \
   215 }
   216 #elif defined(_MSC_VER) && defined(_M_X64)
   217 #define cpuid(func, a, b, c, d) \
   218 { \
   219     int CPUInfo[4]; \
   220     __cpuid(CPUInfo, func); \
   221     a = CPUInfo[0]; \
   222     b = CPUInfo[1]; \
   223     c = CPUInfo[2]; \
   224     d = CPUInfo[3]; \
   225 }
   226 #else
   227 #define cpuid(func, a, b, c, d) \
   228     a = b = c = d = 0
   229 #endif
   230 
   231 static int CPU_CPUIDFeatures[4];
   232 static int CPU_CPUIDMaxFunction = 0;
   233 static SDL_bool CPU_OSSavesYMM = SDL_FALSE;
   234 
   235 static void
   236 CPU_calcCPUIDFeatures(void)
   237 {
   238     static SDL_bool checked = SDL_FALSE;
   239     if (!checked) {
   240         checked = SDL_TRUE;
   241         if (CPU_haveCPUID()) {
   242             int a, b, c, d;
   243             cpuid(0, a, b, c, d);
   244             CPU_CPUIDMaxFunction = a;
   245             if (CPU_CPUIDMaxFunction >= 1) {
   246                 cpuid(1, a, b, c, d);
   247                 CPU_CPUIDFeatures[0] = a;
   248                 CPU_CPUIDFeatures[1] = b;
   249                 CPU_CPUIDFeatures[2] = c;
   250                 CPU_CPUIDFeatures[3] = d;
   251 
   252                 /* Check to make sure we can call xgetbv */
   253                 if (c & 0x08000000) {
   254                     /* Call xgetbv to see if YMM register state is saved */
   255 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
   256                     asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
   257 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
   258                     a = (int)_xgetbv(0);
   259 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   260                     __asm
   261                     {
   262                         xor ecx, ecx
   263                         _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
   264                         mov a, eax
   265                     }
   266 #endif
   267                     CPU_OSSavesYMM = ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
   268                 }
   269             }
   270         }
   271     }
   272 }
   273 
   274 static int
   275 CPU_haveAltiVec(void)
   276 {
   277     volatile int altivec = 0;
   278 #ifndef SDL_CPUINFO_DISABLED
   279 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
   280 #ifdef __OpenBSD__
   281     int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
   282 #else
   283     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
   284 #endif
   285     int hasVectorUnit = 0;
   286     size_t length = sizeof(hasVectorUnit);
   287     int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
   288     if (0 == error)
   289         altivec = (hasVectorUnit != 0);
   290 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
   291     void (*handler) (int sig);
   292     handler = signal(SIGILL, illegal_instruction);
   293     if (setjmp(jmpbuf) == 0) {
   294         asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
   295         altivec = 1;
   296     }
   297     signal(SIGILL, handler);
   298 #endif
   299 #endif
   300     return altivec;
   301 }
   302 
   303 static int
   304 CPU_haveNEON(void)
   305 {
   306     int neon = 0;
   307 
   308 /* The way you detect NEON is a privileged instruction on ARM, so you have
   309    query the OS kernel in a platform-specific way. :/ */
   310 #ifndef SDL_CPUINFO_DISABLED
   311 #if defined(__APPLE__) && defined(__ARM_ARCH)
   312     /* all hardware that runs iOS 5 and later support NEON, but check anyhow */
   313     size_t length = sizeof (neon);
   314     const int error = sysctlbyname("hw.optional.neon", &neon, &length, NULL, 0);
   315     if (!error)
   316         neon = (neon != 0);
   317 #elif 0 && defined(__ANDROID__) && defined(__ARM_ARCH)  /* !!! FIXME */
   318     if ( (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) &&
   319          ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0) ) {
   320         neon = 1;
   321     }
   322 #elif defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
   323     if (getauxval(AT_HWCAP) & HWCAP_NEON) {
   324         neon = 1;
   325     }
   326 #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM)
   327     /* All WinRT ARM devices are required to support NEON, but just in case. */
   328     if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
   329         neon = 1;
   330     }
   331 #endif
   332 #endif
   333 
   334     return neon;
   335 }
   336 
   337 static int
   338 CPU_have3DNow(void)
   339 {
   340     if (CPU_CPUIDMaxFunction > 0) {  /* that is, do we have CPUID at all? */
   341         int a, b, c, d;
   342         cpuid(0x80000000, a, b, c, d);
   343         if (a >= 0x80000001) {
   344             cpuid(0x80000001, a, b, c, d);
   345             return (d & 0x80000000);
   346         }
   347     }
   348     return 0;
   349 }
   350 
   351 #define CPU_haveRDTSC() (CPU_CPUIDFeatures[3] & 0x00000010)
   352 #define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
   353 #define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
   354 #define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
   355 #define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
   356 #define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
   357 #define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
   358 #define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
   359 
   360 static int
   361 CPU_haveAVX2(void)
   362 {
   363     if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
   364         int a, b, c, d;
   365         (void) a; (void) b; (void) c; (void) d;  /* compiler warnings... */
   366         cpuid(7, a, b, c, d);
   367         return (b & 0x00000020);
   368     }
   369     return 0;
   370 }
   371 
   372 static int SDL_CPUCount = 0;
   373 
   374 int
   375 SDL_GetCPUCount(void)
   376 {
   377     if (!SDL_CPUCount) {
   378 #ifndef SDL_CPUINFO_DISABLED
   379 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
   380         if (SDL_CPUCount <= 0) {
   381             SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
   382         }
   383 #endif
   384 #ifdef HAVE_SYSCTLBYNAME
   385         if (SDL_CPUCount <= 0) {
   386             size_t size = sizeof(SDL_CPUCount);
   387             sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
   388         }
   389 #endif
   390 #ifdef __WIN32__
   391         if (SDL_CPUCount <= 0) {
   392             SYSTEM_INFO info;
   393             GetSystemInfo(&info);
   394             SDL_CPUCount = info.dwNumberOfProcessors;
   395         }
   396 #endif
   397 #endif
   398         /* There has to be at least 1, right? :) */
   399         if (SDL_CPUCount <= 0) {
   400             SDL_CPUCount = 1;
   401         }
   402     }
   403     return SDL_CPUCount;
   404 }
   405 
   406 /* Oh, such a sweet sweet trick, just not very useful. :) */
   407 static const char *
   408 SDL_GetCPUType(void)
   409 {
   410     static char SDL_CPUType[13];
   411 
   412     if (!SDL_CPUType[0]) {
   413         int i = 0;
   414 
   415         CPU_calcCPUIDFeatures();
   416         if (CPU_CPUIDMaxFunction > 0) {  /* do we have CPUID at all? */
   417             int a, b, c, d;
   418             cpuid(0x00000000, a, b, c, d);
   419             (void) a;
   420             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   421             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   422             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   423             SDL_CPUType[i++] = (char)(b & 0xff);
   424 
   425             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   426             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   427             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   428             SDL_CPUType[i++] = (char)(d & 0xff);
   429 
   430             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   431             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   432             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   433             SDL_CPUType[i++] = (char)(c & 0xff);
   434         }
   435         if (!SDL_CPUType[0]) {
   436             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
   437         }
   438     }
   439     return SDL_CPUType;
   440 }
   441 
   442 
   443 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
   444 static const char *
   445 SDL_GetCPUName(void)
   446 {
   447     static char SDL_CPUName[48];
   448 
   449     if (!SDL_CPUName[0]) {
   450         int i = 0;
   451         int a, b, c, d;
   452 
   453         CPU_calcCPUIDFeatures();
   454         if (CPU_CPUIDMaxFunction > 0) {  /* do we have CPUID at all? */
   455             cpuid(0x80000000, a, b, c, d);
   456             if (a >= 0x80000004) {
   457                 cpuid(0x80000002, a, b, c, d);
   458                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   459                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   460                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   461                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   462                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   463                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   464                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   465                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   466                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   467                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   468                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   469                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   470                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   471                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   472                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   473                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   474                 cpuid(0x80000003, a, b, c, d);
   475                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   476                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   477                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   478                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   479                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   480                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   481                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   482                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   483                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   484                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   485                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   486                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   487                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   488                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   489                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   490                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   491                 cpuid(0x80000004, a, b, c, d);
   492                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   493                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   494                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   495                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   496                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   497                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   498                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   499                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   500                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   501                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   502                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   503                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   504                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   505                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   506                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   507                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   508             }
   509         }
   510         if (!SDL_CPUName[0]) {
   511             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
   512         }
   513     }
   514     return SDL_CPUName;
   515 }
   516 #endif
   517 
   518 int
   519 SDL_GetCPUCacheLineSize(void)
   520 {
   521     const char *cpuType = SDL_GetCPUType();
   522     int a, b, c, d;
   523     (void) a; (void) b; (void) c; (void) d;
   524     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   525         cpuid(0x00000001, a, b, c, d);
   526         return (((b >> 8) & 0xff) * 8);
   527     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   528         cpuid(0x80000005, a, b, c, d);
   529         return (c & 0xff);
   530     } else {
   531         /* Just make a guess here... */
   532         return SDL_CACHELINE_SIZE;
   533     }
   534 }
   535 
   536 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   537 
   538 static Uint32
   539 SDL_GetCPUFeatures(void)
   540 {
   541     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   542         CPU_calcCPUIDFeatures();
   543         SDL_CPUFeatures = 0;
   544         if (CPU_haveRDTSC()) {
   545             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   546         }
   547         if (CPU_haveAltiVec()) {
   548             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   549         }
   550         if (CPU_haveMMX()) {
   551             SDL_CPUFeatures |= CPU_HAS_MMX;
   552         }
   553         if (CPU_have3DNow()) {
   554             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   555         }
   556         if (CPU_haveSSE()) {
   557             SDL_CPUFeatures |= CPU_HAS_SSE;
   558         }
   559         if (CPU_haveSSE2()) {
   560             SDL_CPUFeatures |= CPU_HAS_SSE2;
   561         }
   562         if (CPU_haveSSE3()) {
   563             SDL_CPUFeatures |= CPU_HAS_SSE3;
   564         }
   565         if (CPU_haveSSE41()) {
   566             SDL_CPUFeatures |= CPU_HAS_SSE41;
   567         }
   568         if (CPU_haveSSE42()) {
   569             SDL_CPUFeatures |= CPU_HAS_SSE42;
   570         }
   571         if (CPU_haveAVX()) {
   572             SDL_CPUFeatures |= CPU_HAS_AVX;
   573         }
   574         if (CPU_haveAVX2()) {
   575             SDL_CPUFeatures |= CPU_HAS_AVX2;
   576         }
   577         if (CPU_haveNEON()) {
   578             SDL_CPUFeatures |= CPU_HAS_NEON;
   579         }
   580     }
   581     return SDL_CPUFeatures;
   582 }
   583 
   584 #define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & f) ? SDL_TRUE : SDL_FALSE)
   585 
   586 SDL_bool SDL_HasRDTSC(void)
   587 {
   588     return CPU_FEATURE_AVAILABLE(CPU_HAS_RDTSC);
   589 }
   590 
   591 SDL_bool
   592 SDL_HasAltiVec(void)
   593 {
   594     return CPU_FEATURE_AVAILABLE(CPU_HAS_ALTIVEC);
   595 }
   596 
   597 SDL_bool
   598 SDL_HasMMX(void)
   599 {
   600     return CPU_FEATURE_AVAILABLE(CPU_HAS_MMX);
   601 }
   602 
   603 SDL_bool
   604 SDL_Has3DNow(void)
   605 {
   606     return CPU_FEATURE_AVAILABLE(CPU_HAS_3DNOW);
   607 }
   608 
   609 SDL_bool
   610 SDL_HasSSE(void)
   611 {
   612     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE);
   613 }
   614 
   615 SDL_bool
   616 SDL_HasSSE2(void)
   617 {
   618     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE2);
   619 }
   620 
   621 SDL_bool
   622 SDL_HasSSE3(void)
   623 {
   624     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE3);
   625 }
   626 
   627 SDL_bool
   628 SDL_HasSSE41(void)
   629 {
   630     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE41);
   631 }
   632 
   633 SDL_bool
   634 SDL_HasSSE42(void)
   635 {
   636     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE42);
   637 }
   638 
   639 SDL_bool
   640 SDL_HasAVX(void)
   641 {
   642     return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX);
   643 }
   644 
   645 SDL_bool
   646 SDL_HasAVX2(void)
   647 {
   648     return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX2);
   649 }
   650 
   651 SDL_bool
   652 SDL_HasNEON(void)
   653 {
   654     return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON);
   655 }
   656 
   657 static int SDL_SystemRAM = 0;
   658 
   659 int
   660 SDL_GetSystemRAM(void)
   661 {
   662     if (!SDL_SystemRAM) {
   663 #ifndef SDL_CPUINFO_DISABLED
   664 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   665         if (SDL_SystemRAM <= 0) {
   666             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   667         }
   668 #endif
   669 #ifdef HAVE_SYSCTLBYNAME
   670         if (SDL_SystemRAM <= 0) {
   671 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
   672 #ifdef HW_REALMEM
   673             int mib[2] = {CTL_HW, HW_REALMEM};
   674 #else
   675             /* might only report up to 2 GiB */
   676             int mib[2] = {CTL_HW, HW_PHYSMEM};
   677 #endif /* HW_REALMEM */
   678 #else
   679             int mib[2] = {CTL_HW, HW_MEMSIZE};
   680 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   681             Uint64 memsize = 0;
   682             size_t len = sizeof(memsize);
   683             
   684             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   685                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   686             }
   687         }
   688 #endif
   689 #ifdef __WIN32__
   690         if (SDL_SystemRAM <= 0) {
   691             MEMORYSTATUSEX stat;
   692             stat.dwLength = sizeof(stat);
   693             if (GlobalMemoryStatusEx(&stat)) {
   694                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   695             }
   696         }
   697 #endif
   698 #endif
   699     }
   700     return SDL_SystemRAM;
   701 }
   702 
   703 
   704 #ifdef TEST_MAIN
   705 
   706 #include <stdio.h>
   707 
   708 int
   709 main()
   710 {
   711     printf("CPU count: %d\n", SDL_GetCPUCount());
   712     printf("CPU type: %s\n", SDL_GetCPUType());
   713     printf("CPU name: %s\n", SDL_GetCPUName());
   714     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   715     printf("RDTSC: %d\n", SDL_HasRDTSC());
   716     printf("Altivec: %d\n", SDL_HasAltiVec());
   717     printf("MMX: %d\n", SDL_HasMMX());
   718     printf("3DNow: %d\n", SDL_Has3DNow());
   719     printf("SSE: %d\n", SDL_HasSSE());
   720     printf("SSE2: %d\n", SDL_HasSSE2());
   721     printf("SSE3: %d\n", SDL_HasSSE3());
   722     printf("SSE4.1: %d\n", SDL_HasSSE41());
   723     printf("SSE4.2: %d\n", SDL_HasSSE42());
   724     printf("AVX: %d\n", SDL_HasAVX());
   725     printf("AVX2: %d\n", SDL_HasAVX2());
   726     printf("NEON: %d\n", SDL_HasNEON());
   727     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   728     return 0;
   729 }
   730 
   731 #endif /* TEST_MAIN */
   732 
   733 /* vi: set ts=4 sw=4 expandtab: */