Skip to content

Commit 28eff1a

Browse files
valpackettgnzlbg
authored andcommitted
Add support for feature detection on FreeBSD/aarch64
1 parent 3c0503d commit 28eff1a

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed

Diff for: crates/stdsimd/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
deny(clippy::missing_inline_in_public_items,)
1212
)]
1313
#![cfg_attr(target_os = "linux", feature(linkage))]
14+
#![cfg_attr(all(target_os = "freebsd", target_arch = "aarch64"), feature(asm))]
1415
#![no_std]
1516
#![unstable(feature = "stdsimd", issue = "27731")]
1617

Diff for: stdsimd/arch/detect/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ cfg_if! {
7171
} else if #[cfg(target_os = "linux")] {
7272
#[path = "os/linux/mod.rs"]
7373
mod os;
74+
} else if #[cfg(target_os = "freebsd")] {
75+
#[cfg(target_arch = "aarch64")]
76+
#[path = "os/aarch64.rs"]
77+
mod aarch64;
78+
#[path = "os/freebsd/mod.rs"]
79+
mod os;
7480
} else {
7581
#[path = "os/other.rs"]
7682
mod os;

Diff for: stdsimd/arch/detect/os/aarch64.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction.
2+
//!
3+
//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use
4+
//! privileged system registers from userspace to check CPU feature support.
5+
//!
6+
//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1
7+
//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc.
8+
//! Each part of the register indicates the level of support for a certain feature, e.g.
9+
//! when ID_AA64ISAR0_EL1[7:4] is >= 1, AES is supported; when it's >= 2, PMULL is supported.
10+
//!
11+
//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb),
12+
//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947).
13+
//!
14+
//! References:
15+
//!
16+
//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp)
17+
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)
18+
19+
use arch::detect::Feature;
20+
use arch::detect::cache;
21+
22+
/// Try to read the features from the system registers.
23+
///
24+
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
25+
pub(crate) fn detect_features() -> cache::Initializer {
26+
let mut value = cache::Initializer::default();
27+
28+
{
29+
let mut enable_feature = |f, enable| {
30+
if enable {
31+
value.set(f as u32);
32+
}
33+
};
34+
35+
// ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
36+
let aa64isar0: u64;
37+
unsafe { asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); }
38+
39+
let aes = bits_shift(aa64isar0, 7, 4) >= 1;
40+
let pmull = bits_shift(aa64isar0, 7, 4) >= 2;
41+
let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
42+
let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
43+
enable_feature(Feature::pmull, pmull);
44+
// Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp
45+
enable_feature(Feature::crypto, aes && pmull && sha1 && sha2);
46+
enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
47+
enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);
48+
49+
// ID_AA64PFR0_EL1 - Processor Feature Register 0
50+
let aa64pfr0: u64;
51+
unsafe { asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); }
52+
53+
let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
54+
let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
55+
let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
56+
let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
57+
enable_feature(Feature::fp, fp);
58+
enable_feature(Feature::fp16, fphp);
59+
// SIMD support requires float support - if half-floats are
60+
// supported, it also requires half-float support:
61+
enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
62+
// SIMD extensions require SIMD support:
63+
enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
64+
enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1);
65+
enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);
66+
67+
// ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1
68+
let aa64isar1: u64;
69+
unsafe { asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); }
70+
71+
enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
72+
}
73+
74+
value
75+
}
76+
77+
#[inline]
78+
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
79+
(x >> low) & ((1 << (high - low + 1)) - 1)
80+
}

Diff for: stdsimd/arch/detect/os/freebsd/aarch64.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//! Run-time feature detection for Aarch64 on FreeBSD.
2+
3+
use arch::detect::Feature;
4+
use arch::detect::cache;
5+
use super::super::aarch64::detect_features;
6+
7+
/// Performs run-time feature detection.
8+
#[inline]
9+
pub fn check_for(x: Feature) -> bool {
10+
cache::test(x as u32, detect_features)
11+
}
12+
13+
#[cfg(test)]
14+
mod tests {
15+
#[test]
16+
fn dump() {
17+
println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
18+
println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
19+
println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
20+
println!("fp16: {:?}", is_aarch64_feature_detected!("fp16"));
21+
println!("sve: {:?}", is_aarch64_feature_detected!("sve"));
22+
println!("crc: {:?}", is_aarch64_feature_detected!("crc"));
23+
println!("crypto: {:?}", is_aarch64_feature_detected!("crypto"));
24+
println!("lse: {:?}", is_aarch64_feature_detected!("lse"));
25+
println!("rdm: {:?}", is_aarch64_feature_detected!("rdm"));
26+
println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc"));
27+
println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod"));
28+
}
29+
}

Diff for: stdsimd/arch/detect/os/freebsd/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//! Run-time feature detection on FreeBSD
2+
3+
cfg_if! {
4+
if #[cfg(target_arch = "aarch64")] {
5+
mod aarch64;
6+
pub use self::aarch64::check_for;
7+
} else {
8+
use arch::detect::Feature;
9+
/// Performs run-time feature detection.
10+
pub fn check_for(_x: Feature) -> bool {
11+
false
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)