#include "cpu_features.h"
#include "zutil.h"
#include <stdint.h>
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(ADLER32_SIMD_SSSE3)
#include <cpuid.h>
#endif
#if defined(ARMV8_OS_MACOS)
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
#else
int ZLIB_INTERNAL arm_cpu_enable_crc32 = …;
int ZLIB_INTERNAL arm_cpu_enable_pmull = …;
#endif
int ZLIB_INTERNAL x86_cpu_enable_sse2 = …;
int ZLIB_INTERNAL x86_cpu_enable_ssse3 = …;
int ZLIB_INTERNAL x86_cpu_enable_simd = …;
int ZLIB_INTERNAL x86_cpu_enable_avx512 = …;
int ZLIB_INTERNAL riscv_cpu_enable_rvv = …;
int ZLIB_INTERNAL riscv_cpu_enable_vclmul = …;
#ifndef CPU_NO_SIMD
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS)
#include <pthread.h>
#endif
#if defined(ARMV8_OS_ANDROID)
#include <cpu-features.h>
#elif defined(ARMV8_OS_LINUX)
#include <asm/hwcap.h>
#include <sys/auxv.h>
#elif defined(ARMV8_OS_FUCHSIA)
#include <zircon/features.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
#include <windows.h>
#elif defined(ARMV8_OS_IOS)
#include <sys/sysctl.h>
#elif !defined(_MSC_VER)
#include <pthread.h>
#else
#error cpu_features.c CPU feature detection in not defined for your platform
#endif
#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS)
static void _cpu_check_features(void);
#endif
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || \
defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) || \
defined(RISCV_RVV)
#if !defined(ARMV8_OS_MACOS)
static pthread_once_t cpu_check_inited_once = …;
#endif
void ZLIB_INTERNAL cpu_check_features(void)
{ … }
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
{
_cpu_check_features();
return TRUE;
}
void ZLIB_INTERNAL cpu_check_features(void)
{
InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
NULL, NULL);
}
#endif
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
#if !defined(ARMV8_OS_MACOS)
static void _cpu_check_features(void)
{
#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
uint64_t features = android_getCpuFeatures();
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
#elif defined(ARMV8_OS_ANDROID)
uint64_t features = android_getCpuFeatures();
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
unsigned long features = getauxval(AT_HWCAP);
arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
unsigned long features = getauxval(AT_HWCAP2);
arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
#elif defined(ARMV8_OS_FUCHSIA)
uint32_t features;
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
return;
arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
#elif defined(ARMV8_OS_WINDOWS)
arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
#elif defined(ARMV8_OS_IOS)
int val = 0;
size_t len = sizeof(val);
arm_cpu_enable_crc32 = sysctlbyname("hw.optional.armv8_crc32", &val, &len, 0, 0) == 0
&& val != 0;
val = 0;
len = sizeof(val);
arm_cpu_enable_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &val, &len, 0, 0) == 0
&& val != 0;
#endif
}
#endif
#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
#ifndef CPU_NO_SIMD
#ifdef CRC32_SIMD_AVX512_PCLMUL
#include <immintrin.h>
#include <xsaveintrin.h>
#endif
static void _cpu_check_features(void)
{ … }
#endif
#elif defined(RISCV_RVV)
#include <sys/auxv.h>
#ifndef ZLIB_HWCAP_RVV
#define ZLIB_HWCAP_RVV …
#endif
static void _cpu_check_features(void)
{
unsigned long features = getauxval(AT_HWCAP);
riscv_cpu_enable_rvv = !!(features & ZLIB_HWCAP_RVV);
}
#endif
#endif