hir_ty/
target_feature.rs

1//! Stuff for handling `#[target_feature]` (needed for unsafe check).
2
3use std::sync::LazyLock;
4
5use hir_def::attr::Attrs;
6use hir_def::tt;
7use intern::{Symbol, sym};
8use rustc_hash::{FxHashMap, FxHashSet};
9
10#[derive(Debug, Default)]
11pub struct TargetFeatures {
12    pub(crate) enabled: FxHashSet<Symbol>,
13}
14
15impl TargetFeatures {
16    pub fn from_attrs(attrs: &Attrs) -> Self {
17        let mut result = TargetFeatures::from_attrs_no_implications(attrs);
18        result.expand_implications();
19        result
20    }
21
22    fn expand_implications(&mut self) {
23        let all_implications = LazyLock::force(&TARGET_FEATURE_IMPLICATIONS);
24        let mut queue = self.enabled.iter().cloned().collect::<Vec<_>>();
25        while let Some(feature) = queue.pop() {
26            if let Some(implications) = all_implications.get(&feature) {
27                for implication in implications {
28                    if self.enabled.insert(implication.clone()) {
29                        queue.push(implication.clone());
30                    }
31                }
32            }
33        }
34    }
35
36    /// Retrieves the target features from the attributes, and does not expand the target features implied by them.
37    pub(crate) fn from_attrs_no_implications(attrs: &Attrs) -> Self {
38        let enabled = attrs
39            .by_key(sym::target_feature)
40            .tt_values()
41            .filter_map(|tt| match tt.token_trees().flat_tokens() {
42                [
43                    tt::TokenTree::Leaf(tt::Leaf::Ident(enable_ident)),
44                    tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. })),
45                    tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
46                        kind: tt::LitKind::Str,
47                        symbol: features,
48                        ..
49                    })),
50                ] if enable_ident.sym == sym::enable => Some(features),
51                _ => None,
52            })
53            .flat_map(|features| features.as_str().split(',').map(Symbol::intern))
54            .collect();
55        Self { enabled }
56    }
57}
58
59// List of the target features each target feature implies.
60// Ideally we'd depend on rustc for this, but rustc_target doesn't compile on stable,
61// and t-compiler prefers for it to stay this way.
62
63static TARGET_FEATURE_IMPLICATIONS: LazyLock<FxHashMap<Symbol, Box<[Symbol]>>> =
64    LazyLock::new(|| {
65        let mut result = FxHashMap::<Symbol, FxHashSet<Symbol>>::default();
66        for &(feature_str, implications) in TARGET_FEATURE_IMPLICATIONS_RAW {
67            let feature = Symbol::intern(feature_str);
68            let implications = implications.iter().copied().map(Symbol::intern);
69            // Some target features appear in two archs, e.g. Arm and x86.
70            // Sometimes they contain different implications, e.g. `aes`.
71            // We should probably choose by the active arch, but for now just merge them.
72            result.entry(feature).or_default().extend(implications);
73        }
74        let mut result = result
75            .into_iter()
76            .map(|(feature, implications)| (feature, Box::from_iter(implications)))
77            .collect::<FxHashMap<_, _>>();
78        result.shrink_to_fit();
79        result
80    });
81
82// spellchecker:off
83const TARGET_FEATURE_IMPLICATIONS_RAW: &[(&str, &[&str])] = &[
84    // Arm
85    ("aes", &["neon"]),
86    ("dotprod", &["neon"]),
87    ("fp-armv8", &["vfp4"]),
88    ("fp16", &["neon"]),
89    ("i8mm", &["neon"]),
90    ("neon", &["vfp3"]),
91    ("sha2", &["neon"]),
92    ("v6", &["v5te"]),
93    ("v6k", &["v6"]),
94    ("v6t2", &["v6k", "thumb2"]),
95    ("v7", &["v6t2"]),
96    ("v8", &["v7"]),
97    ("vfp3", &["vfp2", "d32"]),
98    ("vfp4", &["vfp3"]),
99    // Aarch64
100    ("aes", &["neon"]),
101    ("dotprod", &["neon"]),
102    ("dpb2", &["dpb"]),
103    ("f32mm", &["sve"]),
104    ("f64mm", &["sve"]),
105    ("fcma", &["neon"]),
106    ("fhm", &["fp16"]),
107    ("fp16", &["neon"]),
108    ("fp8", &["faminmax", "lut", "bf16"]),
109    ("fp8dot2", &["fp8dot4"]),
110    ("fp8dot4", &["fp8fma"]),
111    ("fp8fma", &["fp8"]),
112    ("jsconv", &["neon"]),
113    ("lse128", &["lse"]),
114    ("rcpc2", &["rcpc"]),
115    ("rcpc3", &["rcpc2"]),
116    ("rdm", &["neon"]),
117    ("sha2", &["neon"]),
118    ("sha3", &["sha2"]),
119    ("sm4", &["neon"]),
120    ("sme", &["bf16"]),
121    ("sme-b16b16", &["bf16", "sme2", "sve-b16b16"]),
122    ("sme-f16f16", &["sme2"]),
123    ("sme-f64f64", &["sme"]),
124    ("sme-f8f16", &["sme-f8f32"]),
125    ("sme-f8f32", &["sme2", "fp8"]),
126    ("sme-fa64", &["sme", "sve2"]),
127    ("sme-i16i64", &["sme"]),
128    ("sme2", &["sme"]),
129    ("sme2p1", &["sme2"]),
130    ("ssve-fp8dot2", &["ssve-fp8dot4"]),
131    ("ssve-fp8dot4", &["ssve-fp8fma"]),
132    ("ssve-fp8fma", &["sme2", "fp8"]),
133    ("sve", &["neon"]),
134    ("sve-b16b16", &["bf16"]),
135    ("sve2", &["sve"]),
136    ("sve2-aes", &["sve2", "aes"]),
137    ("sve2-bitperm", &["sve2"]),
138    ("sve2-sha3", &["sve2", "sha3"]),
139    ("sve2-sm4", &["sve2", "sm4"]),
140    ("sve2p1", &["sve2"]),
141    ("v8.1a", &["crc", "lse", "rdm", "pan", "lor", "vh"]),
142    ("v8.2a", &["v8.1a", "ras", "dpb"]),
143    ("v8.3a", &["v8.2a", "rcpc", "paca", "pacg", "jsconv"]),
144    ("v8.4a", &["v8.3a", "dotprod", "dit", "flagm"]),
145    ("v8.5a", &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
146    ("v8.6a", &["v8.5a", "bf16", "i8mm"]),
147    ("v8.7a", &["v8.6a", "wfxt"]),
148    ("v8.8a", &["v8.7a", "hbc", "mops"]),
149    ("v8.9a", &["v8.8a", "cssc"]),
150    ("v9.1a", &["v9a", "v8.6a"]),
151    ("v9.2a", &["v9.1a", "v8.7a"]),
152    ("v9.3a", &["v9.2a", "v8.8a"]),
153    ("v9.4a", &["v9.3a", "v8.9a"]),
154    ("v9.5a", &["v9.4a"]),
155    ("v9a", &["v8.5a", "sve2"]),
156    // x86
157    ("aes", &["sse2"]),
158    ("amx-bf16", &["amx-tile"]),
159    ("amx-complex", &["amx-tile"]),
160    ("amx-fp16", &["amx-tile"]),
161    ("amx-int8", &["amx-tile"]),
162    ("avx", &["sse4.2"]),
163    ("avx2", &["avx"]),
164    ("avx512bf16", &["avx512bw"]),
165    ("avx512bitalg", &["avx512bw"]),
166    ("avx512bw", &["avx512f"]),
167    ("avx512cd", &["avx512f"]),
168    ("avx512dq", &["avx512f"]),
169    ("avx512f", &["avx2", "fma", "f16c"]),
170    ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]),
171    ("avx512ifma", &["avx512f"]),
172    ("avx512vbmi", &["avx512bw"]),
173    ("avx512vbmi2", &["avx512bw"]),
174    ("avx512vl", &["avx512f"]),
175    ("avx512vnni", &["avx512f"]),
176    ("avx512vp2intersect", &["avx512f"]),
177    ("avx512vpopcntdq", &["avx512f"]),
178    ("avxifma", &["avx2"]),
179    ("avxneconvert", &["avx2"]),
180    ("avxvnni", &["avx2"]),
181    ("avxvnniint16", &["avx2"]),
182    ("avxvnniint8", &["avx2"]),
183    ("f16c", &["avx"]),
184    ("fma", &["avx"]),
185    ("gfni", &["sse2"]),
186    ("kl", &["sse2"]),
187    ("pclmulqdq", &["sse2"]),
188    ("sha", &["sse2"]),
189    ("sha512", &["avx2"]),
190    ("sm3", &["avx"]),
191    ("sm4", &["avx2"]),
192    ("sse2", &["sse"]),
193    ("sse3", &["sse2"]),
194    ("sse4.1", &["ssse3"]),
195    ("sse4.2", &["sse4.1"]),
196    ("sse4a", &["sse3"]),
197    ("ssse3", &["sse3"]),
198    ("vaes", &["avx2", "aes"]),
199    ("vpclmulqdq", &["avx", "pclmulqdq"]),
200    ("widekl", &["kl"]),
201    ("xop", &[/*"fma4", */ "avx", "sse4a"]),
202    ("xsavec", &["xsave"]),
203    ("xsaveopt", &["xsave"]),
204    ("xsaves", &["xsave"]),
205    // Hexagon
206    ("hvx-length128b", &["hvx"]),
207    // PowerPC
208    ("power10-vector", &["power9-vector"]),
209    ("power8-altivec", &["altivec"]),
210    ("power8-crypto", &["power8-altivec"]),
211    ("power8-vector", &["vsx", "power8-altivec"]),
212    ("power9-altivec", &["power8-altivec"]),
213    ("power9-vector", &["power8-vector", "power9-altivec"]),
214    ("vsx", &["altivec"]),
215    // MIPS
216    // RISC-V
217    ("a", &["zaamo", "zalrsc"]),
218    ("d", &["f"]),
219    ("zabha", &["zaamo"]),
220    ("zdinx", &["zfinx"]),
221    ("zfh", &["zfhmin"]),
222    ("zfhmin", &["f"]),
223    ("zhinx", &["zhinxmin"]),
224    ("zhinxmin", &["zfinx"]),
225    ("zk", &["zkn", "zkr", "zkt"]),
226    ("zkn", &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
227    ("zks", &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
228    // WASM
229    ("relaxed-simd", &["simd128"]),
230    // BPF
231    ("alu32", &[]),
232    // CSKY
233    ("10e60", &["7e10"]),
234    ("2e3", &["e2"]),
235    ("3e3r2", &["3e3r1", "doloop"]),
236    ("3e3r3", &["doloop"]),
237    ("3e7", &["2e3"]),
238    ("7e10", &["3e7"]),
239    ("e1", &["elrw"]),
240    ("e2", &["e2"]),
241    ("mp", &["2e3"]),
242    ("mp1e2", &["3e7"]),
243    // LoongArch
244    ("d", &["f"]),
245    ("lasx", &["lsx"]),
246    ("lsx", &["d"]),
247    // IBM Z
248    ("nnp-assist", &["vector"]),
249    ("vector-enhancements-1", &["vector"]),
250    ("vector-enhancements-2", &["vector-enhancements-1"]),
251    ("vector-packed-decimal", &["vector"]),
252    ("vector-packed-decimal-enhancement", &["vector-packed-decimal"]),
253    ("vector-packed-decimal-enhancement-2", &["vector-packed-decimal-enhancement"]),
254    // SPARC
255    // m68k
256    ("isa-68010", &["isa-68000"]),
257    ("isa-68020", &["isa-68010"]),
258    ("isa-68030", &["isa-68020"]),
259    ("isa-68040", &["isa-68030", "isa-68882"]),
260    ("isa-68060", &["isa-68040"]),
261    ("isa-68882", &["isa-68881"]),
262];
263// spellchecker:on