Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / utils / mono-hwcap-x86.c
1 /**
2  * \file
3  * x86 hardware feature detection
4  *
5  * Authors:
6  *    Alex Rønne Petersen (alexrp@xamarin.com)
7  *    Elijah Taylor (elijahtaylor@google.com)
8  *    Miguel de Icaza (miguel@xamarin.com)
9  *    Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
10  *    Paolo Molaro (lupus@xamarin.com)
11  *    Rodrigo Kumpera (kumpera@gmail.com)
12  *    Sebastien Pouliot (sebastien@xamarin.com)
13  *    Zoltan Varga (vargaz@xamarin.com)
14  *
15  * Copyright 2003 Ximian, Inc.
16  * Copyright 2003-2011 Novell, Inc
17  * Copyright 2006 Broadcom
18  * Copyright 2007-2008 Andreas Faerber
19  * Copyright 2011-2013 Xamarin Inc
20  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21  */
22
23 #include "mono/utils/mono-hwcap.h"
24
25 #if defined(HAVE_UNISTD_H)
26 #include <unistd.h>
27 #endif
28 #if defined(_MSC_VER)
29 #include <intrin.h>
30 #endif
31
32 static gboolean
33 cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
34 {
35 #if defined(_MSC_VER)
36         int info [4];
37 #endif
38
39         /* First, make sure we can use cpuid if we're on 32-bit. */
40 #if defined(TARGET_X86)
41         gboolean have_cpuid = FALSE;
42
43 #if defined(_MSC_VER)
44         __asm {
45                 pushfd
46                 pop eax
47                 mov edx, eax
48                 xor eax, 0x200000
49                 push eax
50                 popfd
51                 pushfd
52                 pop eax
53                 xor eax, edx
54                 and eax, 0x200000
55                 mov have_cpuid, eax
56         }
57 #else
58         __asm__ __volatile__ (
59                 "pushfl\n\t"
60                 "popl\t%%eax\n\t"
61                 "movl\t%%eax, %%edx\n\t"
62                 "xorl\t$0x200000, %%eax\n\t"
63                 "pushl\t%%eax\n\t"
64                 "popfl\n\t"
65                 "pushfl\n\t"
66                 "popl\t%%eax\n\t"
67                 "xorl\t%%edx, %%eax\n\t"
68                 "andl\t$0x200000, %%eax\n\t"
69                 "movl\t%%eax, %0\n\t"
70                 : "=r" (have_cpuid)
71                 :
72                 : "%eax", "%edx"
73         );
74 #endif
75
76         if (!have_cpuid)
77                 return FALSE;
78 #endif
79
80         /* Now issue the actual cpuid instruction. We can use
81            MSVC's __cpuid on both 32-bit and 64-bit. */
82 #if defined(_MSC_VER)
83         __cpuid (info, id);
84         *p_eax = info [0];
85         *p_ebx = info [1];
86         *p_ecx = info [2];
87         *p_edx = info [3];
88 #elif defined(TARGET_X86)
89         /* This complicated stuff is necessary because EBX
90            may be used by the compiler in PIC mode. */
91         __asm__ __volatile__ (
92                 "xchgl\t%%ebx, %k1\n\t"
93                 "cpuid\n\t"
94                 "xchgl\t%%ebx, %k1\n\t"
95                 : "=a" (*p_eax), "=&r" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
96                 : "0" (id)
97         );
98 #else
99         __asm__ __volatile__ (
100                 "cpuid\n\t"
101                 : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
102                 : "a" (id)
103         );
104 #endif
105
106         return TRUE;
107 }
108
109 void
110 mono_hwcap_arch_init (void)
111 {
112         int eax, ebx, ecx, edx;
113
114         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
115                 if (edx & (1 << 15)) {
116                         mono_hwcap_x86_has_cmov = TRUE;
117
118                         if (edx & 1)
119                                 mono_hwcap_x86_has_fcmov = TRUE;
120                 }
121
122                 if (edx & (1 << 25))
123                         mono_hwcap_x86_has_sse1 = TRUE;
124
125                 if (edx & (1 << 26))
126                         mono_hwcap_x86_has_sse2 = TRUE;
127
128                 if (ecx & (1 << 0))
129                         mono_hwcap_x86_has_sse3 = TRUE;
130
131                 if (ecx & (1 << 9))
132                         mono_hwcap_x86_has_ssse3 = TRUE;
133
134                 if (ecx & (1 << 19))
135                         mono_hwcap_x86_has_sse41 = TRUE;
136
137                 if (ecx & (1 << 20))
138                         mono_hwcap_x86_has_sse42 = TRUE;
139         }
140
141         if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
142                 if ((unsigned int) eax >= 0x80000001 && ebx == 0x68747541 && ecx == 0x444D4163 && edx == 0x69746E65) {
143                         if (cpuid (0x80000001, &eax, &ebx, &ecx, &edx)) {
144                                 if (ecx & (1 << 6))
145                                         mono_hwcap_x86_has_sse4a = TRUE;
146                         }
147                 }
148         }
149
150 #if defined(HAVE_UNISTD_H)
151         mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
152 #endif
153 }