Skip to content

Commit

Permalink
Re-enable runtime feature detection on non-x86 platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Feb 14, 2021
1 parent 4abdad0 commit 935acb8
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 48 deletions.
4 changes: 2 additions & 2 deletions crates/std_detect/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ cfg_if! {
// On x86/x86_64 no OS specific functionality is required.
#[path = "os/x86.rs"]
mod os;
} else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
} else if #[cfg(all(target_os = "linux", feature = "libc"))] {
#[path = "os/linux/mod.rs"]
mod os;
} else if #[cfg(all(target_os = "freebsd", feature = "use_std"))] {
} else if #[cfg(all(target_os = "freebsd", feature = "libc"))] {
#[cfg(target_arch = "aarch64")]
#[path = "os/aarch64.rs"]
mod aarch64;
Expand Down
12 changes: 6 additions & 6 deletions crates/std_detect/src/detect/os/freebsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ mod auxvec;
cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::check_for;
pub(crate) use self::aarch64::detect_features;
} else if #[cfg(target_arch = "arm")] {
mod arm;
pub use self::arm::check_for;
pub(crate) use self::arm::detect_features;
} else if #[cfg(target_arch = "powerpc64")] {
mod powerpc;
pub use self::powerpc::check_for;
pub(crate) use self::powerpc::detect_features;
} else {
use crate::arch::detect::Feature;
use crate::detect::cache;
/// Performs run-time feature detection.
pub fn check_for(_x: Feature) -> bool {
false
pub(crate) fn detect_features() -> cache::Initializer {
cache::Initializer::default()
}
}
}
10 changes: 6 additions & 4 deletions crates/std_detect/src/detect/os/linux/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Run-time feature detection for Aarch64 on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{bit, cache, Feature};

/// Try to read the features from the auxiliary vector, and if that fails, try
Expand All @@ -10,7 +10,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
let hwcap: AtHwcap = auxv.into();
return hwcap.cache();
}
if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
let hwcap: AtHwcap = c.into();
return hwcap.cache();
}
Expand Down Expand Up @@ -77,9 +78,10 @@ impl From<auxvec::AuxVec> for AtHwcap {
}
}

impl From<cpuinfo::CpuInfo> for AtHwcap {
#[cfg(feature = "std_detect_file_io")]
impl From<super::cpuinfo::CpuInfo> for AtHwcap {
/// Reads AtHwcap from /proc/cpuinfo .
fn from(c: cpuinfo::CpuInfo) -> Self {
fn from(c: super::cpuinfo::CpuInfo) -> Self {
let f = &c.field("Features");
AtHwcap {
// 64-bit names. FIXME: In 32-bit compatibility mode /proc/cpuinfo will
Expand Down
8 changes: 5 additions & 3 deletions crates/std_detect/src/detect/os/linux/arm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Run-time feature detection for ARM on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{bit, cache, Feature};

/// Try to read the features from the auxiliary vector, and if that fails, try
Expand Down Expand Up @@ -31,7 +31,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
return value;
}

if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
enable_feature(
&mut value,
Feature::neon,
Expand All @@ -55,7 +56,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
/// Is the CPU known to have a broken NEON unit?
///
/// See https://crbug.com/341598.
fn has_broken_neon(cpuinfo: &cpuinfo::CpuInfo) -> bool {
#[cfg(feature = "std_detect_file_io")]
fn has_broken_neon(cpuinfo: &super::cpuinfo::CpuInfo) -> bool {
cpuinfo.field("CPU implementer") == "0x51"
&& cpuinfo.field("CPU architecture") == "7"
&& cpuinfo.field("CPU variant") == "0x1"
Expand Down
82 changes: 59 additions & 23 deletions crates/std_detect/src/detect/os/linux/auxvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ use crate::{fs::File, io::Read};
/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 16;
/// Key to access the CPU Hardware capabilities 2 bitfield.
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
pub(crate) const AT_HWCAP2: usize = 26;

/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
Expand All @@ -17,7 +21,11 @@ pub(crate) const AT_HWCAP2: usize = 26;
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
pub hwcap: usize,
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
pub hwcap2: usize,
}

Expand Down Expand Up @@ -64,7 +72,11 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}

// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
if hwcap != 0 && hwcap2 != 0 {
Expand All @@ -74,21 +86,11 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}
drop(hwcap);
}
#[cfg(feature = "std_detect_file_io")]
{
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv")
}
#[cfg(not(feature = "std_detect_file_io"))]
{
Err(())
}
}

#[cfg(not(feature = "std_detect_dlsym_getauxval"))]
{
let hwcap = unsafe { ffi_getauxval(AT_HWCAP) };
let hwcap = unsafe { libc::getauxval(AT_HWCAP) };

// Targets with only AT_HWCAP:
#[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
Expand All @@ -99,14 +101,29 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}

// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
let hwcap2 = unsafe { ffi_getauxval(AT_HWCAP2) };
let hwcap2 = unsafe { libc::getauxval(AT_HWCAP2) };
if hwcap != 0 && hwcap2 != 0 {
return Ok(AuxVec { hwcap, hwcap2 });
}
}
}

#[cfg(feature = "std_detect_file_io")]
{
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv")
}
#[cfg(not(feature = "std_detect_file_io"))]
{
Err(())
}
}

