Skip to main content

std_detect\detect\os\windows/
aarch64.rs

1//! Run-time feature detection for Aarch64 on Windows.
2
3use crate::detect::{Feature, cache};
4
5/// Try to read the features using IsProcessorFeaturePresent.
6pub(crate) fn detect_features() -> cache::Initializer {
7    type DWORD = u32;
8    type BOOL = i32;
9
10    const FALSE: BOOL = 0;
11    // The following Microsoft documents isn't updated for aarch64.
12    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
13    // These are defined in winnt.h of Windows SDK
14    const PF_ARM_VFP_32_REGISTERS_AVAILABLE: u32 = 18;
15    const PF_ARM_NEON_INSTRUCTIONS_AVAILABLE: u32 = 19;
16    const PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE: u32 = 30;
17    const PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE: u32 = 31;
18    const PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE: u32 = 34;
19    const PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE: u32 = 43;
20    const PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE: u32 = 44;
21    const PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE: u32 = 45;
22    const PF_ARM_SVE_INSTRUCTIONS_AVAILABLE: u32 = 46;
23    const PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE: u32 = 47;
24    const PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE: u32 = 48;
25    const PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE: u32 = 49;
26    const PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE: u32 = 50;
27    const PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE: u32 = 51;
28    // const PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE: u32 = 52;
29    // const PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE: u32 = 53;
30    const PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE: u32 = 54;
31    const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55;
32    const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56;
33    // 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;
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;
42
43    unsafe extern "system" {
44        fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL;
45    }
46
47    let mut value = cache::Initializer::default();
48    {
49        let mut enable_feature = |f, enable| {
50            if enable {
51                value.set(f as u32);
52            }
53        };
54
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.
60        unsafe {
61            enable_feature(
62                Feature::fp,
63                IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) != FALSE,
64            );
65            enable_feature(
66                Feature::asimd,
67                IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != FALSE,
68            );
69            enable_feature(
70                Feature::crc,
71                IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != FALSE,
72            );
73            enable_feature(
74                Feature::lse,
75                IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != FALSE,
76            );
77            enable_feature(
78                Feature::dotprod,
79                IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != FALSE,
80            );
81            enable_feature(
82                Feature::jsconv,
83                IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) != FALSE,
84            );
85            enable_feature(
86                Feature::rcpc,
87                IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) != FALSE,
88            );
89            enable_feature(
90                Feature::sve,
91                IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) != FALSE,
92            );
93            enable_feature(
94                Feature::sve2,
95                IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) != FALSE,
96            );
97            enable_feature(
98                Feature::sve2p1,
99                IsProcessorFeaturePresent(PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE) != FALSE,
100            );
101            enable_feature(
102                Feature::sve2_aes,
103                IsProcessorFeaturePresent(PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE) != FALSE
104                    && IsProcessorFeaturePresent(PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE)
105                        != FALSE,
106            );
107            enable_feature(
108                Feature::sve2_bitperm,
109                IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE) != FALSE,
110            );
111            enable_feature(
112                Feature::sve_b16b16,
113                IsProcessorFeaturePresent(PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE) != FALSE,
114            );
115            enable_feature(
116                Feature::sve2_sha3,
117                IsProcessorFeaturePresent(PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE) != FALSE,
118            );
119            enable_feature(
120                Feature::sve2_sm4,
121                IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE,
122            );
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            );
163            // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and
164            // pmull support
165            let crypto =
166                IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != FALSE;
167            enable_feature(Feature::aes, crypto);
168            enable_feature(Feature::pmull, crypto);
169            enable_feature(Feature::sha2, crypto);
170        }
171    }
172    value
173}