summaryrefslogtreecommitdiffstats
path: root/winsup/mingw/cpu_features.c
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/mingw/cpu_features.c')
-rwxr-xr-xwinsup/mingw/cpu_features.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/winsup/mingw/cpu_features.c b/winsup/mingw/cpu_features.c
new file mode 100755
index 000000000..0eccfbfe3
--- /dev/null
+++ b/winsup/mingw/cpu_features.c
@@ -0,0 +1,105 @@
+#include <stdbool.h>
+#include "cpu_features.h"
+
+/* level 1 edx bits */
+#define EDX_CX8 (1 << 8) /* CMPXCHG8B */
+#define EDX_CMOV (1 << 15)
+#define EDX_MMX (1 << 23)
+#define EDX_FXSR (1 << 24) /* FXSAVE and FXRSTOR */
+#define EDX_SSE (1 << 25)
+#define EDX_SSE2 (1 << 26)
+
+/* level 1 ecx bits */
+#define ECX_SSE3 (1 << 0)
+#define ECX_CX16 (1 << 13) /* CMPXCHG16B */
+
+/* extended level 0x80000001 edx bits */
+#define EDX_3DNOW (1 << 31)
+#define EDX_3DNOWP (1 << 30)
+#define EDX_LM (1 << 29) /*LONG MODE */
+
+#define __cpuid(level,a,b,c,d) \
+ __asm__ __volatile__ ("cpuid;" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d)\
+ : "0" (level))
+
+/* Combine the different cpuid flags into a single bitmap. */
+
+unsigned int __cpu_features = 0;
+
+void __cpu_features_init (void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ /* Try to change the value of CPUID bit (bit 21) in EFLAGS.
+ If the bit can be toggled, CPUID is supported. */
+ asm volatile ("pushfl; pushfl; popl %0;"
+ "movl %0,%1; xorl %2,%0;"
+ "pushl %0; popfl; pushfl; popl %0; popfl"
+ : "=&r" (eax), "=&r" (ebx)
+ : "i" (0x00200000));
+
+ if (((eax ^ ebx) & 0x00200000) == 0)
+ return;
+
+ __cpuid (0, eax, ebx, ecx, edx);
+ if (eax == 0)
+ return;
+
+ __cpuid (1, eax, ebx, ecx, edx);
+
+ if (edx & EDX_CX8)
+ __cpu_features |= _CRT_CMPXCHG8B;
+ if (edx & EDX_CMOV)
+ __cpu_features |= _CRT_CMOV;
+
+ if (edx & EDX_MMX)
+ __cpu_features |= _CRT_MMX;
+ if (edx & EDX_FXSR)
+ __cpu_features |= _CRT_FXSR;
+ if (edx & EDX_SSE)
+ __cpu_features |= _CRT_SSE;
+ if (edx & EDX_SSE2)
+ __cpu_features |= _CRT_SSE2;
+
+
+ if (ecx & ECX_SSE3)
+ __cpu_features |= _CRT_SSE3;
+ if (ecx & ECX_CX16)
+ __cpu_features |= _CRT_CMPXCHG16B;
+
+ __cpuid (0x80000000, eax, ebx, ecx, edx);
+ if (eax < 0x80000001)
+ return;
+ __cpuid (0x80000001, eax, ebx, ecx, edx);
+ if (edx & EDX_3DNOW);
+ __cpu_features |= _CRT_3DNOW;
+ if (edx & EDX_3DNOWP)
+ __cpu_features |= _CRT_3DNOWP;
+
+ return;
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+#define report(feature) \
+ if ((feature) & __cpu_features) printf( #feature " found\n")
+
+int main()
+{
+ __cpu_features_init();
+
+ report(_CRT_CMPXCHG8B);
+ report(_CRT_CMOV);
+ report(_CRT_MMX);
+ report(_CRT_FXSR);
+ report(_CRT_SSE);
+ report(_CRT_SSE2);
+ report(_CRT_SSE3);
+ report(_CRT_CMPXCHG16B);
+ report(_CRT_3DNOW);
+ report(_CRT_3DNOWP);
+ return 0;
+}
+
+#endif