Fix CPUID to detect AVX512F
CPUID is part of x86_64 ISA to query CPU features. In order to determine AVX512F ISA extension, EAX and ECX needs to be set to 7 and 0 respectively before invoking `cpuid` instruction. This commit also removes inline assembly for __cpuid in favor of using compiler provided intrinsic functions. Both GCC and clang provides __cpuid like function via __cpuid_count intrinsic. This commit also creates a portable wrapper over compiler intrinsic functions, __cpuid and __cpuidex. `cpuid' provides base level ISA query and `cpuidex` provides extra extension information like AVX512F. These wrappers lean towards MSVC like API. References: CPUID Docs: https://en.wikipedia.org/wiki/CPUID GCC's ``docs" on __cpuid_count: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/i386/cpuid.h Clang's docs on __cpuid_count: https://clang.llvm.org/doxygen/cpuid_8h.html MSVC's docs on __cpuid and __cpuidex: https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
This commit is contained in:
parent
445e5162fd
commit
bb31125c94
@ -27,16 +27,20 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARM_NEON_SUPPORT
|
||||
/* Needed for ARM NEON detection */
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <intrin.h>
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#include <cpuid.h>
|
||||
#else
|
||||
#error "Unsupported compiler: need __cpuid and __cpuidex for CPU detection"
|
||||
#endif
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/fpu.h"
|
||||
#include "pbd/error.h"
|
||||
@ -49,35 +53,30 @@ using namespace std;
|
||||
FPU* FPU::_instance (0);
|
||||
|
||||
#if ( (defined __x86_64__) || (defined __i386__) || (defined _M_X64) || (defined _M_IX86) ) // ARCH_X86
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
|
||||
/* use __cpuid() as the name to match the MSVC/mingw intrinsic */
|
||||
|
||||
static void
|
||||
__cpuid(int regs[4], int cpuid_leaf)
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
/* Use MSVC/mingw intrinsic to get CPUID */
|
||||
static void cpuid(int reg[4], int cpuid_leaf)
|
||||
{
|
||||
asm volatile (
|
||||
#if defined(__i386__)
|
||||
"pushl %%ebx;\n\t"
|
||||
#endif
|
||||
"cpuid;\n\t"
|
||||
"movl %%eax, (%1);\n\t"
|
||||
"movl %%ebx, 4(%1);\n\t"
|
||||
"movl %%ecx, 8(%1);\n\t"
|
||||
"movl %%edx, 12(%1);\n\t"
|
||||
#if defined(__i386__)
|
||||
"popl %%ebx;\n\t"
|
||||
#endif
|
||||
:"=a" (cpuid_leaf) /* %eax clobbered by CPUID */
|
||||
:"S" (regs), "a" (cpuid_leaf)
|
||||
:
|
||||
#if !defined(__i386__)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%ecx", "%edx", "memory");
|
||||
__cpuid(reg, cpuid_leaf);
|
||||
}
|
||||
|
||||
#endif /* !PLATFORM_WINDOWS */
|
||||
/* Get extended features of CPUID */
|
||||
static void cpuidex(int reg[4], int cpuid_leaf, int cpuid_level)
|
||||
{
|
||||
__cpuidex(reg, cpuid_leaf, cpuid_level);
|
||||
}
|
||||
#else
|
||||
/* use __cpuid() with the same API to match the MSVC/mingw intrinsic */
|
||||
static void cpuid(int reg[4], int cpuid_leaf)
|
||||
{
|
||||
__cpuid_count(cpuid_leaf, 0, reg[0], reg[1], reg[2], reg[3]);
|
||||
}
|
||||
/* Get extended features of CPUID */
|
||||
static void cpuidex(int reg[4], int cpuid_leaf, int cpuid_level)
|
||||
{
|
||||
__cpuid_count(cpuid_leaf, cpuid_level, reg[0], reg[1], reg[2], reg[3]);
|
||||
}
|
||||
#endif // PLATFORM_WINDOWS
|
||||
|
||||
#ifndef HAVE_XGETBV // Allow definition by build system
|
||||
#if defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 5
|
||||
@ -192,7 +191,7 @@ FPU::FPU ()
|
||||
char cpu_string[48];
|
||||
string cpu_vendor;
|
||||
|
||||
__cpuid (cpu_info, 0);
|
||||
cpuid(cpu_info, 0);
|
||||
|
||||
int num_ids = cpu_info[0];
|
||||
std::swap(cpu_info[2], cpu_info[3]);
|
||||
@ -203,9 +202,13 @@ FPU::FPU ()
|
||||
|
||||
if (num_ids > 0) {
|
||||
|
||||
/* Now get CPU/FPU flags */
|
||||
int cpu_info_ex[4];
|
||||
|
||||
__cpuid (cpu_info, 1);
|
||||
/* Now get CPU/FPU flags */
|
||||
cpuid(cpu_info, 1);
|
||||
|
||||
/* Get CPU extended features: Like AVX512F */
|
||||
cpuidex(cpu_info_ex, 7, 0);
|
||||
|
||||
if ((cpu_info[2] & (1<<27)) /* OSXSAVE */ &&
|
||||
(cpu_info[2] & (1<<28) /* AVX */) &&
|
||||
@ -219,7 +222,7 @@ FPU::FPU ()
|
||||
_flags = Flags (_flags | (HasFMA));
|
||||
}
|
||||
|
||||
if (cpu_info[2] & (1<<16) /* AVX512F */) {
|
||||
if (cpu_info_ex[1] & (1<<16) /* AVX512F */) {
|
||||
info << _("AVX512F capable processor") << endmsg;
|
||||
_flags = Flags (_flags | (HasAVX512F));
|
||||
}
|
||||
@ -317,8 +320,7 @@ FPU::FPU ()
|
||||
}
|
||||
|
||||
/* finally get the CPU brand */
|
||||
|
||||
__cpuid (cpu_info, 0x80000000);
|
||||
cpuid(cpu_info, 0x80000000);
|
||||
|
||||
const int parameter_end = 0x80000004;
|
||||
string cpu_brand;
|
||||
@ -328,7 +330,7 @@ FPU::FPU ()
|
||||
|
||||
for (int parameter = 0x80000002; parameter <= parameter_end &&
|
||||
cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) {
|
||||
__cpuid(cpu_info, parameter);
|
||||
cpuid(cpu_info, parameter);
|
||||
memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info));
|
||||
cpu_string_ptr += sizeof(cpu_info);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user