Skip to content

Commit 6445928

Browse files
committed
[arm] runtime-detection support
1 parent 5c40592 commit 6445928

File tree

15 files changed

+491
-101
lines changed

15 files changed

+491
-101
lines changed
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
FROM ubuntu:17.10
22
RUN apt-get update && apt-get install -y --no-install-recommends \
3-
gcc \
4-
ca-certificates \
5-
libc6-dev \
6-
gcc-aarch64-linux-gnu \
7-
libc6-dev-arm64-cross \
8-
qemu-user \
9-
make \
10-
file
3+
gcc \
4+
ca-certificates \
5+
libc6-dev \
6+
gcc-aarch64-linux-gnu \
7+
libc6-dev-arm64-cross \
8+
qemu-user \
9+
make \
10+
file
11+
1112
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
1213
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \
1314
OBJDUMP=aarch64-linux-gnu-objdump

ci/run-docker.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
set -ex
55

66
run() {
7-
echo $1
7+
echo "Building docker container for TARGET=${1}"
88
docker build -t stdsimd ci/docker/$1
99
mkdir -p target
1010
target=$(echo $1 | sed 's/-emulated//')
11+
echo "Running docker"
1112
docker run \
1213
--user `id -u`:`id -g` \
1314
--rm \

ci/run.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ FEATURES="strict,$FEATURES"
1919

2020
echo "RUSTFLAGS=${RUSTFLAGS}"
2121
echo "FEATURES=${FEATURES}"
22+
echo "OBJDUMP=${OBJDUMP}"
2223

23-
cargo test --target $TARGET --features $FEATURES
24-
cargo test --release --target $TARGET --features $FEATURES
24+
cargo test --target $TARGET --features $FEATURES --verbose -- --nocapture
25+
cargo test --release --target $TARGET --features $FEATURES --verbose -- --nocapture

src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,13 @@ pub mod vendor {
153153

154154
#[cfg(target_arch = "aarch64")]
155155
pub use aarch64::*;
156+
157+
pub use runtime::{__unstable_detect_feature, __Feature};
156158
}
157159

160+
#[macro_use]
161+
mod runtime;
162+
158163
#[macro_use]
159164
mod macros;
160165
mod simd_llvm;
@@ -164,7 +169,6 @@ mod v512;
164169
mod v64;
165170

166171
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
167-
#[macro_use]
168172
mod x86;
169173

170174
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]

src/macros.rs

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -272,52 +272,3 @@ macro_rules! define_casts {
272272
)+
273273
}
274274
}
275-
276-
/// Is a feature supported by the host CPU?
277-
///
278-
/// This macro performs run-time feature detection. It returns true if the host
279-
/// CPU in which the binary is running on supports a particular feature.
280-
#[macro_export]
281-
macro_rules! cfg_feature_enabled {
282-
($name:tt) => (
283-
{
284-
#[cfg(target_feature = $name)]
285-
{
286-
true
287-
}
288-
#[cfg(not(target_feature = $name))]
289-
{
290-
__unstable_detect_feature!($name)
291-
}
292-
}
293-
)
294-
}
295-
296-
/// On ARM features are only detected at compile-time using
297-
/// cfg(target_feature), so if this macro is executed the
298-
/// feature is not supported.
299-
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
300-
#[macro_export]
301-
#[doc(hidden)]
302-
macro_rules! __unstable_detect_feature {
303-
("neon") => { false };
304-
($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
305-
}
306-
307-
/// In all unsupported architectures using the macro is an error
308-
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64",
309-
target_arch = "arm", target_arch = "aarch64")))]
310-
#[macro_export]
311-
#[doc(hidden)]
312-
macro_rules! __unstable_detect_feature {
313-
($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
314-
}
315-
316-
#[cfg(test)]
317-
mod tests {
318-
#[cfg(target_arch = "x86_64")]
319-
#[test]
320-
fn test_macros() {
321-
assert!(cfg_feature_enabled!("sse"));
322-
}
323-
}

src/runtime/aarch64.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! Run-time feature detection on ARM Aarch64.
2+
use super::{bit, linux};
3+
4+
#[macro_export]
5+
#[doc(hidden)]
6+
macro_rules! __unstable_detect_feature {
7+
("neon") => {
8+
// FIXME: this should be removed once we rename Aarch64 neon to asimd
9+
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{})
10+
};
11+
("asimd") => {
12+
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{})
13+
};
14+
("pmull") => {
15+
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{})
16+
};
17+
($t:tt) => { compile_error!(concat!("unknown arm target feature: ", $t)) };
18+
}
19+
20+
/// ARM CPU Feature enum. Each variant denotes a position in a bitset for a
21+
/// particular feature.
22+
///
23+
/// PLEASE: do not use this, it is an implementation detail subject to change.
24+
#[doc(hidden)]
25+
#[allow(non_camel_case_types)]
26+
#[repr(u8)]
27+
pub enum __Feature {
28+
/// ARM Advanced SIMD (ASIMD) - Aarch64
29+
asimd,
30+
/// Polynomial Multiply
31+
pmull,
32+
}
33+
34+
pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
35+
let value: usize = 0;
36+
{
37+
let mut enable_feature = | f | {
38+
if x.has_feature(& f) {
39+
bit::set(value, f as u32);
40+
}
41+
};
42+
enable_feature(__Feature::asimd);
43+
enable_feature(__Feature::pmull);
44+
}
45+
value
46+
}
47+
48+
impl linux::FeatureQuery for linux::CpuInfo {
49+
fn has_feature(&mut self, x: &__Feature) -> bool {
50+
use self::__Feature::*;
51+
match *x {
52+
asimd => self.field("Features").has("asimd"),
53+
pmull => self.field("Features").has("pmull"),
54+
}
55+
}
56+
}

