X86CpuInfo::callCpuId() - added support for VS2008 and lesser.

This commit is contained in:
kobalicek
2015-01-21 18:59:34 +01:00
parent 8b3a10dc22
commit 6d24372579
2 changed files with 32 additions and 17 deletions

View File

@@ -99,15 +99,19 @@ union X86XCR {
// callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here. // callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here.
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
void X86CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* result) { void X86CpuUtil::_docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* result) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. // __cpuidex was introduced by VS2008-SP1.
// ASMJIT_ARCH_X64 is here only for readibility, only VS2005 can compile 64-bit code. # if _MSC_FULL_VER >= 150030729
# if _MSC_VER >= 1400 || defined(ASMJIT_ARCH_X64)
// Done by intrinsics.
__cpuidex(reinterpret_cast<int*>(result->i), inEax, inEcx); __cpuidex(reinterpret_cast<int*>(result->i), inEax, inEcx);
# else // _MSC_VER < 1400 # elif defined(ASMJIT_ARCH_X64)
// VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However, 64-bit
// calling convention specifies parameter to be passed in ECX/RCX, so we may
// be lucky if compiler doesn't move the register, otherwise the result is
// undefined.
__cpuid(reinterpret_cast<int*>(result->i), inEax);
# else
uint32_t cpuid_eax = inEax; uint32_t cpuid_eax = inEax;
uint32_t cpuid_ecx = inEcx; uint32_t cpuid_ecx = inEcx;
uint32_t* cpuid_out = result->i; uint32_t* cpuid_out = result->i;
@@ -122,7 +126,7 @@ void X86CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* result) {
mov dword ptr[edi + 8], ecx mov dword ptr[edi + 8], ecx
mov dword ptr[edi + 12], edx mov dword ptr[edi + 12], edx
} }
# endif // _MSC_VER < 1400 # endif
#elif defined(__GNUC__) #elif defined(__GNUC__)
// Note, patched to preserve ebx/rbx register which is used by GCC. // Note, patched to preserve ebx/rbx register which is used by GCC.
@@ -144,10 +148,13 @@ void X86CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* result) {
: "a" (inEax), "c" (inEcx)) : "a" (inEax), "c" (inEcx))
# endif # endif
__myCpuId(inEax, inEcx, result->eax, result->ebx, result->ecx, result->edx); __myCpuId(inEax, inEcx, result->eax, result->ebx, result->ecx, result->edx);
#endif // COMPILER
#else
# error "asmjit::X86CpuUtil::_docpuid() unimplemented!"
#endif
} }
static void callXGetBV(uint32_t inEcx, X86XCR* result) { static void callXGetBV(X86XCR* result, uint32_t inEcx) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
@@ -197,7 +204,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Get vendor string/id. // Get vendor string/id.
callCpuId(0x0, 0x0, &regs); callCpuId(&regs, 0x0);
maxBaseId = regs.eax; maxBaseId = regs.eax;
::memcpy(cpuInfo->_vendorString, &regs.ebx, 4); ::memcpy(cpuInfo->_vendorString, &regs.ebx, 4);
@@ -217,7 +224,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
if (maxBaseId >= 0x1) { if (maxBaseId >= 0x1) {
// Get feature flags in ECX/EDX and family/model in EAX. // Get feature flags in ECX/EDX and family/model in EAX.
callCpuId(0x1, 0x0, &regs); callCpuId(&regs, 0x1);
// Fill family and model fields. // Fill family and model fields.
cpuInfo->_family = (regs.eax >> 8) & 0x0F; cpuInfo->_family = (regs.eax >> 8) & 0x0F;
@@ -266,7 +273,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// Get the content of XCR0 if supported by CPU and enabled by OS. // Get the content of XCR0 if supported by CPU and enabled by OS.
if ((regs.ecx & 0x0C000000U) == 0x0C000000U) { if ((regs.ecx & 0x0C000000U) == 0x0C000000U) {
callXGetBV(0, &xcr0); callXGetBV(&xcr0, 0);
} }
// Detect AVX+. // Detect AVX+.
@@ -290,7 +297,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// Detect new features if the processor supports CPUID-07. // Detect new features if the processor supports CPUID-07.
if (maxBaseId >= 0x7) { if (maxBaseId >= 0x7) {
callCpuId(0x7, 0x0, &regs); callCpuId(&regs, 0x7);
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureFSGSBase); if (regs.ebx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureFSGSBase);
if (regs.ebx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureBMI); if (regs.ebx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureBMI);
@@ -335,7 +342,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
if (maxBaseId >= 0xD && maybeMPX) { if (maxBaseId >= 0xD && maybeMPX) {
callCpuId(0xD, 0x0, &regs); callCpuId(&regs, 0xD);
// Both CPUID result and XCR0 has to be enabled to have support for MPX. // Both CPUID result and XCR0 has to be enabled to have support for MPX.
if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U) { if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U) {
@@ -349,13 +356,13 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// Calling cpuid with 0x80000000 as the in argument gets the number of valid // Calling cpuid with 0x80000000 as the in argument gets the number of valid
// extended IDs. // extended IDs.
callCpuId(0x80000000, 0x0, &regs); callCpuId(&regs, 0x80000000);
uint32_t maxExtId = IntUtil::iMin<uint32_t>(regs.eax, 0x80000004); uint32_t maxExtId = IntUtil::iMin<uint32_t>(regs.eax, 0x80000004);
uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString); uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString);
for (i = 0x80000001; i <= maxExtId; i++) { for (i = 0x80000001; i <= maxExtId; i++) {
callCpuId(i, 0x0, &regs); callCpuId(&regs, i);
switch (i) { switch (i) {
case 0x80000001: case 0x80000001:

View File

@@ -181,8 +181,16 @@ union X86CpuId {
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
//! CPU utilities available only if the host processor is X86/X64. //! CPU utilities available only if the host processor is X86/X64.
struct X86CpuUtil { struct X86CpuUtil {
//! \internal
//!
//! Designed to support VS2008 and less in 64-bit mode, even if this compiler
//! doesn't have `__cpuidex` intrinsic.
ASMJIT_API static void _docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* out);
//! Get the result of calling CPUID instruction to `out`. //! Get the result of calling CPUID instruction to `out`.
ASMJIT_API static void callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* out); static ASMJIT_INLINE void callCpuId(X86CpuId* out, uint32_t inEax, uint32_t inEcx = 0) {
return _docpuid(inEcx, inEax, out);
}
//! Detect the Host CPU. //! Detect the Host CPU.
ASMJIT_API static void detect(X86CpuInfo* cpuInfo); ASMJIT_API static void detect(X86CpuInfo* cpuInfo);