/// Tries to read the `key` from the auxiliary vector by calling the
Expand All @@ -122,7 +139,7 @@ fn getauxval(key: usize) -> Result<usize, ()> {
return Err(());
}

let ffi_getauxval: F = mem::transmute(ptr);
let ffi_getauxval: F = crate::mem::transmute(ptr);
Ok(ffi_getauxval(key))
}
}
Expand All @@ -140,7 +157,8 @@ fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
// 2*32 `usize` elements is enough to read the whole vector.
let mut buf = [0_usize; 64];
{
let raw: &mut [u8; 64 * mem::size_of::<usize>()] = unsafe { mem::transmute(&mut buf) };
let raw: &mut [u8; 64 * crate::mem::size_of::<usize>()] =
unsafe { crate::mem::transmute(&mut buf) };
file.read(raw).map_err(|_| ())?;
}
auxv_from_buf(&buf)
Expand All @@ -161,7 +179,11 @@ fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
}
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
let mut hwcap = None;
let mut hwcap2 = None;
Expand Down Expand Up @@ -214,7 +236,12 @@ mod tests {

// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
// does not always contain the AT_HWCAP key under qemu.
#[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc")))]
#[cfg(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
#[test]
fn auxv_crate() {
let v = auxv();
Expand All @@ -224,7 +251,11 @@ mod tests {
}

// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Some(hwcap2) = auxv_crate_getauxval(AT_HWCAP2) {
let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2;
Expand All @@ -243,7 +274,7 @@ mod tests {
}

#[cfg(feature = "std_detect_file_io")]
cfg_if! {
cfg_if::cfg_if! {
if #[cfg(target_arch = "arm")] {
#[test]
fn linux_rpi3() {
Expand Down Expand Up @@ -287,14 +318,19 @@ mod tests {
}

#[test]
#[cfg(feature = "std_detect_file_io")]
fn auxv_crate_procfs() {
let v = auxv();
if let Some(hwcap) = auxv_crate_getprocfs(AT_HWCAP) {
assert_eq!(v.unwrap().hwcap, hwcap);
}

// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Some(hwcap2) = auxv_crate_getprocfs(AT_HWCAP2) {
assert_eq!(v.unwrap().hwcap2, hwcap2);
Expand Down
16 changes: 8 additions & 8 deletions crates/std_detect/src/detect/os/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ mod auxvec;
#[cfg(feature = "std_detect_file_io")]
mod cpuinfo;

cfg_if! {
cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::check_for;
pub(crate) use self::aarch64::detect_features;
} else if #[cfg(target_arch = "arm")] {
mod arm;
pub use self::arm::check_for;
pub(crate) use self::arm::detect_features;
} else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
mod mips;
pub use self::mips::check_for;
pub(crate) use self::mips::detect_features;
} else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] {
mod powerpc;
pub use self::powerpc::check_for;
pub(crate) use self::powerpc::detect_features;
} else {
use crate::detect::Feature;
use crate::detect::cache;
/// Performs run-time feature detection.
pub fn check_for(_x: Feature) -> bool {
false
pub(crate) fn detect_features() -> cache::Initializer {
cache::Initializer::default()
}
}
}
5 changes: 3 additions & 2 deletions crates/std_detect/src/detect/os/linux/powerpc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Run-time feature detection for PowerPC on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{cache, Feature};

/// Try to read the features from the auxiliary vector, and if that fails, try
Expand All @@ -27,7 +27,8 @@ pub(crate) fn detect_features() -> cache::Initializer {

// PowerPC's /proc/cpuinfo lacks a proper Feature field,
// but `altivec` support is indicated in the `cpu` field.
if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
enable_feature(&mut value, Feature::altivec, c.field("cpu").has("altivec"));
return value;
}
Expand Down

0 comments on commit 935acb8

Please sign in to comment.