Skip to content

Commit bf2b5cf

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

File tree

24 files changed

+843
-106
lines changed

24 files changed

+843
-106
lines changed

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
language: rust
22
sudo: false
33
rust: nightly
4+
services: docker
5+
git:
6+
depth: 1
7+
submodules: false
48

59
matrix:
610
fast_finish: true

Cross.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[build.env]
2+
passthrough = [
3+
"RUST_BACKTRACE",
4+
"RUST_LOG",
5+
"TRAVIS",
6+
"OBJDUMP",
7+
]
Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
FROM ubuntu:17.10
2-
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
2+
3+
RUN apt-get update -y && apt-get install -y --no-install-recommends \
4+
bc \
5+
bzip2 \
6+
ca-certificates \
7+
cmake \
8+
cpio \
9+
curl \
10+
file \
11+
g++ \
12+
gcc-aarch64-linux-gnu \
13+
git \
14+
libc6-dev \
15+
libc6-dev-arm64-cross \
16+
make \
17+
python2.7 \
18+
qemu-system-aarch64 \
19+
xz-utils
20+
21+
COPY linux-aarch64.sh /
22+
RUN bash /linux-aarch64.sh
23+
24+
COPY test-runner-linux /
25+
1126
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
12-
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \
13-
OBJDUMP=aarch64-linux-gnu-objdump
27+
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="/test-runner-linux" \
28+
OBJDUMP=aarch64-linux-gnu-objdump
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
set -ex
2+
3+
mkdir -m 777 /qemu
4+
cd /qemu
5+
6+
curl -LO https://github.com/qemu/qemu/raw/master/pc-bios/efi-virtio.rom
7+
curl -LO http://ftp.debian.org/debian/dists/testing/main/installer-arm64/20170828/images/netboot/debian-installer/arm64/linux
8+
curl -LO http://ftp.debian.org/debian/dists/testing/main/installer-arm64/20170828/images/netboot/debian-installer/arm64/initrd.gz
9+
10+
mv linux kernel
11+
#mv initrd.debian initrd.gz
12+
13+
mkdir init
14+
cd init
15+
gunzip -c ../initrd.gz | cpio -id
16+
rm ../initrd.gz
17+
cp /usr/aarch64-linux-gnu/lib/libgcc_s.so.1 usr/lib/
18+
chmod a+w .
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
cd /qemu/init
6+
echo "arg is: ${1}"
7+
cp -f $1 prog
8+
find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz
9+
cd ..
10+
11+
mkdir bin
12+
cp $OBJDUMP bin/
13+
14+
timeout 60s qemu-system-aarch64 \
15+
-m 1024 \
16+
-smp 1 \
17+
-machine virt \
18+
-cpu cortex-a57 \
19+
-nographic \
20+
-kernel kernel \
21+
-initrd initrd.gz \
22+
--append "console=ttyAMA0" \
23+
-fsdev local,id=r,path=/qemu/bin,security_model=none \
24+
-device virtio-9p-device,fsdev=r,mount_tag=r \
25+
-append init="mount -t 9p -o trans=virtio r /mnt && export PATH=/mnt/bin:$PATH && /prog ${@:2}" > output 2>&1 || true
26+
27+
# remove kernel messages
28+
tr -d '\r' < output | egrep -v '^\['
29+
30+
! grep FAILED output > /dev/null

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/arm/runtime/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+

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)