xref: /aosp_15_r20/external/zlib/cpu_features.c (revision 86ee64e75fa5f8bce2c8c356138035642429cd05)
1*86ee64e7SAndroid Build Coastguard Worker /* cpu_features.c -- Processor features detection.
2*86ee64e7SAndroid Build Coastguard Worker  *
3*86ee64e7SAndroid Build Coastguard Worker  * Copyright 2018 The Chromium Authors
4*86ee64e7SAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*86ee64e7SAndroid Build Coastguard Worker  * found in the Chromium source repository LICENSE file.
6*86ee64e7SAndroid Build Coastguard Worker  */
7*86ee64e7SAndroid Build Coastguard Worker 
8*86ee64e7SAndroid Build Coastguard Worker #include "cpu_features.h"
9*86ee64e7SAndroid Build Coastguard Worker #include "zutil.h"
10*86ee64e7SAndroid Build Coastguard Worker 
11*86ee64e7SAndroid Build Coastguard Worker #include <stdint.h>
12*86ee64e7SAndroid Build Coastguard Worker #if defined(_MSC_VER)
13*86ee64e7SAndroid Build Coastguard Worker #include <intrin.h>
14*86ee64e7SAndroid Build Coastguard Worker #elif defined(ADLER32_SIMD_SSSE3)
15*86ee64e7SAndroid Build Coastguard Worker #include <cpuid.h>
16*86ee64e7SAndroid Build Coastguard Worker #endif
17*86ee64e7SAndroid Build Coastguard Worker 
18*86ee64e7SAndroid Build Coastguard Worker /* TODO(cavalcantii): remove checks for x86_flags on deflate.
19*86ee64e7SAndroid Build Coastguard Worker  */
20*86ee64e7SAndroid Build Coastguard Worker #if defined(ARMV8_OS_MACOS)
21*86ee64e7SAndroid Build Coastguard Worker /* Crypto extensions (crc32/pmull) are a baseline feature in ARMv8.1-A, and
22*86ee64e7SAndroid Build Coastguard Worker  * OSX running on arm64 is new enough that these can be assumed without
23*86ee64e7SAndroid Build Coastguard Worker  * runtime detection.
24*86ee64e7SAndroid Build Coastguard Worker  */
25*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
26*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
27*86ee64e7SAndroid Build Coastguard Worker #else
28*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
29*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
30*86ee64e7SAndroid Build Coastguard Worker #endif
31*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
32*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
33*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
34*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0;
35*86ee64e7SAndroid Build Coastguard Worker 
36*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL riscv_cpu_enable_rvv = 0;
37*86ee64e7SAndroid Build Coastguard Worker int ZLIB_INTERNAL riscv_cpu_enable_vclmul = 0;
38*86ee64e7SAndroid Build Coastguard Worker 
39*86ee64e7SAndroid Build Coastguard Worker #ifndef CPU_NO_SIMD
40*86ee64e7SAndroid Build Coastguard Worker 
41*86ee64e7SAndroid Build Coastguard Worker #if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
42*86ee64e7SAndroid Build Coastguard Worker     defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS)
43*86ee64e7SAndroid Build Coastguard Worker #include <pthread.h>
44*86ee64e7SAndroid Build Coastguard Worker #endif
45*86ee64e7SAndroid Build Coastguard Worker 
46*86ee64e7SAndroid Build Coastguard Worker #if defined(ARMV8_OS_ANDROID)
47*86ee64e7SAndroid Build Coastguard Worker #include <cpu-features.h>
48*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_LINUX)
49*86ee64e7SAndroid Build Coastguard Worker #include <asm/hwcap.h>
50*86ee64e7SAndroid Build Coastguard Worker #include <sys/auxv.h>
51*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_FUCHSIA)
52*86ee64e7SAndroid Build Coastguard Worker #include <zircon/features.h>
53*86ee64e7SAndroid Build Coastguard Worker #include <zircon/syscalls.h>
54*86ee64e7SAndroid Build Coastguard Worker #include <zircon/types.h>
55*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
56*86ee64e7SAndroid Build Coastguard Worker #include <windows.h>
57*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_IOS)
58*86ee64e7SAndroid Build Coastguard Worker #include <sys/sysctl.h>
59*86ee64e7SAndroid Build Coastguard Worker #elif !defined(_MSC_VER)
60*86ee64e7SAndroid Build Coastguard Worker #include <pthread.h>
61*86ee64e7SAndroid Build Coastguard Worker #else
62*86ee64e7SAndroid Build Coastguard Worker #error cpu_features.c CPU feature detection in not defined for your platform
63*86ee64e7SAndroid Build Coastguard Worker #endif
64*86ee64e7SAndroid Build Coastguard Worker 
65*86ee64e7SAndroid Build Coastguard Worker #if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS)
66*86ee64e7SAndroid Build Coastguard Worker static void _cpu_check_features(void);
67*86ee64e7SAndroid Build Coastguard Worker #endif
68*86ee64e7SAndroid Build Coastguard Worker 
69*86ee64e7SAndroid Build Coastguard Worker #if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
70*86ee64e7SAndroid Build Coastguard Worker     defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || \
71*86ee64e7SAndroid Build Coastguard Worker     defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) || \
72*86ee64e7SAndroid Build Coastguard Worker     defined(RISCV_RVV)
73*86ee64e7SAndroid Build Coastguard Worker #if !defined(ARMV8_OS_MACOS)
74*86ee64e7SAndroid Build Coastguard Worker // _cpu_check_features() doesn't need to do anything on mac/arm since all
75*86ee64e7SAndroid Build Coastguard Worker // features are known at build time, so don't call it.
76*86ee64e7SAndroid Build Coastguard Worker // Do provide cpu_check_features() (with a no-op implementation) so that we
77*86ee64e7SAndroid Build Coastguard Worker // don't have to make all callers of it check for mac/arm.
78*86ee64e7SAndroid Build Coastguard Worker static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
79*86ee64e7SAndroid Build Coastguard Worker #endif
cpu_check_features(void)80*86ee64e7SAndroid Build Coastguard Worker void ZLIB_INTERNAL cpu_check_features(void)
81*86ee64e7SAndroid Build Coastguard Worker {
82*86ee64e7SAndroid Build Coastguard Worker #if !defined(ARMV8_OS_MACOS)
83*86ee64e7SAndroid Build Coastguard Worker     pthread_once(&cpu_check_inited_once, _cpu_check_features);
84*86ee64e7SAndroid Build Coastguard Worker #endif
85*86ee64e7SAndroid Build Coastguard Worker }
86*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
87*86ee64e7SAndroid Build Coastguard Worker static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
_cpu_check_features_forwarder(PINIT_ONCE once,PVOID param,PVOID * context)88*86ee64e7SAndroid Build Coastguard Worker static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
89*86ee64e7SAndroid Build Coastguard Worker {
90*86ee64e7SAndroid Build Coastguard Worker     _cpu_check_features();
91*86ee64e7SAndroid Build Coastguard Worker     return TRUE;
92*86ee64e7SAndroid Build Coastguard Worker }
cpu_check_features(void)93*86ee64e7SAndroid Build Coastguard Worker void ZLIB_INTERNAL cpu_check_features(void)
94*86ee64e7SAndroid Build Coastguard Worker {
95*86ee64e7SAndroid Build Coastguard Worker     InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
96*86ee64e7SAndroid Build Coastguard Worker                         NULL, NULL);
97*86ee64e7SAndroid Build Coastguard Worker }
98*86ee64e7SAndroid Build Coastguard Worker #endif
99*86ee64e7SAndroid Build Coastguard Worker 
100*86ee64e7SAndroid Build Coastguard Worker #if (defined(__ARM_NEON__) || defined(__ARM_NEON))
101*86ee64e7SAndroid Build Coastguard Worker #if !defined(ARMV8_OS_MACOS)
102*86ee64e7SAndroid Build Coastguard Worker /*
103*86ee64e7SAndroid Build Coastguard Worker  * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
104*86ee64e7SAndroid Build Coastguard Worker  * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
105*86ee64e7SAndroid Build Coastguard Worker  */
_cpu_check_features(void)106*86ee64e7SAndroid Build Coastguard Worker static void _cpu_check_features(void)
107*86ee64e7SAndroid Build Coastguard Worker {
108*86ee64e7SAndroid Build Coastguard Worker #if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
109*86ee64e7SAndroid Build Coastguard Worker     uint64_t features = android_getCpuFeatures();
110*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
111*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
112*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_ANDROID) /* aarch32 */
113*86ee64e7SAndroid Build Coastguard Worker     uint64_t features = android_getCpuFeatures();
114*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
115*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
116*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
117*86ee64e7SAndroid Build Coastguard Worker     unsigned long features = getauxval(AT_HWCAP);
118*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
119*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
120*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
121*86ee64e7SAndroid Build Coastguard Worker     /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
122*86ee64e7SAndroid Build Coastguard Worker     unsigned long features = getauxval(AT_HWCAP2);
123*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
124*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
125*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_FUCHSIA)
126*86ee64e7SAndroid Build Coastguard Worker     uint32_t features;
127*86ee64e7SAndroid Build Coastguard Worker     zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
128*86ee64e7SAndroid Build Coastguard Worker     if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
129*86ee64e7SAndroid Build Coastguard Worker         return;  /* Report nothing if ASIMD(NEON) is missing */
130*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
131*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
132*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_WINDOWS)
133*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
134*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
135*86ee64e7SAndroid Build Coastguard Worker #elif defined(ARMV8_OS_IOS)
136*86ee64e7SAndroid Build Coastguard Worker     // Determine what features are supported dynamically. This code is applicable to macOS
137*86ee64e7SAndroid Build Coastguard Worker     // as well if we wish to do that dynamically on that platform in the future.
138*86ee64e7SAndroid Build Coastguard Worker     // See https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
139*86ee64e7SAndroid Build Coastguard Worker     int val = 0;
140*86ee64e7SAndroid Build Coastguard Worker     size_t len = sizeof(val);
141*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_crc32 = sysctlbyname("hw.optional.armv8_crc32", &val, &len, 0, 0) == 0
142*86ee64e7SAndroid Build Coastguard Worker                && val != 0;
143*86ee64e7SAndroid Build Coastguard Worker     val = 0;
144*86ee64e7SAndroid Build Coastguard Worker     len = sizeof(val);
145*86ee64e7SAndroid Build Coastguard Worker     arm_cpu_enable_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &val, &len, 0, 0) == 0
146*86ee64e7SAndroid Build Coastguard Worker                && val != 0;
147*86ee64e7SAndroid Build Coastguard Worker #endif
148*86ee64e7SAndroid Build Coastguard Worker }
149*86ee64e7SAndroid Build Coastguard Worker #endif
150*86ee64e7SAndroid Build Coastguard Worker #elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
151*86ee64e7SAndroid Build Coastguard Worker /*
152*86ee64e7SAndroid Build Coastguard Worker  * iOS@x86 (i.e. emulator) is another special case where we disable
153*86ee64e7SAndroid Build Coastguard Worker  * SIMD optimizations.
154*86ee64e7SAndroid Build Coastguard Worker  */
155*86ee64e7SAndroid Build Coastguard Worker #ifndef CPU_NO_SIMD
156*86ee64e7SAndroid Build Coastguard Worker /* On x86 we simply use a instruction to check the CPU features.
157*86ee64e7SAndroid Build Coastguard Worker  * (i.e. CPUID).
158*86ee64e7SAndroid Build Coastguard Worker  */
159*86ee64e7SAndroid Build Coastguard Worker #ifdef CRC32_SIMD_AVX512_PCLMUL
160*86ee64e7SAndroid Build Coastguard Worker #include <immintrin.h>
161*86ee64e7SAndroid Build Coastguard Worker #include <xsaveintrin.h>
162*86ee64e7SAndroid Build Coastguard Worker #endif
_cpu_check_features(void)163*86ee64e7SAndroid Build Coastguard Worker static void _cpu_check_features(void)
164*86ee64e7SAndroid Build Coastguard Worker {
165*86ee64e7SAndroid Build Coastguard Worker     int x86_cpu_has_sse2;
166*86ee64e7SAndroid Build Coastguard Worker     int x86_cpu_has_ssse3;
167*86ee64e7SAndroid Build Coastguard Worker     int x86_cpu_has_sse42;
168*86ee64e7SAndroid Build Coastguard Worker     int x86_cpu_has_pclmulqdq;
169*86ee64e7SAndroid Build Coastguard Worker     int abcd[4];
170*86ee64e7SAndroid Build Coastguard Worker 
171*86ee64e7SAndroid Build Coastguard Worker #ifdef _MSC_VER
172*86ee64e7SAndroid Build Coastguard Worker     __cpuid(abcd, 1);
173*86ee64e7SAndroid Build Coastguard Worker #else
174*86ee64e7SAndroid Build Coastguard Worker     __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
175*86ee64e7SAndroid Build Coastguard Worker #endif
176*86ee64e7SAndroid Build Coastguard Worker 
177*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_has_sse2 = abcd[3] & 0x4000000;
178*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_has_ssse3 = abcd[2] & 0x000200;
179*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_has_sse42 = abcd[2] & 0x100000;
180*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
181*86ee64e7SAndroid Build Coastguard Worker 
182*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_enable_sse2 = x86_cpu_has_sse2;
183*86ee64e7SAndroid Build Coastguard Worker 
184*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
185*86ee64e7SAndroid Build Coastguard Worker 
186*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_enable_simd = x86_cpu_has_sse2 &&
187*86ee64e7SAndroid Build Coastguard Worker                           x86_cpu_has_sse42 &&
188*86ee64e7SAndroid Build Coastguard Worker                           x86_cpu_has_pclmulqdq;
189*86ee64e7SAndroid Build Coastguard Worker 
190*86ee64e7SAndroid Build Coastguard Worker #ifdef CRC32_SIMD_AVX512_PCLMUL
191*86ee64e7SAndroid Build Coastguard Worker     x86_cpu_enable_avx512 = _xgetbv(0) & 0x00000040;
192*86ee64e7SAndroid Build Coastguard Worker #endif
193*86ee64e7SAndroid Build Coastguard Worker }
194*86ee64e7SAndroid Build Coastguard Worker #endif // x86 & NO_SIMD
195*86ee64e7SAndroid Build Coastguard Worker 
196*86ee64e7SAndroid Build Coastguard Worker #elif defined(RISCV_RVV)
197*86ee64e7SAndroid Build Coastguard Worker #include <sys/auxv.h>
198*86ee64e7SAndroid Build Coastguard Worker 
199*86ee64e7SAndroid Build Coastguard Worker #ifndef ZLIB_HWCAP_RVV
200*86ee64e7SAndroid Build Coastguard Worker #define ZLIB_HWCAP_RVV (1 << ('v' - 'a'))
201*86ee64e7SAndroid Build Coastguard Worker #endif
202*86ee64e7SAndroid Build Coastguard Worker 
203*86ee64e7SAndroid Build Coastguard Worker /* TODO(cavalcantii)
204*86ee64e7SAndroid Build Coastguard Worker  * - add support for Android@RISCV i.e. __riscv_hwprobe().
205*86ee64e7SAndroid Build Coastguard Worker  * - detect vclmul (crypto extensions).
206*86ee64e7SAndroid Build Coastguard Worker  */
_cpu_check_features(void)207*86ee64e7SAndroid Build Coastguard Worker static void _cpu_check_features(void)
208*86ee64e7SAndroid Build Coastguard Worker {
209*86ee64e7SAndroid Build Coastguard Worker   unsigned long features = getauxval(AT_HWCAP);
210*86ee64e7SAndroid Build Coastguard Worker   riscv_cpu_enable_rvv = !!(features & ZLIB_HWCAP_RVV);
211*86ee64e7SAndroid Build Coastguard Worker }
212*86ee64e7SAndroid Build Coastguard Worker #endif // ARM | x86 | RISCV
213*86ee64e7SAndroid Build Coastguard Worker #endif // NO SIMD CPU
214