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