Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn std_detect into a no_std crate #1005

Merged
merged 5 commits into from
Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,203 changes: 851 additions & 352 deletions crates/core_arch/src/x86/avx512bf16.rs

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions crates/std_detect/src/detect/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

#![allow(dead_code)] // not used on all platforms

use crate::sync::atomic::Ordering;
use core::sync::atomic::Ordering;

use crate::sync::atomic::AtomicUsize;
use core::sync::atomic::AtomicUsize;

/// Sets the `bit` of `x`.
#[inline]
Expand Down Expand Up @@ -125,9 +125,16 @@ cfg_if::cfg_if! {
if #[cfg(feature = "std_detect_env_override")] {
#[inline]
fn initialize(mut value: Initializer) -> Initializer {
if let Ok(disable) = crate::env::var("RUST_STD_DETECT_UNSTABLE") {
for v in disable.split(" ") {
let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32));
let env = unsafe {
libc::getenv(b"RUST_STD_DETECT_UNSTABLE\0".as_ptr() as *const libc::c_char)
};
if !env.is_null() {
let len = unsafe { libc::strlen(env) };
let env = unsafe { core::slice::from_raw_parts(env as *const u8, len) };
if let Ok(disable) = core::str::from_utf8(env) {
for v in disable.split(" ") {
let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32));
}
}
}
do_initialize(value);
Expand Down
6 changes: 3 additions & 3 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 Expand Up @@ -140,7 +140,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
target_arch = "mips64",
))] {
(0_u8..Feature::_last as u8).map(|discriminant: u8| {
let f: Feature = unsafe { crate::mem::transmute(discriminant) };
let f: Feature = unsafe { core::mem::transmute(discriminant) };
let name: &'static str = f.to_str();
let enabled: bool = check_for(f);
(name, enabled)
Expand Down
2 changes: 1 addition & 1 deletion crates/std_detect/src/detect/os/freebsd/auxvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {

/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
use crate::mem;
use core::mem;

#[derive(Copy, Clone)]
#[repr(C)]
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
100 changes: 72 additions & 28 deletions crates/std_detect/src/detect/os/linux/auxvec.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
//! Parses ELF auxiliary vectors.
#![cfg_attr(not(target_arch = "aarch64"), allow(dead_code))]

#[cfg(feature = "std_detect_file_io")]
use crate::{fs::File, io::Read};
pub(crate) const AT_NULL: usize = 0;

/// 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 +20,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 +71,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 +85,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 +100,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 +138,7 @@ fn getauxval(key: usize) -> Result<usize, ()> {
return Err(());
}

let ffi_getauxval: F = mem::transmute(ptr);
let ffi_getauxval: F = core::mem::transmute(ptr);
Ok(ffi_getauxval(key))
}
}
Expand All @@ -131,18 +147,19 @@ fn getauxval(key: usize) -> Result<usize, ()> {
/// function returns `Err`.
#[cfg(feature = "std_detect_file_io")]
fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
let mut file = File::open(file).map_err(|_| ())?;
let file = super::read_file(file)?;

// See <https://github.com/torvalds/linux/blob/v3.19/include/uapi/linux/auxvec.h>.
//
// The auxiliary vector contains at most 32 (key,value) fields: from
// `AT_EXECFN = 31` to `AT_NULL = 0`. That is, a buffer of
// 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) };
file.read(raw).map_err(|_| ())?;
let len = core::mem::size_of_val(&buf).max(file.len());
unsafe {
core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len);
}

auxv_from_buf(&buf)
}

Expand All @@ -155,18 +172,24 @@ fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
{
for el in buf.chunks(2) {
match el[0] {
AT_NULL => break,
AT_HWCAP => return Ok(AuxVec { hwcap: el[1] }),
_ => (),
}
}
}
// 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;
for el in buf.chunks(2) {
match el[0] {
AT_NULL => break,
AT_HWCAP => hwcap = Some(el[1]),
AT_HWCAP2 => hwcap2 = Some(el[1]),
_ => (),
Expand Down Expand Up @@ -214,7 +237,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 +252,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 +275,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 All @@ -264,6 +296,7 @@ mod tests {
// want to fall back to /proc/cpuinfo in this case, so
// reading should fail. assert_eq!(v.hwcap, 126614527);
// assert_eq!(v.hwcap2, 0);
let _ = v;
}
} else if #[cfg(target_arch = "aarch64")] {
#[test]
Expand All @@ -286,15 +319,26 @@ mod tests {
}
}

#[cfg(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
#[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
Loading