1 /* cpu_features.c -- Processor features detection.
2 *
3 * Copyright 2018 The Chromium Authors. All rights reserved.
4 * 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 */
20 int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
21 int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
22 int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
23 int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
24
25 #if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
26 #include <pthread.h>
27 #endif
28
29 #if defined(ARMV8_OS_ANDROID)
30 #include <cpu-features.h>
31 #elif defined(ARMV8_OS_LINUX)
32 #include <asm/hwcap.h>
33 #include <sys/auxv.h>
34 #elif defined(ARMV8_OS_FUCHSIA)
35 #include <zircon/features.h>
36 #include <zircon/syscalls.h>
37 #include <zircon/types.h>
38 #elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
39 #include <windows.h>
40 #elif !defined(_MSC_VER)
41 #include <pthread.h>
42 #else
43 #error cpu_features.c CPU feature detection in not defined for your platform
44 #endif
45
46 #if !defined(CPU_NO_SIMD) && !defined(ARM_OS_IOS)
47 static void _cpu_check_features(void);
48 #endif
49
50 #if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS)
51 static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
cpu_check_features(void)52 void ZLIB_INTERNAL cpu_check_features(void)
53 {
54 pthread_once(&cpu_check_inited_once, _cpu_check_features);
55 }
56 #elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
57 static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
_cpu_check_features_forwarder(PINIT_ONCE once,PVOID param,PVOID * context)58 static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
59 {
60 _cpu_check_features();
61 return TRUE;
62 }
cpu_check_features(void)63 void ZLIB_INTERNAL cpu_check_features(void)
64 {
65 InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
66 NULL, NULL);
67 }
68 #endif
69
70 #if (defined(__ARM_NEON__) || defined(__ARM_NEON))
71 /*
72 * iOS@ARM is a special case where we always have NEON but don't check
73 * for crypto extensions.
74 */
75 #ifndef ARM_OS_IOS
76 /*
77 * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
78 * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
79 */
_cpu_check_features(void)80 static void _cpu_check_features(void)
81 {
82 #if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
83 uint64_t features = android_getCpuFeatures();
84 arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
85 arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
86 #elif defined(ARMV8_OS_ANDROID) /* aarch32 */
87 uint64_t features = android_getCpuFeatures();
88 arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
89 arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
90 #elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
91 unsigned long features = getauxval(AT_HWCAP);
92 arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
93 arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
94 #elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
95 /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
96 unsigned long features = getauxval(AT_HWCAP2);
97 arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
98 arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
99 #elif defined(ARMV8_OS_FUCHSIA)
100 uint32_t features;
101 zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
102 if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
103 return; /* Report nothing if ASIMD(NEON) is missing */
104 arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
105 arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
106 #elif defined(ARMV8_OS_WINDOWS)
107 arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
108 arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
109 #endif
110 }
111 #endif
112 #elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
113 /*
114 * iOS@x86 (i.e. emulator) is another special case where we disable
115 * SIMD optimizations.
116 */
117 #ifndef CPU_NO_SIMD
118 /* On x86 we simply use a instruction to check the CPU features.
119 * (i.e. CPUID).
120 */
_cpu_check_features(void)121 static void _cpu_check_features(void)
122 {
123 int x86_cpu_has_sse2;
124 int x86_cpu_has_ssse3;
125 int x86_cpu_has_sse42;
126 int x86_cpu_has_pclmulqdq;
127 int abcd[4];
128 #ifdef _MSC_VER
129 __cpuid(abcd, 1);
130 #else
131 __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
132 #endif
133 x86_cpu_has_sse2 = abcd[3] & 0x4000000;
134 x86_cpu_has_ssse3 = abcd[2] & 0x000200;
135 x86_cpu_has_sse42 = abcd[2] & 0x100000;
136 x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
137
138 x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
139
140 x86_cpu_enable_simd = x86_cpu_has_sse2 &&
141 x86_cpu_has_sse42 &&
142 x86_cpu_has_pclmulqdq;
143 }
144 #endif
145 #endif
146