13
0

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:
Ayan Shafqat 2023-02-08 14:27:24 -05:00 committed by Robin Gareus
parent 445e5162fd
commit bb31125c94
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -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);
}