Coverage Report

Created: 2024-05-20 07:14

/src/skia/third_party/externals/zlib/cpu_features.c
Line
Count
Source
1
/* cpu_features.c -- Processor features detection.
2
 *
3
 * Copyright 2018 The Chromium Authors
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
#if defined(ARMV8_OS_MACOS)
21
/* 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
 */
25
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
26
int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
27
#else
28
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
29
int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
30
#endif
31
int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
32
int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
33
int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
34
int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0;
35
36
#ifndef CPU_NO_SIMD
37
38
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS)
39
#include <pthread.h>
40
#endif
41
42
#if defined(ARMV8_OS_ANDROID)
43
#include <cpu-features.h>
44
#elif defined(ARMV8_OS_LINUX)
45
#include <asm/hwcap.h>
46
#include <sys/auxv.h>
47
#elif defined(ARMV8_OS_FUCHSIA)
48
#include <zircon/features.h>
49
#include <zircon/syscalls.h>
50
#include <zircon/types.h>
51
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
52
#include <windows.h>
53
#elif defined(ARMV8_OS_IOS)
54
#include <sys/sysctl.h>
55
#elif !defined(_MSC_VER)
56
#include <pthread.h>
57
#else
58
#error cpu_features.c CPU feature detection in not defined for your platform
59
#endif
60
61
#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS)
62
static void _cpu_check_features(void);
63
#endif
64
65
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS)
66
#if !defined(ARMV8_OS_MACOS)
67
// _cpu_check_features() doesn't need to do anything on mac/arm since all
68
// features are known at build time, so don't call it.
69
// Do provide cpu_check_features() (with a no-op implementation) so that we
70
// don't have to make all callers of it check for mac/arm.
71
static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
72
#endif
73
void ZLIB_INTERNAL cpu_check_features(void)
74
390k
{
75
390k
#if !defined(ARMV8_OS_MACOS)
76
390k
    pthread_once(&cpu_check_inited_once, _cpu_check_features);
77
390k
#endif
78
390k
}
79
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
80
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
81
static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
82
{
83
    _cpu_check_features();
84
    return TRUE;
85
}
86
void ZLIB_INTERNAL cpu_check_features(void)
87
{
88
    InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
89
                        NULL, NULL);
90
}
91
#endif
92
93
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
94
#if !defined(ARMV8_OS_MACOS)
95
/*
96
 * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
97
 * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
98
 */
99
static void _cpu_check_features(void)
100
{
101
#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
102
    uint64_t features = android_getCpuFeatures();
103
    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
104
    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
105
#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
106
    uint64_t features = android_getCpuFeatures();
107
    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
108
    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
109
#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
110
    unsigned long features = getauxval(AT_HWCAP);
111
    arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
112
    arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
113
#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
114
    /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
115
    unsigned long features = getauxval(AT_HWCAP2);
116
    arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
117
    arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
118
#elif defined(ARMV8_OS_FUCHSIA)
119
    uint32_t features;
120
    zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
121
    if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
122
        return;  /* Report nothing if ASIMD(NEON) is missing */
123
    arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
124
    arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
125
#elif defined(ARMV8_OS_WINDOWS)
126
    arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
127
    arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
128
#elif defined(ARMV8_OS_IOS)
129
    // Determine what features are supported dynamically. This code is applicable to macOS
130
    // as well if we wish to do that dynamically on that platform in the future.
131
    // See https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
132
    int val = 0;
133
    size_t len = sizeof(val);
134
    arm_cpu_enable_crc32 = sysctlbyname("hw.optional.armv8_crc32", &val, &len, 0, 0) == 0
135
               && val != 0;
136
    val = 0;
137
    len = sizeof(val);
138
    arm_cpu_enable_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &val, &len, 0, 0) == 0
139
               && val != 0;
140
#endif
141
}
142
#endif
143
#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
144
/*
145
 * iOS@x86 (i.e. emulator) is another special case where we disable
146
 * SIMD optimizations.
147
 */
148
#ifndef CPU_NO_SIMD
149
/* On x86 we simply use a instruction to check the CPU features.
150
 * (i.e. CPUID).
151
 */
152
#ifdef CRC32_SIMD_AVX512_PCLMUL
153
#include <immintrin.h>
154
#include <xsaveintrin.h>
155
#endif
156
static void _cpu_check_features(void)
157
10
{
158
10
    int x86_cpu_has_sse2;
159
10
    int x86_cpu_has_ssse3;
160
10
    int x86_cpu_has_sse42;
161
10
    int x86_cpu_has_pclmulqdq;
162
10
    int abcd[4];
163
164
#ifdef _MSC_VER
165
    __cpuid(abcd, 1);
166
#else
167
10
    __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
168
10
#endif
169
170
10
    x86_cpu_has_sse2 = abcd[3] & 0x4000000;
171
10
    x86_cpu_has_ssse3 = abcd[2] & 0x000200;
172
10
    x86_cpu_has_sse42 = abcd[2] & 0x100000;
173
10
    x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
174
175
10
    x86_cpu_enable_sse2 = x86_cpu_has_sse2;
176
177
10
    x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
178
179
10
    x86_cpu_enable_simd = x86_cpu_has_sse2 &&
180
10
                          x86_cpu_has_sse42 &&
181
10
                          x86_cpu_has_pclmulqdq;
182
183
#ifdef CRC32_SIMD_AVX512_PCLMUL
184
    x86_cpu_enable_avx512 = _xgetbv(0) & 0x00000040;
185
#endif
186
10
}
187
#endif
188
#endif
189
#endif