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