src/runtime/arm.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! Run-time feature detection on ARM Aarch32.
2+
3+
use super::{bit, linux};
4+
5+
#[macro_export]
6+
#[doc(hidden)]
7+
macro_rules! __unstable_detect_feature {
8+
("neon") => {
9+
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::neon{})
10+
};
11+
("pmull") => {
12+
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{})
13+
};
14+
($t:tt) => { compile_error!(concat!("unknown arm target feature: ", $t)) };
15+
}
16+
17+
/// ARM CPU Feature enum. Each variant denotes a position in a bitset for a
18+
/// particular feature.
19+
///
20+
/// PLEASE: do not use this, it is an implementation detail subject to change.
21+
#[doc(hidden)]
22+
#[allow(non_camel_case_types)]
23+
#[repr(u8)]
24+
pub enum __Feature {
25+
/// ARM Advanced SIMD (NEON) - Aarch32
26+
neon,
27+
/// Polynomial Multiply
28+
pmull,
29+
}
30+
31+
pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
32+
let value: usize = 0;
33+
{
34+
let mut enable_feature = | f | {
35+
if x.has_feature(&f) {
36+
bit::set(value, f as u32);
37+
}
38+
};
39+
enable_feature(__Feature::neon);
40+
enable_feature(__Feature::pmull);
41+
}
42+
value
43+
}
44+
45+
/// Is the CPU known to have a broken NEON unit?
46+
///
47+
/// See https://crbug.com/341598.
48+
fn has_broken_neon(cpuinfo: & linux::CpuInfo) -> bool {
49+
cpuinfo.field("CPU implementer") == "0x51"
50+
&& cpuinfo.field("CPU architecture") == "7"
51+
&& cpuinfo.field("CPU variant") == "0x1"
52+
&& cpuinfo.field("CPU part") == "0x04d"
53+
&& cpuinfo.field("CPU revision") == "0"
54+
}
55+
56+
impl linux::FeatureQuery for linux::CpuInfo {
57+
fn has_feature(&mut self, x: &__Feature) -> bool {
58+
use self::__Feature::*;
59+
match *x {
60+
neon => self.field("Features").has("neon") && !has_broken_neon(self),
61+
pmull => self.field("Features").has("pmull"),
62+
}
63+
}
64+
}

src/runtime/bit.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! Bit manipulation utilities
2+
3+
/// Sets the `bit` of `x`.
4+
pub const fn set(x: usize, bit: u32) -> usize {
5+
x | 1 << bit
6+
}
7+
8+
/// Tests the `bit` of `x`.
9+
pub const fn test(x: usize, bit: u32) -> bool {
10+
x & (1 << bit) != 0
11+
}

src/runtime/cache.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//! Cache of run-time feature detection
2+
3+
use super::bit;
4+
use std::sync::atomic::{AtomicUsize, Ordering};
5+
6+
/// This global variable is a bitset used to cache the features supported by
7+
/// the
8+
/// CPU.
9+
static CACHE: AtomicUsize = AtomicUsize::new(::std::usize::MAX);
10+
11+
/// Test the `bit` of the storage. If the storage has not been initialized,
12+
/// initializes it with the result of `f()`.
13+
///
14+
/// On its first invocation, it detects the CPU features and caches them in the
15+
/// `FEATURES` global variable as an `AtomicUsize`.
16+
///
17+
/// It uses the `__Feature` variant to index into this variable as a bitset. If
18+
/// the bit is set, the feature is enabled, and otherwise it is disabled.
19+
///
20+
/// PLEASE: do not use this, it is an implementation detail subject to change.
21+
pub fn test<F>(bit: u32, f: F) -> bool
22+
where
23+
F: FnOnce() -> usize,
24+
{
25+
if CACHE.load(Ordering::Relaxed) == ::std::usize::MAX {
26+
CACHE.store(f(), Ordering::Relaxed);
27+
}
28+
bit::test(CACHE.load(Ordering::Relaxed), bit)
29+
}

0 commit comments

Comments
 (0)