Skip to content

Commit b7af5e1

Browse files
majnemercopybara-github
authored andcommitted
Random: Support runtime dispatch on AArch64 macOS
This lets us dynamically determine if we should attempt to use HW instructions for AES. PiperOrigin-RevId: 716350656 Change-Id: I1ead17b7b44373850b3591307b7f6d3f9147d5f9
1 parent 3ded0b6 commit b7af5e1

File tree

5 files changed

+81
-20
lines changed

5 files changed

+81
-20
lines changed

absl/random/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ absl_cc_library(
853853
absl::random_internal_platform
854854
absl::random_internal_randen_hwaes_impl
855855
absl::config
856+
absl::optional
856857
)
857858

858859
# Internal-only target, do not depend on directly.

absl/random/internal/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ cc_library(
403403
":platform",
404404
":randen_hwaes_impl",
405405
"//absl/base:config",
406+
"//absl/types:optional",
406407
],
407408
)
408409

absl/random/internal/platform.h

+12-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
// SKIP_ABSL_INLINE_NAMESPACE_CHECK
16+
1517
#ifndef ABSL_RANDOM_INTERNAL_PLATFORM_H_
1618
#define ABSL_RANDOM_INTERNAL_PLATFORM_H_
1719

@@ -134,16 +136,23 @@
134136
// accelerated Randen implementation.
135137
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
136138

137-
#if defined(ABSL_ARCH_X86_64)
139+
// iOS does not support dispatch, even on x86, since applications
140+
// should be bundled as fat binaries, with a different build tailored for
141+
// each specific supported platform/architecture.
142+
#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
143+
(defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR)
144+
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
145+
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
146+
#elif defined(ABSL_ARCH_X86_64)
138147
// Dispatch is available on x86_64
139148
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
140149
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
141150
#elif defined(__linux__) && defined(ABSL_ARCH_PPC)
142151
// Or when running linux PPC
143152
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
144153
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
145-
#elif defined(__linux__) && defined(ABSL_ARCH_AARCH64)
146-
// Or when running linux AArch64
154+
#elif (defined(__linux__) || defined(__APPLE__)) && defined(ABSL_ARCH_AARCH64)
155+
// Or when running linux or macOS AArch64
147156
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
148157
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
149158
#elif defined(__linux__) && defined(ABSL_ARCH_ARM) && (__ARM_ARCH >= 8)
@@ -159,13 +168,4 @@
159168
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
160169
#endif
161170

162-
// iOS does not support dispatch, even on x86, since applications
163-
// should be bundled as fat binaries, with a different build tailored for
164-
// each specific supported platform/architecture.
165-
#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
166-
(defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR)
167-
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
168-
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
169-
#endif
170-
171171
#endif // ABSL_RANDOM_INTERNAL_PLATFORM_H_

absl/random/internal/randen_detect.cc

+66-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,21 @@
1919

2020
#include "absl/random/internal/randen_detect.h"
2121

22+
#if defined(__APPLE__) && defined(__aarch64__)
23+
#if defined(__has_include)
24+
#if __has_include(<arm/cpu_capabilities_public.h>)
25+
#include <arm/cpu_capabilities_public.h>
26+
#endif
27+
#endif
28+
#include <sys/sysctl.h>
29+
#include <sys/types.h>
30+
#endif
31+
2232
#include <cstdint>
2333
#include <cstring>
2434

2535
#include "absl/random/internal/platform.h"
36+
#include "absl/types/optional.h" // IWYU pragma: keep
2637

