• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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