blob: 34ae7b913af9a26db95c4a816162b9a4ce8613e8 [file] [log] [blame]
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +00001/* cpu_features.c -- Processor features detection.
2 *
Avi Drissmancbb6b982022-09-27 19:16:57 +00003 * Copyright 2018 The Chromium Authors
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the Chromium source repository LICENSE file.
6 */
7
8#include "cpu_features.h"
9#include "zutil.h"
10
11#include <stdint.h>
12#if defined(_MSC_VER)
13#include <intrin.h>
14#elif defined(ADLER32_SIMD_SSSE3)
15#include <cpuid.h>
16#endif
17
18/* TODO(cavalcantii): remove checks for x86_flags on deflate.
19 */
Mark Mentovai8603eee2020-06-28 07:59:33 +000020#if defined(ARMV8_OS_MACOS)
Adenilson Cavalcanti05e137d2022-09-09 18:14:22 +000021/* Crypto extensions (crc32/pmull) are a baseline feature in ARMv8.1-A, and
22 * OSX running on arm64 is new enough that these can be assumed without
23 * runtime detection.
24 */
Mark Mentovai8603eee2020-06-28 07:59:33 +000025int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
Adenilson Cavalcanti05e137d2022-09-09 18:14:22 +000026int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
Mark Mentovai8603eee2020-06-28 07:59:33 +000027#else
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000028int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
Adenilson Cavalcanti0e6b3ca2022-05-23 07:17:30 +000029int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
Adenilson Cavalcanti05e137d2022-09-09 18:14:22 +000030#endif
Noel Gordonf3175582020-04-21 08:30:00 +000031int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000032int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
33int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
Lei A Shib8906192023-04-04 03:45:42 +000034int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0;
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000035
Adenilson Cavalcanti24c07df2024-03-18 19:57:28 +000036int ZLIB_INTERNAL riscv_cpu_enable_rvv = 0;
37int ZLIB_INTERNAL riscv_cpu_enable_vclmul = 0;
38
Richard Townsendc2eb8a72020-02-14 01:15:01 +000039#ifndef CPU_NO_SIMD
40
Adenilson Cavalcanti24c07df2024-03-18 19:57:28 +000041#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
42 defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000043#include <pthread.h>
44#endif
45
46#if defined(ARMV8_OS_ANDROID)
47#include <cpu-features.h>
48#elif defined(ARMV8_OS_LINUX)
49#include <asm/hwcap.h>
50#include <sys/auxv.h>
51#elif defined(ARMV8_OS_FUCHSIA)
52#include <zircon/features.h>
53#include <zircon/syscalls.h>
54#include <zircon/types.h>
Hans Wennborg2a6432e2020-01-24 22:31:29 +000055#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000056#include <windows.h>
Dave Tapuska1206f0d2023-07-11 20:11:07 +000057#elif defined(ARMV8_OS_IOS)
58#include <sys/sysctl.h>
Hans Wennborg2a6432e2020-01-24 22:31:29 +000059#elif !defined(_MSC_VER)
Nico Weber51dd31c2020-01-24 20:43:07 +000060#include <pthread.h>
Hans Wennborg2a6432e2020-01-24 22:31:29 +000061#else
62#error cpu_features.c CPU feature detection in not defined for your platform
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000063#endif
64
Dave Tapuska1206f0d2023-07-11 20:11:07 +000065#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000066static void _cpu_check_features(void);
67#endif
68
Adenilson Cavalcanti24c07df2024-03-18 19:57:28 +000069#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \
70 defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || \
71 defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) || \
72 defined(RISCV_RVV)
Nico Weber89bddfe2020-07-06 23:44:43 +000073#if !defined(ARMV8_OS_MACOS)
74// _cpu_check_features() doesn't need to do anything on mac/arm since all
75// features are known at build time, so don't call it.
76// Do provide cpu_check_features() (with a no-op implementation) so that we
77// don't have to make all callers of it check for mac/arm.
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000078static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
Nico Weber89bddfe2020-07-06 23:44:43 +000079#endif
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000080void ZLIB_INTERNAL cpu_check_features(void)
81{
Nico Weber89bddfe2020-07-06 23:44:43 +000082#if !defined(ARMV8_OS_MACOS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000083 pthread_once(&cpu_check_inited_once, _cpu_check_features);
Nico Weber89bddfe2020-07-06 23:44:43 +000084#endif
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000085}
Hans Wennborg2a6432e2020-01-24 22:31:29 +000086#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000087static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
88static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
89{
90 _cpu_check_features();
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +000091 return TRUE;
92}
93void ZLIB_INTERNAL cpu_check_features(void)
94{
95 InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
96 NULL, NULL);
97}
98#endif
99
100#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
Dave Tapuska1206f0d2023-07-11 20:11:07 +0000101#if !defined(ARMV8_OS_MACOS)
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000102/*
103 * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
104 * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
105 */
106static void _cpu_check_features(void)
107{
108#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
109 uint64_t features = android_getCpuFeatures();
110 arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
111 arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
112#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
113 uint64_t features = android_getCpuFeatures();
114 arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
115 arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
116#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
117 unsigned long features = getauxval(AT_HWCAP);
118 arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
119 arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
120#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
121 /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
122 unsigned long features = getauxval(AT_HWCAP2);
123 arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
124 arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
125#elif defined(ARMV8_OS_FUCHSIA)
126 uint32_t features;
127 zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
128 if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
129 return; /* Report nothing if ASIMD(NEON) is missing */
130 arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
131 arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
132#elif defined(ARMV8_OS_WINDOWS)
133 arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
134 arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
Dave Tapuska1206f0d2023-07-11 20:11:07 +0000135#elif defined(ARMV8_OS_IOS)
136 // Determine what features are supported dynamically. This code is applicable to macOS
137 // as well if we wish to do that dynamically on that platform in the future.
138 // See https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
139 int val = 0;
140 size_t len = sizeof(val);
141 arm_cpu_enable_crc32 = sysctlbyname("hw.optional.armv8_crc32", &val, &len, 0, 0) == 0
142 && val != 0;
143 val = 0;
144 len = sizeof(val);
145 arm_cpu_enable_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &val, &len, 0, 0) == 0
146 && val != 0;
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000147#endif
148}
149#endif
150#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
151/*
152 * iOS@x86 (i.e. emulator) is another special case where we disable
153 * SIMD optimizations.
154 */
155#ifndef CPU_NO_SIMD
156/* On x86 we simply use a instruction to check the CPU features.
157 * (i.e. CPUID).
158 */
Lei A Shib8906192023-04-04 03:45:42 +0000159#ifdef CRC32_SIMD_AVX512_PCLMUL
160#include <immintrin.h>
161#include <xsaveintrin.h>
162#endif
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000163static void _cpu_check_features(void)
164{
165 int x86_cpu_has_sse2;
166 int x86_cpu_has_ssse3;
167 int x86_cpu_has_sse42;
168 int x86_cpu_has_pclmulqdq;
169 int abcd[4];
Noel Gordonf3175582020-04-21 08:30:00 +0000170
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000171#ifdef _MSC_VER
172 __cpuid(abcd, 1);
173#else
174 __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
175#endif
Noel Gordonf3175582020-04-21 08:30:00 +0000176
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000177 x86_cpu_has_sse2 = abcd[3] & 0x4000000;
178 x86_cpu_has_ssse3 = abcd[2] & 0x000200;
179 x86_cpu_has_sse42 = abcd[2] & 0x100000;
180 x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
181
Noel Gordonf3175582020-04-21 08:30:00 +0000182 x86_cpu_enable_sse2 = x86_cpu_has_sse2;
183
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000184 x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
185
186 x86_cpu_enable_simd = x86_cpu_has_sse2 &&
187 x86_cpu_has_sse42 &&
188 x86_cpu_has_pclmulqdq;
Lei A Shib8906192023-04-04 03:45:42 +0000189
190#ifdef CRC32_SIMD_AVX512_PCLMUL
191 x86_cpu_enable_avx512 = _xgetbv(0) & 0x00000040;
192#endif
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000193}
Adenilson Cavalcanti24c07df2024-03-18 19:57:28 +0000194#endif // x86 & NO_SIMD
195
196#elif defined(RISCV_RVV)
197#include <sys/auxv.h>
198
199#ifndef ZLIB_HWCAP_RVV
200#define ZLIB_HWCAP_RVV (1 << ('v' - 'a'))
Adenilson Cavalcanti5de00af2020-01-08 22:12:31 +0000201#endif
Adenilson Cavalcanti24c07df2024-03-18 19:57:28 +0000202
203/* TODO(cavalcantii)
204 * - add support for Android@RISCV i.e. __riscv_hwprobe().
205 * - detect vclmul (crypto extensions).
206 */
207static void _cpu_check_features(void)
208{
209 unsigned long features = getauxval(AT_HWCAP);
210 riscv_cpu_enable_rvv = !!(features & ZLIB_HWCAP_RVV);
211}
212#endif // ARM | x86 | RISCV
213#endif // NO SIMD CPU