Skip to content

Commit 70eb1da

Browse files
committed
add is_s390x_feature_detected
1 parent b04d87c commit 70eb1da

File tree

10 files changed

+158
-15
lines changed

10 files changed

+158
-15
lines changed

crates/std_detect/README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The private `std::detect` module implements run-time feature detection in Rust's
55
standard library. This allows detecting whether the CPU the binary runs on
66
supports certain features, like SIMD instructions.
77

8-
# Usage
8+
# Usage
99

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

2424
# Features
2525

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

5555
* Linux/Android:
56-
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`: `std_detect`
57-
supports these on Linux by querying ELF auxiliary vectors (using `getauxval`
56+
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`, `s390x`:
57+
`std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval`
5858
when available), and if that fails, by querying `/proc/cpuinfo`.
5959
* `arm64`: partial support for doing run-time feature detection by directly
6060
querying `mrs` is implemented for Linux >= 4.11, but not enabled by default.

crates/std_detect/src/detect/arch/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ mod mips;
2121
mod mips64;
2222
#[macro_use]
2323
mod loongarch;
24+
#[macro_use]
25+
mod s390x;
2426

2527
cfg_if! {
2628
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
@@ -50,6 +52,9 @@ cfg_if! {
5052
} else if #[cfg(target_arch = "loongarch64")] {
5153
#[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")]
5254
pub use loongarch::*;
55+
} else if #[cfg(target_arch = "s390x")] {
56+
#[unstable(feature = "stdarch_s390x_feature_detection", issue = "130869")]
57+
pub use s390x::*;
5358
} else {
5459
// Unimplemented architecture:
5560
#[doc(hidden)]
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Run-time feature detection on s390x.
2+
3+
features! {
4+
@TARGET: s390x;
5+
@CFG: target_arch = "s390x";
6+
@MACRO_NAME: is_s390x_feature_detected;
7+
@MACRO_ATTRS:
8+
/// Checks if `s390x` feature is enabled.
9+
#[unstable(feature = "stdarch_s390x_feature_detection", issue = "130869")]
10+
@FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "130869")] vector: "vector";
11+
/// s390x vector facility
12+
}

crates/std_detect/src/detect/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
101101
target_arch = "mips",
102102
target_arch = "mips64",
103103
target_arch = "loongarch64",
104+
target_arch = "s390x",
104105
))] {
105106
(0_u8..Feature::_last as u8).map(|discriminant: u8| {
106107
#[allow(bindings_with_variant_name)] // RISC-V has Feature::f

crates/std_detect/src/detect/os/linux/auxvec.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ pub(crate) const AT_HWCAP: usize = 16;
1010
target_arch = "aarch64",
1111
target_arch = "arm",
1212
target_arch = "powerpc",
13-
target_arch = "powerpc64"
13+
target_arch = "powerpc64",
14+
target_arch = "s390x",
1415
))]
1516
pub(crate) const AT_HWCAP2: usize = 26;
1617

@@ -26,7 +27,8 @@ pub(crate) struct AuxVec {
2627
target_arch = "aarch64",
2728
target_arch = "arm",
2829
target_arch = "powerpc",
29-
target_arch = "powerpc64"
30+
target_arch = "powerpc64",
31+
target_arch = "s390x",
3032
))]
3133
pub hwcap2: usize,
3234
}
@@ -98,7 +100,8 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
98100
target_arch = "aarch64",
99101
target_arch = "arm",
100102
target_arch = "powerpc",
101-
target_arch = "powerpc64"
103+
target_arch = "powerpc64",
104+
target_arch = "s390x",
102105
))]
103106
{
104107
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
@@ -146,7 +149,8 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
146149
target_arch = "aarch64",
147150
target_arch = "arm",
148151
target_arch = "powerpc",
149-
target_arch = "powerpc64"
152+
target_arch = "powerpc64",
153+
target_arch = "s390x",
150154
))]
151155
{
152156
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, ()> {
242246
target_arch = "aarch64",
243247
target_arch = "arm",
244248
target_arch = "powerpc",
245-
target_arch = "powerpc64"
249+
target_arch = "powerpc64",
250+
target_arch = "s390x",
246251
))]
247252
{
248253
let mut hwcap = None;
@@ -275,7 +280,8 @@ mod tests {
275280
#[cfg(any(
276281
target_arch = "arm",
277282
target_arch = "powerpc",
278-
target_arch = "powerpc64"
283+
target_arch = "powerpc64",
284+
target_arch = "s390x",
279285
))]
280286
#[test]
281287
fn auxv_crate() {
@@ -290,7 +296,8 @@ mod tests {
290296
target_arch = "aarch64",
291297
target_arch = "arm",
292298
target_arch = "powerpc",
293-
target_arch = "powerpc64"
299+
target_arch = "powerpc64",
300+
target_arch = "s390x",
294301
))]
295302
{
296303
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
@@ -365,7 +372,8 @@ mod tests {
365372
target_arch = "aarch64",
366373
target_arch = "arm",
367374
target_arch = "powerpc",
368-
target_arch = "powerpc64"
375+
target_arch = "powerpc64",
376+
target_arch = "s390x",
369377
))]
370378
#[test]
371379
#[cfg(feature = "std_detect_file_io")]

