Skip to content

Commit 59b29d6

Browse files
committed
unify implementations
1 parent d8e9304 commit 59b29d6

File tree

3 files changed

+125
-149
lines changed

3 files changed

+125
-149
lines changed

cpufeatures/src/aarch64.rs

+30-75
Original file line numberDiff line numberDiff line change
@@ -4,86 +4,41 @@
44
//! unprivileged userspace code, so this implementation relies on OS-specific
55
//! APIs for feature detection.
66
7-
/// Create module with CPU feature detection code.
87
#[macro_export]
9-
macro_rules! new {
10-
($mod_name:ident, $($tf:tt),+ $(,)? ) => {
11-
mod $mod_name {
12-
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
13-
14-
const UNINIT: u8 = u8::max_value();
15-
static STORAGE: AtomicU8 = AtomicU8::new(UNINIT);
16-
17-
/// Initialization token
18-
#[derive(Copy, Clone, Debug)]
19-
pub struct InitToken(());
20-
21-
impl InitToken {
22-
/// Get initialized value
23-
#[inline(always)]
24-
pub fn get(&self) -> bool {
25-
#[cfg(not(all($(target_feature=$tf, )*)))]
26-
let res = STORAGE.load(Relaxed) == 1;
27-
#[cfg(all($(target_feature=$tf, )*))]
28-
let res = true;
29-
res
30-
}
31-
}
32-
33-
/// Initialize underlying storage if needed and get
34-
/// stored value and initialization token.
35-
#[inline]
36-
pub fn init_get() -> (InitToken, bool) {
37-
#[cfg(not(all($(target_feature=$tf, )*)))]
38-
let res = {
39-
// Relaxed ordering is fine, as we only have a single atomic variable.
40-
let val = STORAGE.load(Relaxed);
41-
if val == UNINIT {
42-
let res = {
43-
#[cfg(target_os = "linux")]
44-
{
45-
let hwcaps = unsafe { libc::getauxval(libc::AT_HWCAP) };
46-
$(cpufeatures::check!(hwcaps, $tf) & )+ true
47-
}
48-
49-
#[cfg(target_os = "macos")]
50-
{
51-
$(cpufeatures::check!($tf) & )+ true
52-
}
53-
};
54-
55-
STORAGE.store(res as u8, Relaxed);
56-
res
57-
} else {
58-
val == 1
59-
}
60-
};
61-
#[cfg(all($(target_feature=$tf, )*))]
62-
let res = true;
63-
64-
(InitToken(()), res)
65-
}
66-
67-
/// Initialize underlying storage if needed and get
68-
/// initialization token.
69-
#[inline]
70-
pub fn init() -> InitToken {
71-
init_get().0
72-
}
73-
74-
/// Initialize underlying storage if needed and get
75-
/// stored value.
76-
#[inline]
77-
pub fn get() -> bool {
78-
init_get().1
79-
}
8+
macro_rules! __unless_target_features {
9+
($($tf:tt),+ => $body:expr ) => {
10+
{
11+
#[cfg(not(all($(target_feature=$tf,)*)))]
12+
$body
13+
14+
#[cfg(all($(target_feature=$tf,)*))]
15+
true
8016
}
8117
};
8218
}
8319

20+
#[cfg(target_os = "linux")]
21+
#[macro_export]
22+
#[doc(hidden)]
23+
macro_rules! __detect_target_features {
24+
($($tf:tt),+) => {{
25+
let hwcaps = unsafe { libc::getauxval(libc::AT_HWCAP) };
26+
$($crate::check!(hwcaps, $tf) & )+ true
27+
}};
28+
}
29+
30+
#[cfg(target_os = "macos")]
31+
#[macro_export]
32+
#[doc(hidden)]
33+
macro_rules! __detect_target_features {
34+
($($tf:tt),+) => {{
35+
$($crate::check!($tf) & )+ true
36+
}};
37+
}
38+
8439
/// Linux `expand_check_macro`
8540
#[cfg(target_os = "linux")]
86-
macro_rules! expand_check_macro {
41+
macro_rules! __expand_check_macro {
8742
($(($name:tt, $hwcap:expr)),* $(,)?) => {
8843
#[macro_export]
8944
#[doc(hidden)]
@@ -97,7 +52,7 @@ macro_rules! expand_check_macro {
9752

9853
/// Linux `expand_check_macro`
9954
#[cfg(target_os = "linux")]
100-
expand_check_macro! {
55+
__expand_check_macro! {
10156
("aes", HWCAP_AES), // Enable AES support.
10257
("sha2", HWCAP_SHA2), // Enable SHA1 and SHA256 support.
10358
("sha3", HWCAP_SHA3), // Enable SHA512 and SHA3 support.
@@ -125,7 +80,7 @@ macro_rules! check {
12580
true
12681
};
12782
("sha3") => {
128-
unsafe { cpufeatures::aarch64::sysctlbyname(b"hw.optional.armv8_2_sha3\0") }
83+
unsafe { $crate::aarch64::sysctlbyname(b"hw.optional.armv8_2_sha3\0") }
12984
};
13085
}
13186

cpufeatures/src/lib.rs

+65
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,68 @@ mod x86;
6464
target_arch = "x86_64"
6565
)))]
6666
compile_error!("This crate works only on `aarch64` (Linux/Mac), `x86`, and `x86-64 targets.");
67+
68+
/// Create module with CPU feature detection code.
69+
#[macro_export]
70+
macro_rules! new {
71+
($mod_name:ident, $($tf:tt),+) => {
72+
mod $mod_name {
73+
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
74+
75+
const UNINIT: u8 = u8::max_value();
76+
static STORAGE: AtomicU8 = AtomicU8::new(UNINIT);
77+
78+
/// Initialization token
79+
#[derive(Copy, Clone, Debug)]
80+
pub struct InitToken(());
81+
82+
impl InitToken {
83+
/// Get initialized value
84+
#[inline(always)]
85+
pub fn get(&self) -> bool {
86+
$crate::__unless_target_features! {
87+
$($tf),+ => {
88+
STORAGE.load(Relaxed) == 1
89+
}
90+
}
91+
}
92+
}
93+
94+
/// Initialize underlying storage if needed and get
95+
/// stored value and initialization token.
96+
#[inline]
97+
pub fn init_get() -> (InitToken, bool) {
98+
let res = $crate::__unless_target_features! {
99+
$($tf),+ => {
100+
// Relaxed ordering is fine, as we only have a single atomic variable.
101+
let val = STORAGE.load(Relaxed);
102+
103+
if val == UNINIT {
104+
let res = $crate::__detect_target_features!($($tf),+);
105+
STORAGE.store(res as u8, Relaxed);
106+
res
107+
} else {
108+
val == 1
109+
}
110+
}
111+
};
112+
113+
(InitToken(()), res)
114+
}
115+
116+
/// Initialize underlying storage if needed and get
117+
/// initialization token.
118+
#[inline]
119+
pub fn init() -> InitToken {
120+
init_get().0
121+
}
122+
123+
/// Initialize underlying storage if needed and get
124+
/// stored value.
125+
#[inline]
126+
pub fn get() -> bool {
127+
init_get().1
128+
}
129+
}
130+
};
131+
}

cpufeatures/src/x86.rs

+30-74
Original file line numberDiff line numberDiff line change
@@ -3,87 +3,43 @@
33
//! Portable, `no_std`-friendly implementation that relies on the x86 `CPUID`
44
//! instruction for feature detection.
55
6-
/// Create module with CPU feature detection code.
76
#[macro_export]
8-
macro_rules! new {
9-
($mod_name:ident, $($tf:tt),+ $(,)? ) => {
10-
mod $mod_name {
11-
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
7+
#[doc(hidden)]
8+
macro_rules! __unless_target_features {
9+
($($tf:tt),+ => $body:expr ) => {{
10+
#[cfg(not(all($(target_feature=$tf,)*)))]
11+
{
12+
#[cfg(not(target_env = "sgx"))]
13+
$body
1214

13-
const UNINIT: u8 = u8::max_value();
14-
static STORAGE: AtomicU8 = AtomicU8::new(UNINIT);
15-
16-
/// Initialization token
17-
#[derive(Copy, Clone, Debug)]
18-
pub struct InitToken(());
19-
20-
impl InitToken {
21-
/// Get initialized value
22-
#[inline(always)]
23-
pub fn get(&self) -> bool {
24-
// CPUID is not available on SGX targets
25-
#[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))]
26-
let res = STORAGE.load(Relaxed) == 1;
27-
#[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))]
28-
let res = false;
29-
#[cfg(all($(target_feature=$tf, )*))]
30-
let res = true;
31-
res
32-
}
33-
}
34-
35-
/// Initialize underlying storage if needed and get
36-
/// stored value and initialization token.
37-
#[inline]
38-
pub fn init_get() -> (InitToken, bool) {
39-
// CPUID is not available on SGX targets
40-
#[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))]
41-
let res = {
42-
#[cfg(target_arch = "x86")]
43-
use core::arch::x86::{__cpuid, __cpuid_count};
44-
#[cfg(target_arch = "x86_64")]
45-
use core::arch::x86_64::{__cpuid, __cpuid_count};
15+
// CPUID is not available on SGX targets
16+
#[cfg(target_env = "sgx")]
17+
false
18+
}
4619

47-
// Relaxed ordering is fine, as we only have a single atomic variable.
48-
let val = STORAGE.load(Relaxed);
49-
if val == UNINIT {
50-
#[allow(unused_variables)]
51-
let cr = unsafe {
52-
[__cpuid(1), __cpuid_count(7, 0)]
53-
};
54-
let res = $(cpufeatures::check!(cr, $tf) & )+ true;
55-
STORAGE.store(res as u8, Relaxed);
56-
res
57-
} else {
58-
val == 1
59-
}
60-
};
61-
#[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))]
62-
let res = false;
63-
#[cfg(all($(target_feature=$tf, )*))]
64-
let res = true;
20+
#[cfg(all($(target_feature=$tf,)*))]
21+
true
22+
}};
23+
}
6524

66-
(InitToken(()), res)
67-
}
25+
#[macro_export]
26+
#[doc(hidden)]
27+
macro_rules! __detect_target_features {
28+
($($tf:tt),+) => {{
29+
#[cfg(target_arch = "x86")]
30+
use core::arch::x86::{__cpuid, __cpuid_count};
31+
#[cfg(target_arch = "x86_64")]
32+
use core::arch::x86_64::{__cpuid, __cpuid_count};
6833

69-
/// Initialize underlying storage if needed and get
70-
/// initialization token.
71-
#[inline]
72-
pub fn init() -> InitToken {
73-
init_get().0
74-
}
34+
let cr = unsafe {
35+
[__cpuid(1), __cpuid_count(7, 0)]
36+
};
7537

76-
/// Initialize underlying storage if needed and get
77-
/// stored value.
78-
#[inline]
79-
pub fn get() -> bool {
80-
init_get().1
81-
}
82-
}
83-
};
38+
$($crate::check!(cr, $tf) & )+ true
39+
}};
8440
}
8541

86-
macro_rules! expand_check_macro {
42+
macro_rules! __expand_check_macro {
8743
($(($name:tt, $i:expr, $reg:ident, $offset:expr)),* $(,)?) => {
8844
#[macro_export]
8945
#[doc(hidden)]
@@ -95,7 +51,7 @@ macro_rules! expand_check_macro {
9551
};
9652
}
9753

98-
expand_check_macro! {
54+
__expand_check_macro! {
9955
("mmx", 0, edx, 23),
10056
("sse", 0, edx, 25),
10157
("sse2", 0, edx, 26),

0 commit comments

Comments
 (0)