Skip to content

Commit

Permalink
add is_s390x_feature_detected
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev authored and Amanieu committed Jan 16, 2025
1 parent b1f0789 commit 225e1ec
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 15 deletions.
8 changes: 4 additions & 4 deletions crates/std_detect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The private `std::detect` module implements run-time feature detection in Rust's
standard library. This allows detecting whether the CPU the binary runs on
supports certain features, like SIMD instructions.

# Usage
# Usage

`std::detect` APIs are available as part of `libstd`. Prefer using it via the
standard library than through this crate. Unstable features of `std::detect` are
Expand All @@ -19,7 +19,7 @@ from the platform.
You can then manually include `std_detect` as a dependency to get similar
run-time feature detection support than the one offered by Rust's standard
library. We intend to make `std_detect` more flexible and configurable in this
regard to better serve the needs of `#[no_std]` targets.
regard to better serve the needs of `#[no_std]` targets.

# Features

Expand Down Expand Up @@ -53,8 +53,8 @@ crate from working on applications in which `std` is not available.
[`cupid`](https://crates.io/crates/cupid) crate.

* Linux/Android:
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`: `std_detect`
supports these on Linux by querying ELF auxiliary vectors (using `getauxval`
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`, `s390x`:
`std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval`
when available), and if that fails, by querying `/proc/cpuinfo`.
* `arm64`: partial support for doing run-time feature detection by directly
querying `mrs` is implemented for Linux >= 4.11, but not enabled by default.
Expand Down
5 changes: 5 additions & 0 deletions crates/std_detect/src/detect/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ mod mips;
mod mips64;
#[macro_use]
mod loongarch;
#[macro_use]
mod s390x;

cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
Expand Down Expand Up @@ -50,6 +52,9 @@ cfg_if! {
} else if #[cfg(target_arch = "loongarch64")] {
#[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")]
pub use loongarch::*;
} else if #[cfg(target_arch = "s390x")] {
#[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")]
pub use s390x::*;
} else {
// Unimplemented architecture:
#[doc(hidden)]
Expand Down
12 changes: 12 additions & 0 deletions crates/std_detect/src/detect/arch/s390x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Run-time feature detection on s390x.
features! {
@TARGET: s390x;
@CFG: target_arch = "s390x";
@MACRO_NAME: is_s390x_feature_detected;
@MACRO_ATTRS:
/// Checks if `s390x` feature is enabled.
#[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")]
@FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector: "vector";
/// s390x vector facility
}
1 change: 1 addition & 0 deletions crates/std_detect/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
target_arch = "mips",
target_arch = "mips64",
target_arch = "loongarch64",
target_arch = "s390x",
))] {
(0_u8..Feature::_last as u8).map(|discriminant: u8| {
#[allow(bindings_with_variant_name)] // RISC-V has Feature::f
Expand Down
24 changes: 16 additions & 8 deletions crates/std_detect/src/detect/os/linux/auxvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ pub(crate) const AT_HWCAP: usize = 16;
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
pub(crate) const AT_HWCAP2: usize = 26;

Expand All @@ -26,7 +27,8 @@ pub(crate) struct AuxVec {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
pub hwcap2: usize,
}
Expand Down Expand Up @@ -98,7 +100,8 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
{
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
Expand Down Expand Up @@ -146,7 +149,8 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
{
let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize };
Expand Down Expand Up @@ -242,7 +246,8 @@ fn auxv_from_buf(buf: &[usize]) -> Result<AuxVec, ()> {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
{
let mut hwcap = None;
Expand Down Expand Up @@ -275,7 +280,8 @@ mod tests {
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
#[test]
fn auxv_crate() {
Expand All @@ -290,7 +296,8 @@ mod tests {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
{
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
Expand Down Expand Up @@ -365,7 +372,8 @@ mod tests {
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
#[test]
#[cfg(feature = "std_detect_file_io")]
Expand Down
3 changes: 3 additions & 0 deletions crates/std_detect/src/detect/os/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "loongarch64")] {
mod loongarch;
pub(crate) use self::loongarch::detect_features;
} else if #[cfg(target_arch = "s390x")] {
mod s390x;
pub(crate) use self::s390x::detect_features;
} else {
use crate::detect::cache;
/// Performs run-time feature detection.
Expand Down
95 changes: 95 additions & 0 deletions crates/std_detect/src/detect/os/linux/s390x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//! Run-time feature detection for s390x on Linux.
use super::auxvec;
use crate::detect::{bit, cache, Feature};

/// Try to read the features from the auxiliary vector
pub(crate) fn detect_features() -> cache::Initializer {
if let Ok(auxv) = auxvec::auxv() {
let hwcap: AtHwcap = auxv.into();
return hwcap.cache();
}

cache::Initializer::default()
}

/// These values are part of the platform-specific [asm/elf.h][kernel], and are a selection of the
/// fields found in the [Facility Indications].
///
/// [Facility Indications]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf#page=63
/// [kernel]: https://github.com/torvalds/linux/blob/b62cef9a5c673f1b8083159f5dc03c1c5daced2f/arch/s390/include/asm/elf.h#L129
#[derive(Debug, Default, PartialEq)]
struct AtHwcap {
esan3: bool,
zarch: bool,
stfle: bool,
msa: bool,
ldisp: bool,
eimm: bool,
dfp: bool,
hpage: bool,
etf3eh: bool,
high_gprs: bool,
te: bool,
vxrs: bool,
vxrs_bcd: bool,
vxrs_ext: bool,
gs: bool,
vxrs_ext2: bool,
vxrs_pde: bool,
sort: bool,
dflt: bool,
vxrs_pde2: bool,
nnpa: bool,
pci_mio: bool,
sie: bool,
}

impl From<auxvec::AuxVec> for AtHwcap {
/// Reads AtHwcap from the auxiliary vector.
fn from(auxv: auxvec::AuxVec) -> Self {
AtHwcap {
esan3: bit::test(auxv.hwcap, 0),
zarch: bit::test(auxv.hwcap, 1),
stfle: bit::test(auxv.hwcap, 2),
msa: bit::test(auxv.hwcap, 3),
ldisp: bit::test(auxv.hwcap, 4),
eimm: bit::test(auxv.hwcap, 5),
dfp: bit::test(auxv.hwcap, 6),
hpage: bit::test(auxv.hwcap, 7),
etf3eh: bit::test(auxv.hwcap, 8),
high_gprs: bit::test(auxv.hwcap, 9),
te: bit::test(auxv.hwcap, 10),
vxrs: bit::test(auxv.hwcap, 11),
vxrs_bcd: bit::test(auxv.hwcap, 12),
vxrs_ext: bit::test(auxv.hwcap, 13),
gs: bit::test(auxv.hwcap, 14),
vxrs_ext2: bit::test(auxv.hwcap, 15),
vxrs_pde: bit::test(auxv.hwcap, 16),
sort: bit::test(auxv.hwcap, 17),
dflt: bit::test(auxv.hwcap, 18),
vxrs_pde2: bit::test(auxv.hwcap, 19),
nnpa: bit::test(auxv.hwcap, 20),
pci_mio: bit::test(auxv.hwcap, 21),
sie: bit::test(auxv.hwcap, 22),
}
}
}

impl AtHwcap {
/// Initializes the cache from the feature bits.
fn cache(self) -> cache::Initializer {
let mut value = cache::Initializer::default();
{
let mut enable_feature = |f, enable| {
if enable {
value.set(f as u32);
}
};

// bit 129 of the extended facility list
enable_feature(Feature::vector, self.vxrs);
}
value
}
}
1 change: 1 addition & 0 deletions crates/std_detect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//! * `powerpc`: [`is_powerpc_feature_detected`]
//! * `powerpc64`: [`is_powerpc64_feature_detected`]
//! * `loongarch`: [`is_loongarch_feature_detected`]
//! * `s390x`: [`is_s390x_feature_detected`]
#![unstable(feature = "stdarch_internal", issue = "none")]
#![feature(staged_api, doc_cfg, allow_internal_unstable)]
Expand Down
10 changes: 9 additions & 1 deletion crates/std_detect/tests/cpu-detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![cfg_attr(target_arch = "aarch64", feature(stdarch_aarch64_feature_detection))]
#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))]
#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))]
#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))]
#![cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
feature(sha512_sm_x86, x86_amx_intrinsics, xop_target_feature)
Expand All @@ -18,7 +19,8 @@
target_arch = "x86",
target_arch = "x86_64",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
),
macro_use
)]
Expand Down Expand Up @@ -240,6 +242,12 @@ fn powerpc64_linux_or_freebsd() {
println!("power8: {}", is_powerpc64_feature_detected!("power8"));
}

#[test]
#[cfg(all(target_arch = "s390x", target_os = "linux",))]
fn s390x_linux() {
println!("vector: {}", is_s390x_feature_detected!("vector"));
}

#[test]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn x86_all() {
Expand Down
14 changes: 12 additions & 2 deletions crates/std_detect/tests/macro_trailing_commas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
target_arch = "x86",
target_arch = "x86_64",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
),
feature(stdarch_internal)
)]
#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))]
#![cfg_attr(target_arch = "aarch64", feature(stdarch_aarch64_feature_detection))]
#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))]
#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))]
#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))]
#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)]

#[cfg(any(
Expand All @@ -24,7 +26,8 @@
target_arch = "x86",
target_arch = "x86_64",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_arch = "s390x",
))]
#[macro_use]
extern crate std_detect;
Expand Down Expand Up @@ -60,6 +63,13 @@ fn powerpc64_linux() {
let _ = is_powerpc64_feature_detected!("altivec",);
}

#[test]
#[cfg(all(target_arch = "s390x", target_os = "linux"))]
fn s390x_linux() {
let _ = is_s390x_feature_detected!("vector");
let _ = is_s390x_feature_detected!("vector",);
}

#[test]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn x86_all() {
Expand Down

0 comments on commit 225e1ec

Please sign in to comment.