crates/std_detect/src/detect/os/linux/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ cfg_if::cfg_if! {
5757
} else if #[cfg(target_arch = "loongarch64")] {
5858
mod loongarch;
5959
pub(crate) use self::loongarch::detect_features;
60+
} else if #[cfg(target_arch = "s390x")] {
61+
mod s390x;
62+
pub(crate) use self::s390x::detect_features;
6063
} else {
6164
use crate::detect::cache;
6265
/// Performs run-time feature detection.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! Run-time feature detection for s390x on Linux.
2+
3+
use super::auxvec;
4+
use crate::detect::{bit, cache, Feature};
5+
6+
/// Try to read the features from the auxiliary vector
7+
pub(crate) fn detect_features() -> cache::Initializer {
8+
if let Ok(auxv) = auxvec::auxv() {
9+
let hwcap: AtHwcap = auxv.into();
10+
return hwcap.cache();
11+
}
12+
13+
cache::Initializer::default()
14+
}
15+
16+
/// These values are part of the platform-specific [asm/elf.h][kernel], and are a selection of the
17+
/// fields found in the [Facility Indications].
18+
///
19+
/// [Facility Indications]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf#page=63
20+
/// [kernel]: https://github.com/torvalds/linux/blob/b62cef9a5c673f1b8083159f5dc03c1c5daced2f/arch/s390/include/asm/elf.h#L129
21+
#[derive(Debug, Default, PartialEq)]
22+
struct AtHwcap {
23+
esan3: bool,
24+
zarch: bool,
25+
stfle: bool,
26+
msa: bool,
27+
ldisp: bool,
28+
eimm: bool,
29+
dfp: bool,
30+
hpage: bool,
31+
etf3eh: bool,
32+
high_gprs: bool,
33+
te: bool,
34+
vxrs: bool,
35+
vxrs_bcd: bool,
36+
vxrs_ext: bool,
37+
gs: bool,
38+
vxrs_ext2: bool,
39+
vxrs_pde: bool,
40+
sort: bool,
41+
dflt: bool,
42+
vxrs_pde2: bool,
43+
nnpa: bool,
44+
pci_mio: bool,
45+
sie: bool,
46+
}
47+
48+
impl From<auxvec::AuxVec> for AtHwcap {
49+
/// Reads AtHwcap from the auxiliary vector.
50+
fn from(auxv: auxvec::AuxVec) -> Self {
51+
AtHwcap {
52+
esan3: bit::test(auxv.hwcap, 0),
53+
zarch: bit::test(auxv.hwcap, 1),
54+
stfle: bit::test(auxv.hwcap, 2),
55+
msa: bit::test(auxv.hwcap, 3),
56+
ldisp: bit::test(auxv.hwcap, 4),
57+
eimm: bit::test(auxv.hwcap, 5),
58+
dfp: bit::test(auxv.hwcap, 6),
59+
hpage: bit::test(auxv.hwcap, 7),
60+
etf3eh: bit::test(auxv.hwcap, 8),
61+
high_gprs: bit::test(auxv.hwcap, 9),
62+
te: bit::test(auxv.hwcap, 10),
63+
vxrs: bit::test(auxv.hwcap, 11),
64+
vxrs_bcd: bit::test(auxv.hwcap, 12),
65+
vxrs_ext: bit::test(auxv.hwcap, 13),
66+
gs: bit::test(auxv.hwcap, 14),
67+
vxrs_ext2: bit::test(auxv.hwcap, 15),
68+
vxrs_pde: bit::test(auxv.hwcap, 16),
69+
sort: bit::test(auxv.hwcap, 17),
70+
dflt: bit::test(auxv.hwcap, 18),
71+
vxrs_pde2: bit::test(auxv.hwcap, 19),
72+
nnpa: bit::test(auxv.hwcap, 20),
73+
pci_mio: bit::test(auxv.hwcap, 21),
74+
sie: bit::test(auxv.hwcap, 22),
75+
}
76+
}
77+
}
78+
79+
impl AtHwcap {
80+
/// Initializes the cache from the feature bits.
81+
fn cache(self) -> cache::Initializer {
82+
let mut value = cache::Initializer::default();
83+
{
84+
let mut enable_feature = |f, enable| {
85+
if enable {
86+
value.set(f as u32);
87+
}
88+
};
89+
90+
// bit 129 of the extended facility list
91+
enable_feature(Feature::vector, self.vxrs);
92+
}
93+
value
94+
}
95+
}

crates/std_detect/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! * `powerpc`: [`is_powerpc_feature_detected`]
1313
//! * `powerpc64`: [`is_powerpc64_feature_detected`]
1414
//! * `loongarch`: [`is_loongarch_feature_detected`]
15+
//! * `s390x`: [`is_s390x_feature_detected`]
1516
1617
#![unstable(feature = "stdarch_internal", issue = "none")]
1718
#![feature(staged_api, doc_cfg, allow_internal_unstable)]

crates/std_detect/tests/cpu-detection.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![cfg_attr(target_arch = "aarch64", feature(stdarch_aarch64_feature_detection))]
55
#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))]
66
#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))]
7+
#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))]
78
#![cfg_attr(
89
any(target_arch = "x86", target_arch = "x86_64"),
910
feature(sha512_sm_x86, x86_amx_intrinsics, xop_target_feature)
@@ -18,7 +19,8 @@
1819
target_arch = "x86",
1920
target_arch = "x86_64",
2021
target_arch = "powerpc",
21-
target_arch = "powerpc64"
22+
target_arch = "powerpc64",
23+
target_arch = "s390x",
2224
),
2325
macro_use
2426
)]
@@ -240,6 +242,12 @@ fn powerpc64_linux_or_freebsd() {
240242
println!("power8: {}", is_powerpc64_feature_detected!("power8"));
241243
}
242244

