/**
|
* \file
|
* x86 hardware feature detection
|
*
|
* Authors:
|
* Alex Rønne Petersen (alexrp@xamarin.com)
|
* Elijah Taylor (elijahtaylor@google.com)
|
* Miguel de Icaza (miguel@xamarin.com)
|
* Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
|
* Paolo Molaro (lupus@xamarin.com)
|
* Rodrigo Kumpera (kumpera@gmail.com)
|
* Sebastien Pouliot (sebastien@xamarin.com)
|
* Zoltan Varga (vargaz@xamarin.com)
|
*
|
* Copyright 2003 Ximian, Inc.
|
* Copyright 2003-2011 Novell, Inc
|
* Copyright 2006 Broadcom
|
* Copyright 2007-2008 Andreas Faerber
|
* Copyright 2011-2013 Xamarin Inc
|
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
*/
|
|
#include "mono/utils/mono-hwcap.h"
|
|
#if defined(HAVE_UNISTD_H)
|
#include <unistd.h>
|
#endif
|
#if defined(_MSC_VER)
|
#include <intrin.h>
|
#endif
|
|
static gboolean
|
cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
|
{
|
#if defined(_MSC_VER)
|
int info [4];
|
#endif
|
|
/* First, make sure we can use cpuid if we're on 32-bit. */
|
#if defined(TARGET_X86)
|
gboolean have_cpuid = FALSE;
|
|
#if defined(_MSC_VER)
|
__asm {
|
pushfd
|
pop eax
|
mov edx, eax
|
xor eax, 0x200000
|
push eax
|
popfd
|
pushfd
|
pop eax
|
xor eax, edx
|
and eax, 0x200000
|
mov have_cpuid, eax
|
}
|
#else
|
__asm__ __volatile__ (
|
"pushfl\n\t"
|
"popl\t%%eax\n\t"
|
"movl\t%%eax, %%edx\n\t"
|
"xorl\t$0x200000, %%eax\n\t"
|
"pushl\t%%eax\n\t"
|
"popfl\n\t"
|
"pushfl\n\t"
|
"popl\t%%eax\n\t"
|
"xorl\t%%edx, %%eax\n\t"
|
"andl\t$0x200000, %%eax\n\t"
|
"movl\t%%eax, %0\n\t"
|
: "=r" (have_cpuid)
|
:
|
: "%eax", "%edx"
|
);
|
#endif
|
|
if (!have_cpuid)
|
return FALSE;
|
#endif
|
|
/* Now issue the actual cpuid instruction. We can use
|
MSVC's __cpuid on both 32-bit and 64-bit. */
|
#if defined(_MSC_VER)
|
__cpuid (info, id);
|
*p_eax = info [0];
|
*p_ebx = info [1];
|
*p_ecx = info [2];
|
*p_edx = info [3];
|
#elif defined(TARGET_X86)
|
/* This complicated stuff is necessary because EBX
|
may be used by the compiler in PIC mode. */
|
__asm__ __volatile__ (
|
"xchgl\t%%ebx, %k1\n\t"
|
"cpuid\n\t"
|
"xchgl\t%%ebx, %k1\n\t"
|
: "=a" (*p_eax), "=&r" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
|
: "0" (id)
|
);
|
#else
|
__asm__ __volatile__ (
|
"cpuid\n\t"
|
: "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
|
: "a" (id)
|
);
|
#endif
|
|
return TRUE;
|
}
|
|
void
|
mono_hwcap_arch_init (void)
|
{
|
int eax, ebx, ecx, edx;
|
|
if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
|
if (edx & (1 << 15)) {
|
mono_hwcap_x86_has_cmov = TRUE;
|
|
if (edx & 1)
|
mono_hwcap_x86_has_fcmov = TRUE;
|
}
|
|
if (edx & (1 << 25))
|
mono_hwcap_x86_has_sse1 = TRUE;
|
|
if (edx & (1 << 26))
|
mono_hwcap_x86_has_sse2 = TRUE;
|
|
if (ecx & (1 << 0))
|
mono_hwcap_x86_has_sse3 = TRUE;
|
|
if (ecx & (1 << 9))
|
mono_hwcap_x86_has_ssse3 = TRUE;
|
|
if (ecx & (1 << 19))
|
mono_hwcap_x86_has_sse41 = TRUE;
|
|
if (ecx & (1 << 20))
|
mono_hwcap_x86_has_sse42 = TRUE;
|
}
|
|
if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
|
if ((unsigned int) eax >= 0x80000001 && ebx == 0x68747541 && ecx == 0x444D4163 && edx == 0x69746E65) {
|
if (cpuid (0x80000001, &eax, &ebx, &ecx, &edx)) {
|
if (ecx & (1 << 6))
|
mono_hwcap_x86_has_sse4a = TRUE;
|
}
|
}
|
}
|
|
#if defined(HAVE_UNISTD_H) && !defined(NO_HAVE_ACCESS)
|
mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
|
#endif
|
}
|