Merge pull request #3395 from lambdageek/dev/handles-strings
[mono.git] / mono / utils / mono-hwcap-x86.c
1 /*
2  * mono-hwcap-x86.c: x86 hardware feature detection
3  *
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)
13  *
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.
20  */
21
22 #include "mono/utils/mono-hwcap.h"
23
24 #if defined(HAVE_UNISTD_H)
25 #include <unistd.h>
26 #endif
27 #if defined(_MSC_VER)
28 #include <intrin.h>
29 #endif
30
31 static gboolean
32 cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
33 {
34 #if defined(_MSC_VER)
35         int info [4];
36 #endif
37
38         /* First, make sure we can use cpuid if we're on 32-bit. */
39 #if defined(TARGET_X86)
40         gboolean have_cpuid = FALSE;
41
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
55         }
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)
70                 :
71                 : "%eax", "%edx"
72         );
73 #endif
74
75         if (!have_cpuid)
76                 return FALSE;
77 #endif
78
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)
96         );
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)
102         );
103 #endif
104
105         return TRUE;
106 }
107
108 void
109 mono_hwcap_arch_init (void)
110 {
111         int eax, ebx, ecx, edx;
112
113         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
114                 if (edx & (1 << 15)) {
115                         mono_hwcap_x86_has_cmov = TRUE;
116
117                         if (edx & 1)
118                                 mono_hwcap_x86_has_fcmov = TRUE;
119                 }
120
121                 if (edx & (1 << 25))
122                         mono_hwcap_x86_has_sse1 = TRUE;
123
124                 if (edx & (1 << 26))
125                         mono_hwcap_x86_has_sse2 = TRUE;
126
127                 if (ecx & (1 << 0))
128                         mono_hwcap_x86_has_sse3 = TRUE;
129
130                 if (ecx & (1 << 9))
131                         mono_hwcap_x86_has_ssse3 = TRUE;
132
133                 if (ecx & (1 << 19))
134                         mono_hwcap_x86_has_sse41 = TRUE;
135
136                 if (ecx & (1 << 20))
137                         mono_hwcap_x86_has_sse42 = TRUE;
138         }
139
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;
145                         }
146                 }
147         }
148
149 #if defined(HAVE_UNISTD_H)
150         mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
151 #endif
152 }