Merge pull request #2816 from xmcclure/profile-clean-0
[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-x86.h"
23
24 #if defined(HAVE_UNISTD_H)
25 #include <unistd.h>
26 #endif
27
28 #if defined(_MSC_VER)
29 #include <intrin.h>
30 #endif
31
32 gboolean mono_hwcap_x86_is_xen = FALSE;
33 gboolean mono_hwcap_x86_has_cmov = FALSE;
34 gboolean mono_hwcap_x86_has_fcmov = FALSE;
35 gboolean mono_hwcap_x86_has_sse1 = FALSE;
36 gboolean mono_hwcap_x86_has_sse2 = FALSE;
37 gboolean mono_hwcap_x86_has_sse3 = FALSE;
38 gboolean mono_hwcap_x86_has_ssse3 = FALSE;
39 gboolean mono_hwcap_x86_has_sse41 = FALSE;
40 gboolean mono_hwcap_x86_has_sse42 = FALSE;
41 gboolean mono_hwcap_x86_has_sse4a = FALSE;
42
43 static gboolean
44 cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
45 {
46 #if defined(_MSC_VER)
47         int info [4];
48 #endif
49
50         /* First, make sure we can use cpuid if we're on 32-bit. */
51 #if defined(TARGET_X86)
52         gboolean have_cpuid = FALSE;
53
54 #if defined(_MSC_VER)
55         __asm {
56                 pushfd
57                 pop eax
58                 mov edx, eax
59                 xor eax, 0x200000
60                 push eax
61                 popfd
62                 pushfd
63                 pop eax
64                 xor eax, edx
65                 and eax, 0x200000
66                 mov have_cpuid, eax
67         }
68 #else
69         __asm__ __volatile__ (
70                 "pushfl\n\t"
71                 "popl\t%%eax\n\t"
72                 "movl\t%%eax, %%edx\n\t"
73                 "xorl\t$0x200000, %%eax\n\t"
74                 "pushl\t%%eax\n\t"
75                 "popfl\n\t"
76                 "pushfl\n\t"
77                 "popl\t%%eax\n\t"
78                 "xorl\t%%edx, %%eax\n\t"
79                 "andl\t$0x200000, %%eax\n\t"
80                 "movl\t%%eax, %0\n\t"
81                 : "=r" (have_cpuid)
82                 :
83                 : "%eax", "%edx"
84         );
85 #endif
86
87         if (!have_cpuid)
88                 return FALSE;
89 #endif
90
91         /* Now issue the actual cpuid instruction. We can use
92            MSVC's __cpuid on both 32-bit and 64-bit. */
93 #if defined(_MSC_VER)
94         __cpuid (info, id);
95         *p_eax = info [0];
96         *p_ebx = info [1];
97         *p_ecx = info [2];
98         *p_edx = info [3];
99 #elif defined(TARGET_X86)
100         /* This complicated stuff is necessary because EBX
101            may be used by the compiler in PIC mode. */
102         __asm__ __volatile__ (
103                 "xchgl\t%%ebx, %k1\n\t"
104                 "cpuid\n\t"
105                 "xchgl\t%%ebx, %k1\n\t"
106                 : "=a" (*p_eax), "=&r" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
107                 : "0" (id)
108         );
109 #else
110         __asm__ __volatile__ (
111                 "cpuid\n\t"
112                 : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
113                 : "a" (id)
114         );
115 #endif
116
117         return TRUE;
118 }
119
120 void
121 mono_hwcap_arch_init (void)
122 {
123         int eax, ebx, ecx, edx;
124
125         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
126                 if (edx & (1 << 15)) {
127                         mono_hwcap_x86_has_cmov = TRUE;
128
129                         if (edx & 1)
130                                 mono_hwcap_x86_has_fcmov = TRUE;
131                 }
132
133                 if (edx & (1 << 25))
134                         mono_hwcap_x86_has_sse1 = TRUE;
135
136                 if (edx & (1 << 26))
137                         mono_hwcap_x86_has_sse2 = TRUE;
138
139                 if (ecx & (1 << 0))
140                         mono_hwcap_x86_has_sse3 = TRUE;
141
142                 if (ecx & (1 << 9))
143                         mono_hwcap_x86_has_ssse3 = TRUE;
144
145                 if (ecx & (1 << 19))
146                         mono_hwcap_x86_has_sse41 = TRUE;
147
148                 if (ecx & (1 << 20))
149                         mono_hwcap_x86_has_sse42 = TRUE;
150         }
151
152         if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
153                 if ((unsigned int) eax >= 0x80000001 && ebx == 0x68747541 && ecx == 0x444D4163 && edx == 0x69746E65) {
154                         if (cpuid (0x80000001, &eax, &ebx, &ecx, &edx)) {
155                                 if (ecx & (1 << 6))
156                                         mono_hwcap_x86_has_sse4a = TRUE;
157                         }
158                 }
159         }
160
161 #if defined(HAVE_UNISTD_H)
162         mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
163 #endif
164 }
165
166 void
167 mono_hwcap_print (FILE *f)
168 {
169         g_fprintf (f, "mono_hwcap_x86_is_xen = %i\n", mono_hwcap_x86_is_xen);
170         g_fprintf (f, "mono_hwcap_x86_has_cmov = %i\n", mono_hwcap_x86_has_cmov);
171         g_fprintf (f, "mono_hwcap_x86_has_fcmov = %i\n", mono_hwcap_x86_has_fcmov);
172         g_fprintf (f, "mono_hwcap_x86_has_sse1 = %i\n", mono_hwcap_x86_has_sse1);
173         g_fprintf (f, "mono_hwcap_x86_has_sse2 = %i\n", mono_hwcap_x86_has_sse2);
174         g_fprintf (f, "mono_hwcap_x86_has_sse3 = %i\n", mono_hwcap_x86_has_sse3);
175         g_fprintf (f, "mono_hwcap_x86_has_ssse3 = %i\n", mono_hwcap_x86_has_ssse3);
176         g_fprintf (f, "mono_hwcap_x86_has_sse41 = %i\n", mono_hwcap_x86_has_sse41);
177         g_fprintf (f, "mono_hwcap_x86_has_sse42 = %i\n", mono_hwcap_x86_has_sse42);
178         g_fprintf (f, "mono_hwcap_x86_has_sse4a = %i\n", mono_hwcap_x86_has_sse4a);
179 }