1#include "../../zutil.h"
2
3#if defined(__linux__)
4# include <sys/auxv.h>
5# ifdef ARM_ASM_HWCAP
6# include <asm/hwcap.h>
7# endif
8#elif defined(__FreeBSD__) && defined(__aarch64__)
9# include <machine/armreg.h>
10# ifndef ID_AA64ISAR0_CRC32_VAL
11# define ID_AA64ISAR0_CRC32_VAL ID_AA64ISAR0_CRC32
12# endif
13#elif defined(__APPLE__)
14# include <sys/sysctl.h>
15#elif defined(_WIN32)
16# include <winapifamily.h>
17#endif
18
19static int arm_has_crc32() {
20#if defined(__linux__) && defined(ARM_AUXV_HAS_CRC32)
21# ifdef HWCAP_CRC32
22 return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0 ? 1 : 0;
23# else
24 return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0 ? 1 : 0;
25# endif
26#elif defined(__FreeBSD__) && defined(__aarch64__)
27 return getenv("QEMU_EMULATING") == NULL
28 && ID_AA64ISAR0_CRC32_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_CRC32_BASE;
29#elif defined(__APPLE__)
30 int hascrc32;
31 size_t size = sizeof(hascrc32);
32 return sysctlbyname("hw.optional.armv8_crc32", &hascrc32, &size, NULL, 0) == 0
33 && hascrc32 == 1;
34#elif defined(ARM_NOCHECK_ACLE)
35 return 1;
36#else
37 return 0;
38#endif
39}
40
41/* AArch64 has neon. */
42#if !defined(__aarch64__) && !defined(_M_ARM64)
43static inline int arm_has_neon() {
44#if defined(__linux__) && defined(ARM_AUXV_HAS_NEON)
45# ifdef HWCAP_ARM_NEON
46 return (getauxval(AT_HWCAP) & HWCAP_ARM_NEON) != 0 ? 1 : 0;
47# else
48 return (getauxval(AT_HWCAP) & HWCAP_NEON) != 0 ? 1 : 0;
49# endif
50#elif defined(__APPLE__)
51 int hasneon;
52 size_t size = sizeof(hasneon);
53 return sysctlbyname("hw.optional.neon", &hasneon, &size, NULL, 0) == 0
54 && hasneon == 1;
55#elif defined(_M_ARM) && defined(WINAPI_FAMILY_PARTITION)
56# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
57 return 1; /* Always supported */
58# endif
59#endif
60
61#if defined(ARM_NOCHECK_NEON)
62 return 1;
63#else
64 return 0;
65#endif
66}
67#endif
68
69Z_INTERNAL int arm_cpu_has_neon;
70Z_INTERNAL int arm_cpu_has_crc32;
71
72void Z_INTERNAL arm_check_features(void) {
73#if defined(__aarch64__) || defined(_M_ARM64)
74 arm_cpu_has_neon = 1; /* always available */
75#else
76 arm_cpu_has_neon = arm_has_neon();
77#endif
78 arm_cpu_has_crc32 = arm_has_crc32();
79}
80