Skip to content

add is_s390x_feature_detected #1699

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

Merged
merged 1 commit into from
Jan 16, 2025
Merged
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
8 changes: 4 additions & 4 deletions crates/std_detect/README.md
Original file line number Diff line number Diff line change
@@ -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
@@ -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

@@ -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.
5 changes: 5 additions & 0 deletions crates/std_detect/src/detect/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -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"))] {
@@ -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)]
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
@@ -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
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
@@ -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;

@@ -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,
}
@@ -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) {
@@ -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 };
@@ -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;
@@ -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() {
@@ -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) {
@@ -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")]
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
@@ -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.
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
@@ -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)]
10 changes: 9 additions & 1 deletion crates/std_detect/tests/cpu-detection.rs
Original file line number Diff line number Diff line change
@@ -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)
@@ -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
)]
@@ -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() {
14 changes: 12 additions & 2 deletions crates/std_detect/tests/macro_trailing_commas.rs
Original file line number Diff line number Diff line change
@@ -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(
@@ -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;
@@ -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() {