mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
X86CpuInfo::callCpuId() - added support for VS2008 and lesser.
This commit is contained in:
@@ -99,15 +99,19 @@ union X86XCR {
|
||||
|
||||
// callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here.
|
||||
#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)
|
||||
// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler.
|
||||
// ASMJIT_ARCH_X64 is here only for readibility, only VS2005 can compile 64-bit code.
|
||||
# if _MSC_VER >= 1400 || defined(ASMJIT_ARCH_X64)
|
||||
// Done by intrinsics.
|
||||
// __cpuidex was introduced by VS2008-SP1.
|
||||
# if _MSC_FULL_VER >= 150030729
|
||||
__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_ecx = inEcx;
|
||||
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 + 12], edx
|
||||
}
|
||||
# endif // _MSC_VER < 1400
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
// 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))
|
||||
# endif
|
||||
__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)
|
||||
|
||||
@@ -197,7 +204,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Get vendor string/id.
|
||||
callCpuId(0x0, 0x0, ®s);
|
||||
callCpuId(®s, 0x0);
|
||||
|
||||
maxBaseId = regs.eax;
|
||||
::memcpy(cpuInfo->_vendorString, ®s.ebx, 4);
|
||||
@@ -217,7 +224,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
|
||||
|
||||
if (maxBaseId >= 0x1) {
|
||||
// Get feature flags in ECX/EDX and family/model in EAX.
|
||||
callCpuId(0x1, 0x0, ®s);
|
||||
callCpuId(®s, 0x1);
|
||||
|
||||
// Fill family and model fields.
|
||||
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.
|
||||
if ((regs.ecx & 0x0C000000U) == 0x0C000000U) {
|
||||
callXGetBV(0, &xcr0);
|
||||
callXGetBV(&xcr0, 0);
|
||||
}
|
||||
|
||||
// Detect AVX+.
|
||||
@@ -290,7 +297,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
|
||||
|
||||
// Detect new features if the processor supports CPUID-07.
|
||||
if (maxBaseId >= 0x7) {
|
||||
callCpuId(0x7, 0x0, ®s);
|
||||
callCpuId(®s, 0x7);
|
||||
|
||||
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureFSGSBase);
|
||||
if (regs.ebx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureBMI);
|
||||
@@ -335,7 +342,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (maxBaseId >= 0xD && maybeMPX) {
|
||||
callCpuId(0xD, 0x0, ®s);
|
||||
callCpuId(®s, 0xD);
|
||||
|
||||
// Both CPUID result and XCR0 has to be enabled to have support for MPX.
|
||||
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
|
||||
// extended IDs.
|
||||
callCpuId(0x80000000, 0x0, ®s);
|
||||
callCpuId(®s, 0x80000000);
|
||||
|
||||
uint32_t maxExtId = IntUtil::iMin<uint32_t>(regs.eax, 0x80000004);
|
||||
uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString);
|
||||
|
||||
for (i = 0x80000001; i <= maxExtId; i++) {
|
||||
callCpuId(i, 0x0, ®s);
|
||||
callCpuId(®s, i);
|
||||
|
||||
switch (i) {
|
||||
case 0x80000001:
|
||||
|
||||
@@ -181,8 +181,16 @@ union X86CpuId {
|
||||
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64)
|
||||
//! CPU utilities available only if the host processor is X86/X64.
|
||||
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`.
|
||||
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.
|
||||
ASMJIT_API static void detect(X86CpuInfo* cpuInfo);
|
||||
|
||||
Reference in New Issue
Block a user