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