about summary refs log tree commit diff
path: root/library/stdarch/crates/std_detect
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-01-12 17:35:47 +0100
committerAmanieu d'Antras <amanieu@gmail.com>2025-01-16 20:39:13 +0000
commitb5babcfac28a61f7308e02333a195ad7e4249af8 (patch)
treee932df486d574ba6fb25a35ecc443ee9891bfa3a /library/stdarch/crates/std_detect
parenta1be13aeeb56b92beccd7f40f34c9531fe35249c (diff)
downloadrust-b5babcfac28a61f7308e02333a195ad7e4249af8.tar.gz
rust-b5babcfac28a61f7308e02333a195ad7e4249af8.zip
add `is_s390x_feature_detected`
Diffstat (limited to 'library/stdarch/crates/std_detect')
-rw-r--r--library/stdarch/crates/std_detect/README.md8
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/mod.rs5
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/s390x.rs12
-rw-r--r--library/stdarch/crates/std_detect/src/detect/mod.rs1
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs24
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs3
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs95
-rw-r--r--library/stdarch/crates/std_detect/src/lib.rs1
-rw-r--r--library/stdarch/crates/std_detect/tests/cpu-detection.rs10
-rw-r--r--library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs14
10 files changed, 158 insertions, 15 deletions
diff --git a/library/stdarch/crates/std_detect/README.md b/library/stdarch/crates/std_detect/README.md
index 04bc6a665e7..b9146d42c9e 100644
--- a/library/stdarch/crates/std_detect/README.md
+++ b/library/stdarch/crates/std_detect/README.md
@@ -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.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mod.rs b/library/stdarch/crates/std_detect/src/detect/arch/mod.rs
index d0f5fab7491..ff00c202dea 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mod.rs
@@ -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)]
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs b/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs
new file mode 100644
index 00000000000..be62aeb96ac
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs
@@ -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
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs
index ab247a303ed..a61400a5553 100644
--- a/library/stdarch/crates/std_detect/src/detect/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/mod.rs
@@ -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
diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs
index 61b6e2df1ac..79720a0dee0 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs
@@ -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")]
diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs
index 30577385200..fbe6bea93c9 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs
@@ -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.
diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs
new file mode 100644
index 00000000000..91ce55e94e3
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs
@@ -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
+    }
+}
diff --git a/library/stdarch/crates/std_detect/src/lib.rs b/library/stdarch/crates/std_detect/src/lib.rs
index 881e12cf9c3..ab1b77bad5b 100644
--- a/library/stdarch/crates/std_detect/src/lib.rs
+++ b/library/stdarch/crates/std_detect/src/lib.rs
@@ -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)]
diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
index 6ed612a5960..69b7075bb10 100644
--- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs
+++ b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
@@ -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
 )]
@@ -241,6 +243,12 @@ fn powerpc64_linux_or_freebsd() {
 }
 
 #[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() {
     println!("aes: {:?}", is_x86_feature_detected!("aes"));
diff --git a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs b/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs
index 9f6ef074d00..4769a5e3185 100644
--- a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs
+++ b/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs
@@ -7,7 +7,8 @@
         target_arch = "x86",
         target_arch = "x86_64",
         target_arch = "powerpc",
-        target_arch = "powerpc64"
+        target_arch = "powerpc64",
+        target_arch = "s390x",
     ),
     feature(stdarch_internal)
 )]
@@ -15,6 +16,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))]
 #![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;
@@ -61,6 +64,13 @@ fn powerpc64_linux() {
 }
 
 #[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() {
     let _ = is_x86_feature_detected!("sse");