Skip to content

Commit 6a43d3c

Browse files
Rollup merge of rust-lang#155856 - imazen:winarm-stable-features, r=Amanieu
std_detect: support detecting more features on aarch64 Windows Wires `IsProcessorFeaturePresent` calls for the `PF_ARM_*` constants exposed in Windows SDK 26100 (Windows 11 24H2), plus an architectural derivation for `rdm`. All eight feature names have been stable in `is_aarch64_feature_detected!` on Linux/Darwin/BSD since Rust 1.60 — this brings the Windows backend to parity. | Feature | Source on Windows | |---|---| | `fp16` | `PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE` (value 67) | | `i8mm` | `PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE` (value 66) | | `bf16` | `PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE` (value 68) | | `sha3` | `PF_ARM_SHA3` (value 64) **AND** `PF_ARM_SHA512` (value 65) | | `lse2` | `PF_ARM_LSE2_AVAILABLE` (value 62) | | `f32mm` | `PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE` (value 58) | | `f64mm` | `PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE` (value 59) | | `rdm` | derived from `PF_ARM_V82_DP` (see below) | `PF_ARM_SVE_F32MM` / `PF_ARM_SVE_F64MM` (values 58 / 59) were already added as commented-out placeholders in rust-lang/stdarch#1749 — they have direct stable Feature mappings (`f32mm`, `f64mm`), unlike their sibling values 52 / 53 / 57 (`SVE_BF16`, `SVE_EBF16`, `SVE_I8MM`) which have no SVE-specific stdarch Feature name and remain commented for that reason. `sha3` requires both `PF_ARM_SHA3` (FEAT_SHA3) and `PF_ARM_SHA512` (FEAT_SHA512), matching the existing convention from rust-lang/stdarch#1749 where `sve2-aes` is set only when both `PF_ARM_SVE_AES` and `PF_ARM_SVE_PMULL128` are present. ### `rdm` derivation There is no `PF_ARM_RDM_*` constant; Microsoft has never defined one. We derive it from `PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE` (FEAT_DotProd) via the following architectural chain: 1. FEAT_DotProd is an optional v8.2-A feature, so its presence implies the core implements at least v8.1-A. 2. Per Arm ARM K.a §D17.2.91: *"In an ARMv8.1 implementation, if FEAT_AdvSIMD is implemented, FEAT_RDM is implemented."* 3. AdvSIMD is universally implemented on every Windows-on-ARM SKU. 4. Therefore: DotProd ⇒ v8.1-A baseline + AdvSIMD ⇒ FEAT_RDM. This is the same derivation .NET 10 uses, with comment cited verbatim ([dotnet/runtime PR 109493](dotnet/runtime#109493), shipped in v10.0.0 at [`src/native/minipal/cpufeatures.c`](https://github.com/dotnet/runtime/blob/v10.0.0/src/native/minipal/cpufeatures.c)): > *"IsProcessorFeaturePresent does not have a dedicated flag for RDM, so we enable it by implication. > 1) DP is an optional instruction set for Armv8.2, which may be included only in processors implementing at least Armv8.1. > 2) Armv8.1 requires RDM when AdvSIMD is implemented, and AdvSIMD is a baseline requirement of .NET. > Therefore, by documented standard, DP cannot exist here without RDM. In practice, there is only one CPU supported by Windows that includes RDM without DP, so this implication also has little practical chance of a false negative."* The "one CPU with RDM without DP" trade-off applies equally to us: we accept a possible false negative on that single SKU rather than introducing a more aggressive heuristic. ### Tests Adds `println!` lines to the existing `aarch64_windows()` test in `library/std_detect/tests/cpu-detection.rs` for each newly-detected feature, mirroring the existing single-line pattern. No structural assertions added. ### Scope Stable feature names only. The unstable SME family (`sme`, `sme2`, `sme2p1`, `sme_*`, `ssve_fp8*`) and other unstable additions tracked under rust-lang#127764 are intentionally out of scope here to keep this PR minimal — happy to do a follow-up. ### References - Tracking issue: rust-lang#127764 (`stdarch_aarch64_feature_detection`) - Precedent: rust-lang/stdarch#1749 (taiki-e, merged 2025-03-24) — added the SVE constants this builds on - MS docs: [`IsProcessorFeaturePresent`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent) — full PF_ARM_* table r? @Amanieu cc @taiki-e (author of rust-lang/stdarch#1749, would appreciate your eyes on the `rdm` inference) @rustbot label +T-libs +O-windows +O-ARM
2 parents 271cbc6 + f0a751d commit 6a43d3c

