| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/crc/internal/cpu_detect.h" |
|
|
| #include <cstdint> |
| #include <string> |
|
|
| #include "absl/base/config.h" |
|
|
| #if defined(__aarch64__) && defined(__linux__) |
| #include <asm/hwcap.h> |
| #include <sys/auxv.h> |
| #endif |
|
|
| #if defined(_WIN32) || defined(_WIN64) |
| #include <intrin.h> |
| #endif |
|
|
| #if defined(__x86_64__) || defined(_M_X64) |
| #if ABSL_HAVE_BUILTIN(__cpuid) |
| |
| |
| extern void __cpuid(int[4], int); |
| #elif !defined(_WIN32) && !defined(_WIN64) |
| |
| |
| static void __cpuid(int cpu_info[4], int info_type) { |
| __asm__ volatile("cpuid \n\t" |
| : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), |
| "=d"(cpu_info[3]) |
| : "a"(info_type), "c"(0)); |
| } |
| #endif |
| #endif |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace crc_internal { |
|
|
| #if defined(__x86_64__) || defined(_M_X64) |
|
|
| namespace { |
|
|
| enum class Vendor { |
| kUnknown, |
| kIntel, |
| kAmd, |
| }; |
|
|
| Vendor GetVendor() { |
| |
| int cpu_info[4]; |
| __cpuid(cpu_info, 0); |
|
|
| std::string vendor; |
| vendor.append(reinterpret_cast<char*>(&cpu_info[1]), 4); |
| vendor.append(reinterpret_cast<char*>(&cpu_info[3]), 4); |
| vendor.append(reinterpret_cast<char*>(&cpu_info[2]), 4); |
| if (vendor == "GenuineIntel") { |
| return Vendor::kIntel; |
| } else if (vendor == "AuthenticAMD") { |
| return Vendor::kAmd; |
| } else { |
| return Vendor::kUnknown; |
| } |
| } |
|
|
| CpuType GetIntelCpuType() { |
| |
| |
| |
| |
| |
| |
| int cpu_info[4]; |
| __cpuid(cpu_info, 1); |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| int family = (cpu_info[0] >> 8) & 0x0f; |
| int model_num = (cpu_info[0] >> 4) & 0x0f; |
| int ext_family = (cpu_info[0] >> 20) & 0xff; |
| int ext_model_num = (cpu_info[0] >> 16) & 0x0f; |
|
|
| int brand_id = cpu_info[1] & 0xff; |
|
|
| |
| if (family == 0x0f) { |
| family += ext_family; |
| } |
|
|
| if (family == 0x0f || family == 0x6) { |
| model_num += (ext_model_num << 4); |
| } |
|
|
| switch (brand_id) { |
| case 0: |
| switch (family) { |
| case 6: |
| switch (model_num) { |
| case 0x2c: |
| return CpuType::kIntelWestmere; |
| case 0x2d: |
| return CpuType::kIntelSandybridge; |
| case 0x3e: |
| return CpuType::kIntelIvybridge; |
| case 0x3c: |
| case 0x3f: |
| return CpuType::kIntelHaswell; |
| case 0x4f: |
| case 0x56: |
| return CpuType::kIntelBroadwell; |
| case 0x55: |
| if ((cpu_info[0] & 0x0f) < 5) { |
| return CpuType::kIntelSkylakeXeon; |
| } else { |
| return CpuType::kIntelCascadelakeXeon; |
| } |
| case 0x5e: |
| return CpuType::kIntelSkylake; |
| default: |
| return CpuType::kUnknown; |
| } |
| default: |
| return CpuType::kUnknown; |
| } |
| default: |
| return CpuType::kUnknown; |
| } |
| } |
|
|
| CpuType GetAmdCpuType() { |
| |
| |
| |
| |
| |
| int cpu_info[4]; |
| __cpuid(cpu_info, 1); |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| int family = (cpu_info[0] >> 8) & 0x0f; |
| int model_num = (cpu_info[0] >> 4) & 0x0f; |
| int ext_family = (cpu_info[0] >> 20) & 0xff; |
| int ext_model_num = (cpu_info[0] >> 16) & 0x0f; |
|
|
| if (family == 0x0f) { |
| family += ext_family; |
| model_num += (ext_model_num << 4); |
| } |
|
|
| switch (family) { |
| case 0x17: |
| switch (model_num) { |
| case 0x0: |
| case 0x1: |
| return CpuType::kAmdNaples; |
| case 0x30: |
| case 0x31: |
| return CpuType::kAmdRome; |
| default: |
| return CpuType::kUnknown; |
| } |
| break; |
| case 0x19: |
| switch (model_num) { |
| case 0x0: |
| case 0x1: |
| return CpuType::kAmdMilan; |
| case 0x10: |
| case 0x11: |
| return CpuType::kAmdGenoa; |
| case 0x44: |
| return CpuType::kAmdRyzenV3000; |
| default: |
| return CpuType::kUnknown; |
| } |
| break; |
| default: |
| return CpuType::kUnknown; |
| } |
| } |
|
|
| } |
|
|
| CpuType GetCpuType() { |
| switch (GetVendor()) { |
| case Vendor::kIntel: |
| return GetIntelCpuType(); |
| case Vendor::kAmd: |
| return GetAmdCpuType(); |
| default: |
| return CpuType::kUnknown; |
| } |
| } |
|
|
| bool SupportsArmCRC32PMULL() { return false; } |
|
|
| #elif defined(__aarch64__) && defined(__linux__) |
|
|
| #ifndef HWCAP_CPUID |
| #define HWCAP_CPUID (1 << 11) |
| #endif |
|
|
| #define ABSL_INTERNAL_AARCH64_ID_REG_READ(id, val) \ |
| asm("mrs %0, " #id : "=r"(val)) |
|
|
| CpuType GetCpuType() { |
| |
| |
| |
| |
| |
| |
| uint64_t hwcaps = getauxval(AT_HWCAP); |
| if (hwcaps & HWCAP_CPUID) { |
| uint64_t midr = 0; |
| ABSL_INTERNAL_AARCH64_ID_REG_READ(MIDR_EL1, midr); |
| uint32_t implementer = (midr >> 24) & 0xff; |
| uint32_t part_number = (midr >> 4) & 0xfff; |
| switch (implementer) { |
| case 0x41: |
| switch (part_number) { |
| case 0xd0c: return CpuType::kArmNeoverseN1; |
| case 0xd40: return CpuType::kArmNeoverseV1; |
| case 0xd49: return CpuType::kArmNeoverseN2; |
| case 0xd4f: return CpuType::kArmNeoverseV2; |
| default: |
| return CpuType::kUnknown; |
| } |
| break; |
| case 0xc0: |
| switch (part_number) { |
| case 0xac3: return CpuType::kAmpereSiryn; |
| default: |
| return CpuType::kUnknown; |
| } |
| break; |
| default: |
| return CpuType::kUnknown; |
| } |
| } |
| return CpuType::kUnknown; |
| } |
|
|
| bool SupportsArmCRC32PMULL() { |
| uint64_t hwcaps = getauxval(AT_HWCAP); |
| return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL); |
| } |
|
|
| #else |
|
|
| CpuType GetCpuType() { return CpuType::kUnknown; } |
|
|
| bool SupportsArmCRC32PMULL() { return false; } |
|
|
| #endif |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|