| |
| |
| |
|
|
| #include "common/arch.h" |
| #if CITRA_ARCH(x86_64) |
|
|
| #include <cstring> |
| #include "common/common_types.h" |
| #include "common/x64/cpu_detect.h" |
|
|
| #ifdef _MSC_VER |
| #include <intrin.h> |
| #else |
|
|
| #if defined(__DragonFly__) || defined(__FreeBSD__) |
| |
| #include <sys/types.h> |
| #include <machine/cpufunc.h> |
| |
| #endif |
|
|
| static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { |
| #if defined(__DragonFly__) || defined(__FreeBSD__) |
| |
| cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info); |
| #else |
| info[0] = function_id; |
| info[2] = subfunction_id; |
| __asm__("cpuid" |
| : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) |
| : "a"(function_id), "c"(subfunction_id)); |
| #endif |
| } |
|
|
| static inline void __cpuid(int info[4], int function_id) { |
| return __cpuidex(info, function_id, 0); |
| } |
|
|
| #define _XCR_XFEATURE_ENABLED_MASK 0 |
| static inline u64 _xgetbv(u32 index) { |
| u32 eax, edx; |
| __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); |
| return ((u64)edx << 32) | eax; |
| } |
|
|
| #endif |
|
|
| namespace Common { |
|
|
| |
| static CPUCaps Detect() { |
| CPUCaps caps = {}; |
|
|
| |
| |
|
|
| int cpu_id[4]; |
| std::memset(caps.brand_string, 0, sizeof(caps.brand_string)); |
|
|
| |
| __cpuid(cpu_id, 0x00000000); |
| u32 max_std_fn = cpu_id[0]; |
|
|
| std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(int)); |
| std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(int)); |
| std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(int)); |
|
|
| __cpuid(cpu_id, 0x80000000); |
|
|
| u32 max_ex_fn = cpu_id[0]; |
|
|
| |
| strcpy(caps.cpu_string, caps.brand_string); |
|
|
| |
| if (max_std_fn >= 1) { |
| __cpuid(cpu_id, 0x00000001); |
|
|
| if ((cpu_id[3] >> 25) & 1) |
| caps.sse = true; |
| if ((cpu_id[3] >> 26) & 1) |
| caps.sse2 = true; |
| if ((cpu_id[2]) & 1) |
| caps.sse3 = true; |
| if ((cpu_id[2] >> 9) & 1) |
| caps.ssse3 = true; |
| if ((cpu_id[2] >> 19) & 1) |
| caps.sse4_1 = true; |
| if ((cpu_id[2] >> 20) & 1) |
| caps.sse4_2 = true; |
| if ((cpu_id[2] >> 25) & 1) |
| caps.aes = true; |
|
|
| |
| |
| |
| |
| if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) { |
| if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { |
| caps.avx = true; |
| if ((cpu_id[2] >> 12) & 1) |
| caps.fma = true; |
| } |
| } |
|
|
| if (max_std_fn >= 7) { |
| __cpuidex(cpu_id, 0x00000007, 0x00000000); |
| |
| if ((cpu_id[1] >> 5) & 1) |
| caps.avx2 = caps.avx; |
| if ((cpu_id[1] >> 3) & 1) |
| caps.bmi1 = true; |
| if ((cpu_id[1] >> 8) & 1) |
| caps.bmi2 = true; |
| |
| if ((cpu_id[1] >> 16) & 1 && (cpu_id[1] >> 28) & 1 && (cpu_id[1] >> 31) & 1 && |
| (cpu_id[1] >> 17) & 1 && (cpu_id[1] >> 30) & 1) { |
| caps.avx512 = caps.avx2; |
| } |
| } |
| } |
|
|
| if (max_ex_fn >= 0x80000004) { |
| |
| __cpuid(cpu_id, 0x80000002); |
| std::memcpy(caps.cpu_string, cpu_id, sizeof(cpu_id)); |
| __cpuid(cpu_id, 0x80000003); |
| std::memcpy(caps.cpu_string + 16, cpu_id, sizeof(cpu_id)); |
| __cpuid(cpu_id, 0x80000004); |
| std::memcpy(caps.cpu_string + 32, cpu_id, sizeof(cpu_id)); |
| } |
|
|
| if (max_ex_fn >= 0x80000001) { |
| |
| __cpuid(cpu_id, 0x80000001); |
| if ((cpu_id[2] >> 16) & 1) |
| caps.fma4 = true; |
| } |
|
|
| return caps; |
| } |
|
|
| const CPUCaps& GetCPUCaps() { |
| static CPUCaps caps = Detect(); |
| return caps; |
| } |
|
|
| } |
|
|
| #endif |
|
|