2 files changed

Lines changed: 61 additions & 5 deletions

File tree

library/std_detect/src/detect/os/windows/aarch64.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ pub(crate) fn detect_features() -> cache::Initializer {
3131
const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55;
3232
const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56;
3333
// const PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 57;
34-
// const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58;
35-
// const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59;
34+
const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58;
35+
const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59;
36+
const PF_ARM_LSE2_AVAILABLE: u32 = 62;
37+
const PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 64;
38+
const PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE: u32 = 65;
39+
const PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 66;
40+
const PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE: u32 = 67;
41+
const PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE: u32 = 68;
3642

3743
unsafe extern "system" {
3844
fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL;
@@ -46,9 +52,11 @@ pub(crate) fn detect_features() -> cache::Initializer {
4652
}
4753
};
4854

49-
// Some features may be supported on current CPU,
50-
// but no way to detect it by OS API.
51-
// Also, we require unsafe block for the extern "system" calls.
55+
// Some features may be supported on the current CPU but have no
56+
// detection path through the Win32 API; those report `false`.
57+
// SAFETY: `IsProcessorFeaturePresent` is a Win32 entry point taking a
58+
// `DWORD` by value and returning a `BOOL`. No pointer parameters,
59+
// no out-parameters, no thread-safety constraints.
5260
unsafe {
5361
enable_feature(
5462
Feature::fp,
@@ -112,6 +120,46 @@ pub(crate) fn detect_features() -> cache::Initializer {
112120
Feature::sve2_sm4,
113121
IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE,
114122
);
123+
enable_feature(
124+
Feature::f32mm,
125+
IsProcessorFeaturePresent(PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE) != FALSE,
126+
);
127+
enable_feature(
128+
Feature::f64mm,
129+
IsProcessorFeaturePresent(PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE) != FALSE,
130+
);
131+
enable_feature(
132+
Feature::lse2,
133+
IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE) != FALSE,
134+
);
135+
enable_feature(
136+
Feature::fp16,
137+
IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) != FALSE,
138+
);
139+
enable_feature(
140+
Feature::i8mm,
141+
IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE) != FALSE,
142+
);
143+
enable_feature(
144+
Feature::bf16,
145+
IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE) != FALSE,
146+
);
147+
// stdarch `sha3` is FEAT_SHA3 + FEAT_SHA512 together; Windows
148+
// exposes them as two separate flags.
149+
enable_feature(
150+
Feature::sha3,
151+
IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE) != FALSE
152+
&& IsProcessorFeaturePresent(PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE) != FALSE,
153+
);
154+
// No PF_ARM_RDM_* constant exists. Derive FEAT_RDM from FEAT_DotProd:
155+
// DotProd is an optional v8.2-A feature only present on cores that
156+
// implement at least v8.1-A; v8.1-A with AdvSIMD mandates FEAT_RDM
157+
// (Arm ARM K.a §D17.2.91), and AdvSIMD is universal on Windows-on-ARM.
158+
// Same inference shipped in .NET 10 (dotnet/runtime PR 109493).
159+
enable_feature(
160+
Feature::rdm,
161+
IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != FALSE,
162+
);
115163
// PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and
116164
// pmull support
117165
let crypto =

library/std_detect/tests/cpu-detection.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,22 @@ fn aarch64_linux() {
150150
fn aarch64_windows() {
151151
println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
152152
println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
153+
println!("fp16: {:?}", is_aarch64_feature_detected!("fp16"));
153154
println!("crc: {:?}", is_aarch64_feature_detected!("crc"));
154155
println!("lse: {:?}", is_aarch64_feature_detected!("lse"));
156+
println!("lse2: {:?}", is_aarch64_feature_detected!("lse2"));
157+
println!("rdm: {:?}", is_aarch64_feature_detected!("rdm"));
155158
println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod"));
159+
println!("i8mm: {:?}", is_aarch64_feature_detected!("i8mm"));
160+
println!("bf16: {:?}", is_aarch64_feature_detected!("bf16"));
156161
println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv"));
157162
println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc"));
158163
println!("aes: {:?}", is_aarch64_feature_detected!("aes"));
159164
println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
160165
println!("sha2: {:?}", is_aarch64_feature_detected!("sha2"));
166+
println!("sha3: {:?}", is_aarch64_feature_detected!("sha3"));
167+
println!("f32mm: {:?}", is_aarch64_feature_detected!("f32mm"));
168+
println!("f64mm: {:?}", is_aarch64_feature_detected!("f64mm"));
161169
}
162170

163171
#[test]

0 commit comments

Comments
 (0)