Merge pull request #3715 from kumpera/fix-44707
[mono-project.git] / mono / utils / mono-hwcap-x86.c
blob5d72a4c7e2030260e74b82369ffc82db450636f4
1 /*
2 * mono-hwcap-x86.c: x86 hardware feature detection
4 * Authors:
5 * Alex Rønne Petersen (alexrp@xamarin.com)
6 * Elijah Taylor (elijahtaylor@google.com)
7 * Miguel de Icaza (miguel@xamarin.com)
8 * Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
9 * Paolo Molaro (lupus@xamarin.com)
10 * Rodrigo Kumpera (kumpera@gmail.com)
11 * Sebastien Pouliot (sebastien@xamarin.com)
12 * Zoltan Varga (vargaz@xamarin.com)
14 * Copyright 2003 Ximian, Inc.
15 * Copyright 2003-2011 Novell, Inc
16 * Copyright 2006 Broadcom
17 * Copyright 2007-2008 Andreas Faerber
18 * Copyright 2011-2013 Xamarin Inc
19 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "mono/utils/mono-hwcap.h"
24 #if defined(HAVE_UNISTD_H)
25 #include <unistd.h>
26 #endif
27 #if defined(_MSC_VER)
28 #include <intrin.h>
29 #endif
31 static gboolean
32 cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
34 #if defined(_MSC_VER)
35 int info [4];
36 #endif
38 /* First, make sure we can use cpuid if we're on 32-bit. */
39 #if defined(TARGET_X86)
40 gboolean have_cpuid = FALSE;
42 #if defined(_MSC_VER)
43 __asm {
44 pushfd
45 pop eax
46 mov edx, eax
47 xor eax, 0x200000
48 push eax
49 popfd
50 pushfd
51 pop eax
52 xor eax, edx
53 and eax, 0x200000
54 mov have_cpuid, eax
56 #else
57 __asm__ __volatile__ (
58 "pushfl\n\t"
59 "popl\t%%eax\n\t"
60 "movl\t%%eax, %%edx\n\t"
61 "xorl\t$0x200000, %%eax\n\t"
62 "pushl\t%%eax\n\t"
63 "popfl\n\t"
64 "pushfl\n\t"
65 "popl\t%%eax\n\t"
66 "xorl\t%%edx, %%eax\n\t"
67 "andl\t$0x200000, %%eax\n\t"
68 "movl\t%%eax, %0\n\t"
69 : "=r" (have_cpuid)
71 : "%eax", "%edx"
73 #endif
75 if (!have_cpuid)
76 return FALSE;
77 #endif
79 /* Now issue the actual cpuid instruction. We can use
80 MSVC's __cpuid on both 32-bit and 64-bit. */
81 #if defined(_MSC_VER)
82 __cpuid (info, id);
83 *p_eax = info [0];
84 *p_ebx = info [1];
85 *p_ecx = info [2];
86 *p_edx = info [3];
87 #elif defined(TARGET_X86)
88 /* This complicated stuff is necessary because EBX
89 may be used by the compiler in PIC mode. */
90 __asm__ __volatile__ (
91 "xchgl\t%%ebx, %k1\n\t"
92 "cpuid\n\t"
93 "xchgl\t%%ebx, %k1\n\t"
94 : "=a" (*p_eax), "=&r" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
95 : "0" (id)
97 #else
98 __asm__ __volatile__ (
99 "cpuid\n\t"
100 : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
101 : "a" (id)
103 #endif
105 return TRUE;
108 void
109 mono_hwcap_arch_init (void)
111 int eax, ebx, ecx, edx;
113 if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
114 if (edx & (1 << 15)) {
115 mono_hwcap_x86_has_cmov = TRUE;
117 if (edx & 1)
118 mono_hwcap_x86_has_fcmov = TRUE;
121 if (edx & (1 << 25))
122 mono_hwcap_x86_has_sse1 = TRUE;
124 if (edx & (1 << 26))
125 mono_hwcap_x86_has_sse2 = TRUE;
127 if (ecx & (1 << 0))
128 mono_hwcap_x86_has_sse3 = TRUE;
130 if (ecx & (1 << 9))
131 mono_hwcap_x86_has_ssse3 = TRUE;
133 if (ecx & (1 << 19))
134 mono_hwcap_x86_has_sse41 = TRUE;
136 if (ecx & (1 << 20))
137 mono_hwcap_x86_has_sse42 = TRUE;
140 if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
141 if ((unsigned int) eax >= 0x80000001 && ebx == 0x68747541 && ecx == 0x444D4163 && edx == 0x69746E65) {
142 if (cpuid (0x80000001, &eax, &ebx, &ecx, &edx)) {
143 if (ecx & (1 << 6))
144 mono_hwcap_x86_has_sse4a = TRUE;
149 #if defined(HAVE_UNISTD_H)
150 mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
151 #endif