]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | //! Run-time feature detection for Aarch64 on Linux. |
2 | ||
cdc7bbd5 | 3 | use super::auxvec; |
74b04a01 | 4 | use crate::detect::{bit, cache, Feature}; |
83c7162d XL |
5 | |
6 | /// Try to read the features from the auxiliary vector, and if that fails, try | |
7 | /// to read them from /proc/cpuinfo. | |
74b04a01 | 8 | pub(crate) fn detect_features() -> cache::Initializer { |
83c7162d XL |
9 | if let Ok(auxv) = auxvec::auxv() { |
10 | let hwcap: AtHwcap = auxv.into(); | |
11 | return hwcap.cache(); | |
12 | } | |
cdc7bbd5 XL |
13 | #[cfg(feature = "std_detect_file_io")] |
14 | if let Ok(c) = super::cpuinfo::CpuInfo::new() { | |
83c7162d XL |
15 | let hwcap: AtHwcap = c.into(); |
16 | return hwcap.cache(); | |
17 | } | |
18 | cache::Initializer::default() | |
19 | } | |
20 | ||
21 | /// These values are part of the platform-specific [asm/hwcap.h][hwcap] . | |
22 | /// | |
17df50a5 XL |
23 | /// The names match those used for cpuinfo. |
24 | /// | |
83c7162d XL |
25 | /// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h |
26 | struct AtHwcap { | |
74b04a01 | 27 | fp: bool, // 0 |
83c7162d | 28 | asimd: bool, // 1 |
17df50a5 | 29 | // evtstrm: bool, // 2 No LLVM support |
74b04a01 XL |
30 | aes: bool, // 3 |
31 | pmull: bool, // 4 | |
32 | sha1: bool, // 5 | |
33 | sha2: bool, // 6 | |
34 | crc32: bool, // 7 | |
83c7162d | 35 | atomics: bool, // 8 |
74b04a01 | 36 | fphp: bool, // 9 |
83c7162d | 37 | asimdhp: bool, // 10 |
17df50a5 | 38 | // cpuid: bool, // 11 No LLVM support |
83c7162d | 39 | asimdrdm: bool, // 12 |
17df50a5 XL |
40 | jscvt: bool, // 13 |
41 | fcma: bool, // 14 | |
42 | lrcpc: bool, // 15 | |
43 | dcpop: bool, // 16 | |
44 | sha3: bool, // 17 | |
45 | sm3: bool, // 18 | |
46 | sm4: bool, // 19 | |
47 | asimddp: bool, // 20 | |
48 | sha512: bool, // 21 | |
49 | sve: bool, // 22 | |
50 | fhm: bool, // 23 | |
51 | dit: bool, // 24 | |
52 | uscat: bool, // 25 | |
53 | ilrcpc: bool, // 26 | |
54 | flagm: bool, // 27 | |
55 | ssbs: bool, // 28 | |
56 | sb: bool, // 29 | |
57 | paca: bool, // 30 | |
58 | pacg: bool, // 31 | |
59 | dcpodp: bool, // 32 | |
60 | sve2: bool, // 33 | |
61 | sveaes: bool, // 34 | |
62 | // svepmull: bool, // 35 No LLVM support | |
63 | svebitperm: bool, // 36 | |
64 | svesha3: bool, // 37 | |
65 | svesm4: bool, // 38 | |
66 | // flagm2: bool, // 39 No LLVM support | |
67 | frint: bool, // 40 | |
68 | // svei8mm: bool, // 41 See i8mm feature | |
69 | svef32mm: bool, // 42 | |
70 | svef64mm: bool, // 43 | |
71 | // svebf16: bool, // 44 See bf16 feature | |
72 | i8mm: bool, // 45 | |
73 | bf16: bool, // 46 | |
74 | // dgh: bool, // 47 No LLVM support | |
75 | rng: bool, // 48 | |
76 | bti: bool, // 49 | |
77 | mte: bool, // 50 | |
83c7162d XL |
78 | } |
79 | ||
80 | impl From<auxvec::AuxVec> for AtHwcap { | |
81 | /// Reads AtHwcap from the auxiliary vector. | |
82 | fn from(auxv: auxvec::AuxVec) -> Self { | |
83 | AtHwcap { | |
84 | fp: bit::test(auxv.hwcap, 0), | |
85 | asimd: bit::test(auxv.hwcap, 1), | |
86 | // evtstrm: bit::test(auxv.hwcap, 2), | |
87 | aes: bit::test(auxv.hwcap, 3), | |
88 | pmull: bit::test(auxv.hwcap, 4), | |
89 | sha1: bit::test(auxv.hwcap, 5), | |
90 | sha2: bit::test(auxv.hwcap, 6), | |
91 | crc32: bit::test(auxv.hwcap, 7), | |
92 | atomics: bit::test(auxv.hwcap, 8), | |
93 | fphp: bit::test(auxv.hwcap, 9), | |
94 | asimdhp: bit::test(auxv.hwcap, 10), | |
95 | // cpuid: bit::test(auxv.hwcap, 11), | |
96 | asimdrdm: bit::test(auxv.hwcap, 12), | |
17df50a5 XL |
97 | jscvt: bit::test(auxv.hwcap, 13), |
98 | fcma: bit::test(auxv.hwcap, 14), | |
83c7162d | 99 | lrcpc: bit::test(auxv.hwcap, 15), |
17df50a5 XL |
100 | dcpop: bit::test(auxv.hwcap, 16), |
101 | sha3: bit::test(auxv.hwcap, 17), | |
102 | sm3: bit::test(auxv.hwcap, 18), | |
103 | sm4: bit::test(auxv.hwcap, 19), | |
83c7162d | 104 | asimddp: bit::test(auxv.hwcap, 20), |
17df50a5 | 105 | sha512: bit::test(auxv.hwcap, 21), |
83c7162d | 106 | sve: bit::test(auxv.hwcap, 22), |
17df50a5 XL |
107 | fhm: bit::test(auxv.hwcap, 23), |
108 | dit: bit::test(auxv.hwcap, 24), | |
109 | uscat: bit::test(auxv.hwcap, 25), | |
110 | ilrcpc: bit::test(auxv.hwcap, 26), | |
111 | flagm: bit::test(auxv.hwcap, 27), | |
112 | ssbs: bit::test(auxv.hwcap, 28), | |
113 | sb: bit::test(auxv.hwcap, 29), | |
114 | paca: bit::test(auxv.hwcap, 30), | |
115 | pacg: bit::test(auxv.hwcap, 31), | |
116 | dcpodp: bit::test(auxv.hwcap, 32), | |
117 | sve2: bit::test(auxv.hwcap, 33), | |
118 | sveaes: bit::test(auxv.hwcap, 34), | |
119 | // svepmull: bit::test(auxv.hwcap, 35), | |
120 | svebitperm: bit::test(auxv.hwcap, 36), | |
121 | svesha3: bit::test(auxv.hwcap, 37), | |
122 | svesm4: bit::test(auxv.hwcap, 38), | |
123 | // flagm2: bit::test(auxv.hwcap, 39), | |
124 | frint: bit::test(auxv.hwcap, 40), | |
125 | // svei8mm: bit::test(auxv.hwcap, 41), | |
126 | svef32mm: bit::test(auxv.hwcap, 42), | |
127 | svef64mm: bit::test(auxv.hwcap, 43), | |
128 | // svebf16: bit::test(auxv.hwcap, 44), | |
129 | i8mm: bit::test(auxv.hwcap, 45), | |
130 | bf16: bit::test(auxv.hwcap, 46), | |
131 | // dgh: bit::test(auxv.hwcap, 47), | |
132 | rng: bit::test(auxv.hwcap, 48), | |
133 | bti: bit::test(auxv.hwcap, 49), | |
134 | mte: bit::test(auxv.hwcap, 50), | |
83c7162d XL |
135 | } |
136 | } | |
137 | } | |
138 | ||
cdc7bbd5 XL |
139 | #[cfg(feature = "std_detect_file_io")] |
140 | impl From<super::cpuinfo::CpuInfo> for AtHwcap { | |
83c7162d | 141 | /// Reads AtHwcap from /proc/cpuinfo . |
cdc7bbd5 | 142 | fn from(c: super::cpuinfo::CpuInfo) -> Self { |
83c7162d XL |
143 | let f = &c.field("Features"); |
144 | AtHwcap { | |
145 | // 64-bit names. FIXME: In 32-bit compatibility mode /proc/cpuinfo will | |
146 | // map some of the 64-bit names to some 32-bit feature names. This does not | |
147 | // cover that yet. | |
148 | fp: f.has("fp"), | |
149 | asimd: f.has("asimd"), | |
150 | // evtstrm: f.has("evtstrm"), | |
151 | aes: f.has("aes"), | |
152 | pmull: f.has("pmull"), | |
153 | sha1: f.has("sha1"), | |
154 | sha2: f.has("sha2"), | |
155 | crc32: f.has("crc32"), | |
156 | atomics: f.has("atomics"), | |
157 | fphp: f.has("fphp"), | |
158 | asimdhp: f.has("asimdhp"), | |
159 | // cpuid: f.has("cpuid"), | |
160 | asimdrdm: f.has("asimdrdm"), | |
17df50a5 XL |
161 | jscvt: f.has("jscvt"), |
162 | fcma: f.has("fcma"), | |
83c7162d | 163 | lrcpc: f.has("lrcpc"), |
17df50a5 XL |
164 | dcpop: f.has("dcpop"), |
165 | sha3: f.has("sha3"), | |
166 | sm3: f.has("sm3"), | |
167 | sm4: f.has("sm4"), | |
83c7162d | 168 | asimddp: f.has("asimddp"), |
17df50a5 | 169 | sha512: f.has("sha512"), |
83c7162d | 170 | sve: f.has("sve"), |
17df50a5 XL |
171 | fhm: f.has("asimdfhm"), |
172 | dit: f.has("dit"), | |
173 | uscat: f.has("uscat"), | |
174 | ilrcpc: f.has("ilrcpc"), | |
175 | flagm: f.has("flagm"), | |
176 | ssbs: f.has("ssbs"), | |
177 | sb: f.has("sb"), | |
178 | paca: f.has("paca"), | |
179 | pacg: f.has("pacg"), | |
180 | dcpodp: f.has("dcpodp"), | |
181 | sve2: f.has("sve2"), | |
182 | sveaes: f.has("sveaes"), | |
183 | // svepmull: f.has("svepmull"), | |
184 | svebitperm: f.has("svebitperm"), | |
185 | svesha3: f.has("svesha3"), | |
186 | svesm4: f.has("svesm4"), | |
187 | // flagm2: f.has("flagm2"), | |
188 | frint: f.has("frint"), | |
189 | // svei8mm: f.has("svei8mm"), | |
190 | svef32mm: f.has("svef32mm"), | |
191 | svef64mm: f.has("svef64mm"), | |
192 | // svebf16: f.has("svebf16"), | |
193 | i8mm: f.has("i8mm"), | |
194 | bf16: f.has("bf16"), | |
195 | // dgh: f.has("dgh"), | |
196 | rng: f.has("rng"), | |
197 | bti: f.has("bti"), | |
198 | mte: f.has("mte"), | |
83c7162d XL |
199 | } |
200 | } | |
201 | } | |
202 | ||
203 | impl AtHwcap { | |
204 | /// Initializes the cache from the feature -bits. | |
205 | /// | |
17df50a5 XL |
206 | /// The feature dependencies here come directly from LLVM's feature definintions: |
207 | /// https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64.td | |
8faf50e0 | 208 | fn cache(self) -> cache::Initializer { |
83c7162d XL |
209 | let mut value = cache::Initializer::default(); |
210 | { | |
211 | let mut enable_feature = |f, enable| { | |
212 | if enable { | |
213 | value.set(f as u32); | |
214 | } | |
215 | }; | |
216 | ||
217 | enable_feature(Feature::fp, self.fp); | |
218 | // Half-float support requires float support | |
219 | enable_feature(Feature::fp16, self.fp && self.fphp); | |
17df50a5 XL |
220 | // FHM (fp16fml in LLVM) requires half float support |
221 | enable_feature(Feature::fhm, self.fphp && self.fhm); | |
83c7162d XL |
222 | enable_feature(Feature::pmull, self.pmull); |
223 | enable_feature(Feature::crc, self.crc32); | |
224 | enable_feature(Feature::lse, self.atomics); | |
17df50a5 | 225 | enable_feature(Feature::lse2, self.uscat); |
83c7162d | 226 | enable_feature(Feature::rcpc, self.lrcpc); |
17df50a5 XL |
227 | // RCPC2 (rcpc-immo in LLVM) requires RCPC support |
228 | enable_feature(Feature::rcpc2, self.ilrcpc && self.lrcpc); | |
229 | enable_feature(Feature::dit, self.dit); | |
230 | enable_feature(Feature::flagm, self.flagm); | |
231 | enable_feature(Feature::ssbs, self.ssbs); | |
232 | enable_feature(Feature::sb, self.sb); | |
233 | // FEAT_PAuth provides both paca & pacg | |
234 | enable_feature(Feature::pauth, self.paca && self.pacg); | |
235 | enable_feature(Feature::dpb, self.dcpop); | |
236 | enable_feature(Feature::dpb2, self.dcpodp); | |
237 | enable_feature(Feature::rand, self.rng); | |
238 | enable_feature(Feature::bti, self.bti); | |
239 | enable_feature(Feature::mte, self.mte); | |
240 | // jsconv requires float support | |
241 | enable_feature(Feature::jsconv, self.jscvt && self.fp); | |
242 | enable_feature(Feature::rdm, self.asimdrdm); | |
243 | enable_feature(Feature::dotprod, self.asimddp); | |
244 | enable_feature(Feature::frintts, self.frint); | |
245 | ||
246 | // FEAT_I8MM & FEAT_BF16 also include optional SVE components which linux exposes | |
247 | // separately. We ignore that distinction here. | |
248 | enable_feature(Feature::i8mm, self.i8mm); | |
249 | enable_feature(Feature::bf16, self.bf16); | |
83c7162d | 250 | |
17df50a5 | 251 | // ASIMD support requires float support - if half-floats are |
83c7162d XL |
252 | // supported, it also requires half-float support: |
253 | let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); | |
254 | enable_feature(Feature::asimd, asimd); | |
17df50a5 XL |
255 | // ASIMD extensions require ASIMD support: |
256 | enable_feature(Feature::fcma, self.fcma && asimd); | |
83c7162d XL |
257 | enable_feature(Feature::sve, self.sve && asimd); |
258 | ||
17df50a5 XL |
259 | // SVE extensions require SVE & ASIMD |
260 | enable_feature(Feature::f32mm, self.svef32mm && self.sve && asimd); | |
261 | enable_feature(Feature::f64mm, self.svef64mm && self.sve && asimd); | |
262 | ||
263 | // Cryptographic extensions require ASIMD | |
264 | enable_feature(Feature::aes, self.aes && asimd); | |
265 | enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); | |
266 | // SHA512/SHA3 require SHA1 & SHA256 | |
267 | enable_feature( | |
268 | Feature::sha3, | |
269 | self.sha512 && self.sha3 && self.sha1 && self.sha2 && asimd, | |
270 | ); | |
271 | enable_feature(Feature::sm4, self.sm3 && self.sm4 && asimd); | |
272 | ||
273 | // SVE2 requires SVE | |
274 | let sve2 = self.sve2 && self.sve && asimd; | |
275 | enable_feature(Feature::sve2, sve2); | |
276 | // SVE2 extensions require SVE2 and crypto features | |
277 | enable_feature(Feature::sve2_aes, self.sveaes && sve2 && self.aes); | |
278 | enable_feature( | |
279 | Feature::sve2_sm4, | |
280 | self.svesm4 && sve2 && self.sm3 && self.sm4, | |
281 | ); | |
74b04a01 | 282 | enable_feature( |
17df50a5 XL |
283 | Feature::sve2_sha3, |
284 | self.svesha3 && sve2 && self.sha512 && self.sha3 && self.sha1 && self.sha2, | |
74b04a01 | 285 | ); |
17df50a5 | 286 | enable_feature(Feature::sve2_bitperm, self.svebitperm && self.sve2); |
83c7162d XL |
287 | } |
288 | value | |
289 | } | |
290 | } |