diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel index 36b606f6..b659a7e2 100644 --- a/absl/crc/BUILD.bazel +++ b/absl/crc/BUILD.bazel @@ -42,6 +42,7 @@ cc_library( deps = [ "//absl/base", "//absl/base:config", + "//absl/types:optional", ], ) diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt index d52a1bc4..f068e543 100644 --- a/absl/crc/CMakeLists.txt +++ b/absl/crc/CMakeLists.txt @@ -25,6 +25,7 @@ absl_cc_library( DEPS absl::base absl::config + absl::optional ) # Internal-only target, do not depend on directly. diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc index e27719cf..1dba71ae 100644 --- a/absl/crc/internal/cpu_detect.cc +++ b/absl/crc/internal/cpu_detect.cc @@ -18,12 +18,21 @@ #include #include "absl/base/config.h" +#include "absl/types/optional.h" // IWYU pragma: keep #if defined(__aarch64__) && defined(__linux__) #include #include #endif +#if defined(__aarch64__) && defined(__APPLE__) +#if defined(__has_include) && __has_include() +#include +#endif +#include +#include +#endif + #if defined(_WIN32) || defined(_WIN64) #include #endif @@ -277,6 +286,61 @@ bool SupportsArmCRC32PMULL() { #endif } +#elif defined(__aarch64__) && defined(__APPLE__) + +CpuType GetCpuType() { return CpuType::kUnknown; } + +template +static absl::optional ReadSysctlByName(const char* name) { + T val; + size_t val_size = sizeof(T); + int ret = sysctlbyname(name, &val, &val_size, nullptr, 0); + if (ret == -1) { + return std::nullopt; + } + return val; +} + +bool SupportsArmCRC32PMULL() { +#if ABSL_HAVE_BUILTIN(__builtin_cpu_supports) + // Support for the AES and PMULL instructions are tied together: + // "When Cryptographic extensions are implemented and enabled then AESE, AESD, + // AESMC, and AESIMC instructions are implemented and also PMULL/PMULL2 + // instructions operating on 64-bit data quantities." + // + // __builtin_cpu_supports expects users of PMULL to check for AES. + // + // https://developer.arm.com/documentation/101800/0201/AArch64-registers/AArch64-Identification-register-summary/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0 + return __builtin_cpu_supports("crc+aes"); +#endif + + // Newer XNU kernels support querying all capabilities in a single + // sysctlbyname. +#if defined(CAP_BIT_CRC32) && defined(CAP_BIT_FEAT_PMULL) + static const absl::optional caps = + ReadSysctlByName("hw.optional.arm.caps"); + if (caps.has_value()) { + constexpr uint64_t kCrc32AndPmullCaps = + (uint64_t{1} << CAP_BIT_CRC32) | (uint64_t{1} << CAP_BIT_FEAT_PMULL); + return (*caps & kCrc32AndPmullCaps) == kCrc32AndPmullCaps; + } +#endif + + // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619 + static const absl::optional armv8_crc32 = + ReadSysctlByName("hw.optional.armv8_crc32"); + if (armv8_crc32.value_or(0) == 0) { + return false; + } + // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855 + static const absl::optional feat_pmull = + ReadSysctlByName("hw.optional.arm.FEAT_PMULL"); + if (feat_pmull.value_or(0) == 0) { + return false; + } + return true; +} + #else CpuType GetCpuType() { return CpuType::kUnknown; }