overte/libraries/shared/src/CPUDetect.h
2017-06-20 16:09:52 -07:00

158 lines
3.6 KiB
C

//
// CPUDetect.h
// libraries/shared/src
//
// Created by Ken Cooke on 6/16/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_CPUDetect_h
#define hifi_CPUDetect_h
//
// Lightweight functions to detect SSE/AVX/AVX2/AVX512 support
//
#define MASK_SSE3 (1 << 0) // SSE3
#define MASK_SSSE3 (1 << 9) // SSSE3
#define MASK_SSE41 (1 << 19) // SSE4.1
#define MASK_SSE42 ((1 << 20) | (1 << 23)) // SSE4.2 and POPCNT
#define MASK_OSXSAVE (1 << 27) // OSXSAVE
#define MASK_AVX ((1 << 27) | (1 << 28)) // OSXSAVE and AVX
#define MASK_AVX2 (1 << 5) // AVX2
#define MASK_AVX512 ((1 << 16) | (1 << 17) | (1 << 28) | (1 << 30) | (1 << 31)) // AVX512 F,DQ,CD,BW,VL (SKX)
#define MASK_XCR0_YMM ((1 << 1) | (1 << 2)) // XMM,YMM
#define MASK_XCR0_ZMM ((1 << 1) | (1 << 2) | (7 << 5)) // XMM,YMM,ZMM
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
#define ARCH_X86
#endif
#if defined(ARCH_X86) && defined(_MSC_VER)
#include <intrin.h>
// use MSVC intrinsics
#define cpuidex(info, eax, ecx) __cpuidex(info, eax, ecx)
#define xgetbv(ecx) _xgetbv(ecx)
#elif defined(ARCH_X86) && defined(__GNUC__)
#include <cpuid.h>
// use GCC intrinics/asm
static inline void cpuidex(int info[4], int eax, int ecx) {
__cpuid_count(eax, ecx, info[0], info[1], info[2], info[3]);
}
static inline unsigned long long xgetbv(unsigned int ecx){
unsigned int eax, edx;
__asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(ecx));
return ((unsigned long long)edx << 32) | eax;
}
#else
static inline void cpuidex(int info[4], int eax, int ecx) {
info[0] = 0;
info[1] = 0;
info[2] = 0;
info[3] = 0;
}
static inline unsigned long long xgetbv(unsigned int ecx){
return 0ULL;
}
#endif
static inline bool cpuSupportsSSE3() {
int info[4];
cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE3) == MASK_SSE3);
}
static inline bool cpuSupportsSSSE3() {
int info[4];
cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSSE3) == MASK_SSSE3);
}
static inline bool cpuSupportsSSE41() {
int info[4];
cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE41) == MASK_SSE41);
}
static inline bool cpuSupportsSSE42() {
int info[4];
cpuidex(info, 0x1, 0);
return ((info[2] & MASK_SSE42) == MASK_SSE42);
}
static inline bool cpuSupportsAVX() {
int info[4];
cpuidex(info, 0x1, 0);
bool result = false;
if ((info[2] & MASK_AVX) == MASK_AVX) {
// verify OS support for YMM state
if ((xgetbv(0) & MASK_XCR0_YMM) == MASK_XCR0_YMM) {
result = true;
}
}
return result;
}
static inline bool cpuSupportsAVX2() {
int info[4];
bool result = false;
if (cpuSupportsAVX()) {
cpuidex(info, 0x7, 0);
if ((info[1] & MASK_AVX2) == MASK_AVX2) {
result = true;
}
}
return result;
}
static inline bool cpuSupportsAVX512() {
int info[4];
cpuidex(info, 0x1, 0);
bool result = false;
if ((info[2] & MASK_OSXSAVE) == MASK_OSXSAVE) {
// verify OS support for ZMM state
if ((xgetbv(0) & MASK_XCR0_ZMM) == MASK_XCR0_ZMM) {
cpuidex(info, 0x7, 0);
if ((info[1] & MASK_AVX512) == MASK_AVX512) {
result = true;
}
}
}
return result;
}
#endif // hifi_CPUDetect_h