245+
#[test]
246+
#[cfg(all(target_arch = "s390x", target_os = "linux",))]
247+
fn s390x_linux() {
248+
println!("vector: {}", is_s390x_feature_detected!("vector"));
249+
}
250+
243251
#[test]
244252
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
245253
fn x86_all() {

crates/std_detect/tests/macro_trailing_commas.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
target_arch = "x86",
88
target_arch = "x86_64",
99
target_arch = "powerpc",
10-
target_arch = "powerpc64"
10+
target_arch = "powerpc64",
11+
target_arch = "s390x",
1112
),
1213
feature(stdarch_internal)
1314
)]
1415
#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))]
1516
#![cfg_attr(target_arch = "aarch64", feature(stdarch_aarch64_feature_detection))]
1617
#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))]
1718
#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))]
19+
#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))]
1820
#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)]
1921

2022
#[cfg(any(
@@ -24,7 +26,8 @@
2426
target_arch = "x86",
2527
target_arch = "x86_64",
2628
target_arch = "powerpc",
27-
target_arch = "powerpc64"
29+
target_arch = "powerpc64",
30+
target_arch = "s390x",
2831
))]
2932
#[macro_use]
3033
extern crate std_detect;
@@ -60,6 +63,13 @@ fn powerpc64_linux() {
6063
let _ = is_powerpc64_feature_detected!("altivec",);
6164
}
6265

66+
#[test]
67+
#[cfg(all(target_arch = "s390x", target_os = "linux"))]
68+
fn s390x_linux() {
69+
let _ = is_s390x_feature_detected!("vector");
70+
let _ = is_s390x_feature_detected!("vector",);
71+
}
72+
6373
#[test]
6474
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
6575
fn x86_all() {

0 commit comments

Comments
 (0)