• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2023 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "./vpx_config.h"
12 #include "arm_cpudetect.h"
13 
14 #if defined(__APPLE__)
15 #include <sys/sysctl.h>
16 #endif
17 
18 #if !CONFIG_RUNTIME_CPU_DETECT
19 
arm_get_cpu_caps(void)20 static int arm_get_cpu_caps(void) {
21   // This function should actually be a no-op. There is no way to adjust any of
22   // these because the RTCD tables do not exist: the functions are called
23   // statically.
24   int flags = 0;
25 #if HAVE_NEON
26   flags |= HAS_NEON;
27 #endif  // HAVE_NEON
28   return flags;
29 }
30 
31 #elif defined(__APPLE__)  // end !CONFIG_RUNTIME_CPU_DETECT
32 
33 // sysctlbyname() parameter documentation for instruction set characteristics:
34 // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
have_feature(const char * feature)35 static INLINE int64_t have_feature(const char *feature) {
36   int64_t feature_present = 0;
37   size_t size = sizeof(feature_present);
38   if (sysctlbyname(feature, &feature_present, &size, NULL, 0) != 0) {
39     return 0;
40   }
41   return feature_present;
42 }
43 
arm_get_cpu_caps(void)44 static int arm_get_cpu_caps(void) {
45   int flags = 0;
46 #if HAVE_NEON
47   flags |= HAS_NEON;
48 #endif  // HAVE_NEON
49 #if HAVE_NEON_DOTPROD
50   if (have_feature("hw.optional.arm.FEAT_DotProd")) {
51     flags |= HAS_NEON_DOTPROD;
52   }
53 #endif  // HAVE_NEON_DOTPROD
54 #if HAVE_NEON_I8MM
55   if (have_feature("hw.optional.arm.FEAT_I8MM")) {
56     flags |= HAS_NEON_I8MM;
57   }
58 #endif  // HAVE_NEON_I8MM
59   return flags;
60 }
61 
62 #elif defined(_WIN32)  // end __APPLE__
63 
arm_get_cpu_caps(void)64 static int arm_get_cpu_caps(void) {
65   int flags = 0;
66 // IsProcessorFeaturePresent() parameter documentation:
67 // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent#parameters
68 #if HAVE_NEON
69   flags |= HAS_NEON;  // Neon is mandatory in Armv8.0-A.
70 #endif  // HAVE_NEON
71 #if HAVE_NEON_DOTPROD
72 // Support for PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE was added in Windows SDK
73 // 20348, supported by Windows 11 and Windows Server 2022.
74 #if defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
75   if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {
76     flags |= HAS_NEON_DOTPROD;
77   }
78 #endif  // defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
79 #endif  // HAVE_NEON_DOTPROD
80   // No I8MM or SVE feature detection available on Windows at time of writing.
81   return flags;
82 }
83 
84 #elif defined(ANDROID_USE_CPU_FEATURES_LIB)
85 
arm_get_cpu_caps(void)86 static int arm_get_cpu_caps(void) {
87   int flags = 0;
88 #if HAVE_NEON
89   flags |= HAS_NEON;  // Neon is mandatory in Armv8.0-A.
90 #endif  // HAVE_NEON
91   return flags;
92 }
93 
94 #elif defined(__linux__)  // end defined(VPX_USE_ANDROID_CPU_FEATURES)
95 
96 #include <sys/auxv.h>
97 
98 // Define hwcap values ourselves: building with an old auxv header where these
99 // hwcap values are not defined should not prevent features from being enabled.
100 #define VPX_AARCH64_HWCAP_ASIMDDP (1 << 20)
101 #define VPX_AARCH64_HWCAP_SVE (1 << 22)
102 #define VPX_AARCH64_HWCAP2_I8MM (1 << 13)
103 
arm_get_cpu_caps(void)104 static int arm_get_cpu_caps(void) {
105   int flags = 0;
106   unsigned long hwcap = getauxval(AT_HWCAP);
107 #if HAVE_NEON_I8MM
108   unsigned long hwcap2 = getauxval(AT_HWCAP2);
109 #endif  // HAVE_NEON_I8MM
110 #if HAVE_NEON
111   flags |= HAS_NEON;  // Neon is mandatory in Armv8.0-A.
112 #endif  // HAVE_NEON
113 #if HAVE_NEON_DOTPROD
114   if (hwcap & VPX_AARCH64_HWCAP_ASIMDDP) {
115     flags |= HAS_NEON_DOTPROD;
116   }
117 #endif  // HAVE_NEON_DOTPROD
118 #if HAVE_NEON_I8MM
119   if (hwcap2 & VPX_AARCH64_HWCAP2_I8MM) {
120     flags |= HAS_NEON_I8MM;
121   }
122 #endif  // HAVE_NEON_I8MM
123 #if HAVE_SVE
124   if (hwcap & VPX_AARCH64_HWCAP_SVE) {
125     flags |= HAS_SVE;
126   }
127 #endif  // HAVE_SVE
128   return flags;
129 }
130 
131 #elif defined(__Fuchsia__)  // end __linux__
132 
133 #include <zircon/features.h>
134 #include <zircon/syscalls.h>
135 
136 // Added in https://fuchsia-review.googlesource.com/c/fuchsia/+/894282.
137 #ifndef ZX_ARM64_FEATURE_ISA_I8MM
138 #define ZX_ARM64_FEATURE_ISA_I8MM ((uint32_t)(1u << 19))
139 #endif
140 // Added in https://fuchsia-review.googlesource.com/c/fuchsia/+/895083.
141 #ifndef ZX_ARM64_FEATURE_ISA_SVE
142 #define ZX_ARM64_FEATURE_ISA_SVE ((uint32_t)(1u << 20))
143 #endif
144 
arm_get_cpu_caps(void)145 static int arm_get_cpu_caps(void) {
146   int flags = 0;
147 #if HAVE_NEON
148   flags |= HAS_NEON;  // Neon is mandatory in Armv8.0-A.
149 #endif  // HAVE_NEON
150   uint32_t features;
151   zx_status_t status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
152   if (status != ZX_OK) {
153     return flags;
154   }
155 #if HAVE_NEON_DOTPROD
156   if (features & ZX_ARM64_FEATURE_ISA_DP) {
157     flags |= HAS_NEON_DOTPROD;
158   }
159 #endif  // HAVE_NEON_DOTPROD
160 #if HAVE_NEON_I8MM
161   if (features & ZX_ARM64_FEATURE_ISA_I8MM) {
162     flags |= HAS_NEON_I8MM;
163   }
164 #endif  // HAVE_NEON_I8MM
165 #if HAVE_SVE
166   if (features & ZX_ARM64_FEATURE_ISA_SVE) {
167     flags |= HAS_SVE;
168   }
169 #endif  // HAVE_SVE
170   return flags;
171 }
172 
173 #else  // end __Fuchsia__
174 #error \
175     "Runtime CPU detection selected, but no CPU detection method available" \
176 "for your platform. Rerun configure with --disable-runtime-cpu-detect."
177 #endif
178 
arm_cpu_caps(void)179 int arm_cpu_caps(void) {
180   int flags = 0;
181   if (!arm_cpu_env_flags(&flags)) {
182     flags = arm_get_cpu_caps() & arm_cpu_env_mask();
183   }
184 
185   // Restrict flags: FEAT_I8MM assumes that FEAT_DotProd is available.
186   if (!(flags & HAS_NEON_DOTPROD)) {
187     flags &= ~HAS_NEON_I8MM;
188   }
189 
190   // Restrict flags: FEAT_SVE assumes that FEAT_{DotProd,I8MM} are available.
191   if (!(flags & HAS_NEON_DOTPROD)) {
192     flags &= ~HAS_SVE;
193   }
194   if (!(flags & HAS_NEON_I8MM)) {
195     flags &= ~HAS_SVE;
196   }
197 
198   return flags;
199 }
200