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

add is_s390x_feature_detected #1699

Merged
merged 1 commit into from
Jan 16, 2025
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
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
Loading