1 //! Run-time feature detection for Aarch64 on Linux.
2
3 use super::{auxvec, cpuinfo};
4 use crate::detect::{bit, cache, Feature};
5
6 /// Performs run-time feature detection.
7 #[inline]
check_for(x: Feature) -> bool8 pub fn check_for(x: Feature) -> bool {
9 cache::test(x as u32, detect_features)
10 }
11
12 /// Try to read the features from the auxiliary vector, and if that fails, try
13 /// to read them from /proc/cpuinfo.
detect_features() -> cache::Initializer14 fn detect_features() -> cache::Initializer {
15 if let Ok(auxv) = auxvec::auxv() {
16 let hwcap: AtHwcap = auxv.into();
17 return hwcap.cache();
18 }
19 if let Ok(c) = cpuinfo::CpuInfo::new() {
20 let hwcap: AtHwcap = c.into();
21 return hwcap.cache();
22 }
23 cache::Initializer::default()
24 }
25
26 /// These values are part of the platform-specific [asm/hwcap.h][hwcap] .
27 ///
28 /// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
29 struct AtHwcap {
30 fp: bool, // 0
31 asimd: bool, // 1
32 // evtstrm: bool, // 2
33 aes: bool, // 3
34 pmull: bool, // 4
35 sha1: bool, // 5
36 sha2: bool, // 6
37 crc32: bool, // 7
38 atomics: bool, // 8
39 fphp: bool, // 9
40 asimdhp: bool, // 10
41 // cpuid: bool, // 11
42 asimdrdm: bool, // 12
43 // jscvt: bool, // 13
44 // fcma: bool, // 14
45 lrcpc: bool, // 15
46 // dcpop: bool, // 16
47 // sha3: bool, // 17
48 // sm3: bool, // 18
49 // sm4: bool, // 19
50 asimddp: bool, // 20
51 // sha512: bool, // 21
52 sve: bool, // 22
53 }
54
55 impl From<auxvec::AuxVec> for AtHwcap {
56 /// Reads AtHwcap from the auxiliary vector.
from(auxv: auxvec::AuxVec) -> Self57 fn from(auxv: auxvec::AuxVec) -> Self {
58 AtHwcap {
59 fp: bit::test(auxv.hwcap, 0),
60 asimd: bit::test(auxv.hwcap, 1),
61 // evtstrm: bit::test(auxv.hwcap, 2),
62 aes: bit::test(auxv.hwcap, 3),
63 pmull: bit::test(auxv.hwcap, 4),
64 sha1: bit::test(auxv.hwcap, 5),
65 sha2: bit::test(auxv.hwcap, 6),
66 crc32: bit::test(auxv.hwcap, 7),
67 atomics: bit::test(auxv.hwcap, 8),
68 fphp: bit::test(auxv.hwcap, 9),
69 asimdhp: bit::test(auxv.hwcap, 10),
70 // cpuid: bit::test(auxv.hwcap, 11),
71 asimdrdm: bit::test(auxv.hwcap, 12),
72 // jscvt: bit::test(auxv.hwcap, 13),
73 // fcma: bit::test(auxv.hwcap, 14),
74 lrcpc: bit::test(auxv.hwcap, 15),
75 // dcpop: bit::test(auxv.hwcap, 16),
76 // sha3: bit::test(auxv.hwcap, 17),
77 // sm3: bit::test(auxv.hwcap, 18),
78 // sm4: bit::test(auxv.hwcap, 19),
79 asimddp: bit::test(auxv.hwcap, 20),
80 // sha512: bit::test(auxv.hwcap, 21),
81 sve: bit::test(auxv.hwcap, 22),
82 }
83 }
84 }
85
86 impl From<cpuinfo::CpuInfo> for AtHwcap {
87 /// Reads AtHwcap from /proc/cpuinfo .
from(c: cpuinfo::CpuInfo) -> Self88 fn from(c: cpuinfo::CpuInfo) -> Self {
89 let f = &c.field("Features");
90 AtHwcap {
91 // 64-bit names. FIXME: In 32-bit compatibility mode /proc/cpuinfo will
92 // map some of the 64-bit names to some 32-bit feature names. This does not
93 // cover that yet.
94 fp: f.has("fp"),
95 asimd: f.has("asimd"),
96 // evtstrm: f.has("evtstrm"),
97 aes: f.has("aes"),
98 pmull: f.has("pmull"),
99 sha1: f.has("sha1"),
100 sha2: f.has("sha2"),
101 crc32: f.has("crc32"),
102 atomics: f.has("atomics"),
103 fphp: f.has("fphp"),
104 asimdhp: f.has("asimdhp"),
105 // cpuid: f.has("cpuid"),
106 asimdrdm: f.has("asimdrdm"),
107 // jscvt: f.has("jscvt"),
108 // fcma: f.has("fcma"),
109 lrcpc: f.has("lrcpc"),
110 // dcpop: f.has("dcpop"),
111 // sha3: f.has("sha3"),
112 // sm3: f.has("sm3"),
113 // sm4: f.has("sm4"),
114 asimddp: f.has("asimddp"),
115 // sha512: f.has("sha512"),
116 sve: f.has("sve"),
117 }
118 }
119 }
120
121 impl AtHwcap {
122 /// Initializes the cache from the feature -bits.
123 ///
124 /// The features are enabled approximately like in LLVM host feature detection:
125 /// https://github.com/llvm-mirror/llvm/blob/master/lib/Support/Host.cpp#L1273
cache(self) -> cache::Initializer126 fn cache(self) -> cache::Initializer {
127 let mut value = cache::Initializer::default();
128 {
129 let mut enable_feature = |f, enable| {
130 if enable {
131 value.set(f as u32);
132 }
133 };
134
135 enable_feature(Feature::fp, self.fp);
136 // Half-float support requires float support
137 enable_feature(Feature::fp16, self.fp && self.fphp);
138 enable_feature(Feature::pmull, self.pmull);
139 enable_feature(Feature::crc, self.crc32);
140 enable_feature(Feature::lse, self.atomics);
141 enable_feature(Feature::rcpc, self.lrcpc);
142
143 // SIMD support requires float support - if half-floats are
144 // supported, it also requires half-float support:
145 let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp);
146 enable_feature(Feature::asimd, asimd);
147 // SIMD extensions require SIMD support:
148 enable_feature(Feature::rdm, self.asimdrdm && asimd);
149 enable_feature(Feature::dotprod, self.asimddp && asimd);
150 enable_feature(Feature::sve, self.sve && asimd);
151
152 // Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp
153 enable_feature(
154 Feature::crypto,
155 self.aes && self.pmull && self.sha1 && self.sha2,
156 );
157 }
158 value
159 }
160 }
161