2738
#if !defined(__UCLIBC__) && defined(__GLIBC__) && \
2839
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16))
@@ -102,6 +113,19 @@ static uint32_t GetAuxval(uint32_t hwcap_type) {
102113

103114
#endif
104115

116+
#if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
117+
template <typename T>
118+
static absl::optional<T> ReadSysctlByName(const char* name) {
119+
T val;
120+
size_t val_size = sizeof(T);
121+
int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
122+
if (ret == -1) {
123+
return std::nullopt;
124+
}
125+
return val;
126+
}
127+
#endif
128+
105129
namespace absl {
106130
ABSL_NAMESPACE_BEGIN
107131
namespace random_internal {
@@ -122,14 +146,18 @@ namespace random_internal {
122146
//
123147
// Fon non-x86 it is much more complicated.
124148
//
125-
// 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
149+
// 2. Try to use __builtin_cpu_supports.
150+
//
151+
// 3. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
126152
// the direct c-library version, or the android probing version which loads
127153
// libc), and read the hardware capability bits.
128154
// This is based on the technique used by boringssl uses to detect
129155
// cpu capabilities, and should allow us to enable crypto in the android
130156
// builds where it is supported.
131157
//
132-
// 3. Use the default for the compiler architecture.
158+
// 4. When __APPLE__ is defined on AARCH64, use sysctlbyname().
159+
//
160+
// 5. Use the default for the compiler architecture.
133161
//
134162

135163
bool CPUSupportsRandenHwAes() {
@@ -139,8 +167,14 @@ bool CPUSupportsRandenHwAes() {
139167
__cpuid(reinterpret_cast<int*>(regs), 1);
140168
return regs[2] & (1 << 25); // AES
141169

170+
#elif defined(ABSL_ARCH_AARCH64) && ABSL_HAVE_BUILTIN(__builtin_cpu_supports)
171+
// For AARCH64: Require crypto+neon
172+
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
173+
//
174+
// __builtin_cpu_supports spells "crypt" as "aes" and "neon" as "simd".
175+
return __builtin_cpu_supports("aes+simd");
142176
#elif defined(ABSL_INTERNAL_USE_GETAUXVAL)
143-
// 2. Use getauxval() to read the hardware bits and determine
177+
// 3. Use getauxval() to read the hardware bits and determine
144178
// cpu capabilities.
145179

146180
#define AT_HWCAP 16
@@ -178,8 +212,36 @@ bool CPUSupportsRandenHwAes() {
178212
return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0);
179213
#endif
180214

215+
#elif defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
216+
// 4. Use sysctlbyname.
217+
218+
// Newer XNU kernels support querying all capabilities in a single
219+
// sysctlbyname.
220+
#if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES)
221+
static const absl::optional<uint64_t> caps =
222+
ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
223+
if (caps.has_value()) {
224+
constexpr uint64_t kNeonAndAesCaps =
225+
(uint64_t{1} << CAP_BIT_AdvSIMD) | (uint64_t{1} << CAP_BIT_FEAT_AES);
226+
return (*caps & kNeonAndAesCaps) == kNeonAndAesCaps;
227+
}
228+
#endif
229+
230+
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview
231+
static const absl::optional<int> adv_simd =
232+
ReadSysctlByName<int>("hw.optional.AdvSIMD");
233+
if (adv_simd.value_or(0) == 0) {
234+
return false;
235+
}
236+
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
237+
static const absl::optional<int> feat_aes =
238+
ReadSysctlByName<int>("hw.optional.arm.FEAT_AES");
239+
if (feat_aes.value_or(0) == 0) {
240+
return false;
241+
}
242+
return true;
181243
#else // ABSL_INTERNAL_USE_GETAUXVAL
182-
// 3. By default, assume that the compiler default.
244+
// 5. By default, assume that the compiler default.
183245
return ABSL_HAVE_ACCELERATED_AES ? true : false;
184246

185247
#endif
@@ -215,9 +277,6 @@ bool CPUSupportsRandenHwAes() {
215277
// __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val));
216278
//
217279
// * Use a CPUID-style heuristic database.
218-
//
219-
// * On Apple (__APPLE__), AES is available on Arm v8.
220-
// https://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
221280
}
222281

223282
#if defined(__clang__)

absl/random/internal/randen_hwaes_test.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ int main(int argc, char* argv[]) {
8989
LOG(INFO) << "HasRandenHwAesImplementation = " << x;
9090

9191
int y = absl::random_internal::CPUSupportsRandenHwAes();
92-
LOG(INFO) << "CPUSupportsRandenHwAes = " << x;
92+
LOG(INFO) << "CPUSupportsRandenHwAes = " << y;
9393

9494
if (!x || !y) {
9595
LOG(INFO) << "Skipping Randen HWAES tests.";

0 commit comments

Comments
 (0)