rustc_target/
target_features.rs

1//! Declares Rust's target feature names for each target.
2//! Note that these are similar to but not always identical to LLVM's feature names,
3//! and Rust adds some features that do not correspond to LLVM features at all.
4use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6use rustc_span::{Symbol, sym};
7
8use crate::spec::{FloatAbi, RustcAbi, Target};
9
10/// Features that control behaviour of rustc, rather than the codegen.
11/// These exist globally and are not in the target-specific lists below.
12pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
13
14/// Features that require special handling when passing to LLVM:
15/// these are target-specific (i.e., must also be listed in the target-specific list below)
16/// but do not correspond to an LLVM target feature.
17pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
18
19/// Stability information for target features.
20#[derive(Debug, Copy, Clone)]
21pub enum Stability {
22    /// This target feature is stable, it can be used in `#[target_feature]` and
23    /// `#[cfg(target_feature)]`.
24    Stable,
25    /// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on
26    /// nightly and using it in `#[target_feature]` requires enabling the given nightly feature.
27    Unstable(
28        /// This must be a *language* feature, or else rustc will ICE when reporting a missing
29        /// feature gate!
30        Symbol,
31    ),
32    /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be
33    /// set in the target spec. It is never set in `cfg(target_feature)`. Used in
34    /// particular for features are actually ABI configuration flags (not all targets are as nice as
35    /// RISC-V and have an explicit way to set the ABI separate from target features).
36    Forbidden { reason: &'static str },
37}
38use Stability::*;
39
40impl<CTX> HashStable<CTX> for Stability {
41    #[inline]
42    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
43        std::mem::discriminant(self).hash_stable(hcx, hasher);
44        match self {
45            Stability::Stable => {}
46            Stability::Unstable(nightly_feature) => {
47                nightly_feature.hash_stable(hcx, hasher);
48            }
49            Stability::Forbidden { reason } => {
50                reason.hash_stable(hcx, hasher);
51            }
52        }
53    }
54}
55
56impl Stability {
57    /// Returns whether the feature can be used in `cfg(target_feature)` ever.
58    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
59    /// `requires_nightly`.)
60    pub fn in_cfg(&self) -> bool {
61        !matches!(self, Stability::Forbidden { .. })
62    }
63
64    /// Returns the nightly feature that is required to toggle this target feature via
65    /// `#[target_feature]`/`-Ctarget-feature` or to test it via `cfg(target_feature)`.
66    /// (For `cfg` we only care whether the feature is nightly or not, we don't require
67    /// the feature gate to actually be enabled when using a nightly compiler.)
68    ///
69    /// Before calling this, ensure the feature is even permitted for this use:
70    /// - for `#[target_feature]`/`-Ctarget-feature`, check `allow_toggle()`
71    /// - for `cfg(target_feature)`, check `in_cfg`
72    pub fn requires_nightly(&self) -> Option<Symbol> {
73        match *self {
74            Stability::Unstable(nightly_feature) => Some(nightly_feature),
75            Stability::Stable { .. } => None,
76            Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
77        }
78    }
79
80    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
81    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
82    /// `requires_nightly`.)
83    pub fn toggle_allowed(&self) -> Result<(), &'static str> {
84        match self {
85            Stability::Forbidden { reason } => Err(reason),
86            _ => Ok(()),
87        }
88    }
89}
90
91// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
92// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with
93// `-Ctarget-feature`.
94//
95// Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature`
96// on stable. Using a feature not on the list of Rust target features only emits a warning.
97// Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating.
98// `cfg(target_feature)` for unstable features just works on nightly without any feature gate.
99// `#[target_feature]` requires a feature gate.
100//
101// When adding features to the below lists
102// check whether they're named already elsewhere in rust
103// e.g. in stdarch and whether the given name matches LLVM's
104// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted.
105// Additionally, if the feature is not available in older version of LLVM supported by the current
106// rust, the same function must be updated to filter out these features to avoid triggering
107// warnings.
108//
109// Also note that all target features listed here must be purely additive: for target_feature 1.1 to
110// be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a
111// per-function level, since we would then allow safe calls from functions with `+soft-float` to
112// functions without that feature!
113//
114// It is important for soundness to consider the interaction of targets features and the function
115// call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
116// arguments, so letting people toggle that feature would be unsound. To this end, the
117// `abi_required_features` function computes which target features must and must not be enabled for
118// any given target, and individual features can also be marked as `Forbidden`.
119// See https://github.com/rust-lang/rust/issues/116344 for some more context.
120//
121// The one exception to features that change the ABI is features that enable larger vector
122// registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store
123// information about which target feature is ABI-required for which vector size; this is used to
124// ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For
125// the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.)
126// Also see https://github.com/rust-lang/rust/issues/116558.
127//
128// Stabilizing a target feature requires t-lang approval.
129
130// If feature A "implies" feature B, then:
131// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B
132// - when B gets disabled (via `-Ctarget-feature`), we also disable A
133//
134// Both of these are also applied transitively.
135type ImpliedFeatures = &'static [&'static str];
136
137static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
138    // tidy-alphabetical-start
139    ("aclass", Unstable(sym::arm_target_feature), &[]),
140    ("aes", Unstable(sym::arm_target_feature), &["neon"]),
141    (
142        "atomics-32",
143        Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
144        &[],
145    ),
146    ("crc", Unstable(sym::arm_target_feature), &[]),
147    ("d32", Unstable(sym::arm_target_feature), &[]),
148    ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
149    ("dsp", Unstable(sym::arm_target_feature), &[]),
150    ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
151    ("fp16", Unstable(sym::arm_target_feature), &["neon"]),
152    ("fpregs", Unstable(sym::arm_target_feature), &[]),
153    ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
154    ("mclass", Unstable(sym::arm_target_feature), &[]),
155    ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
156    ("rclass", Unstable(sym::arm_target_feature), &[]),
157    ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
158    // This can be *disabled* on non-`hf` targets to enable the use
159    // of hardfloats while keeping the softfloat ABI.
160    // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of
161    // matching the odd negative feature LLVM uses?
162    ("soft-float", Unstable(sym::arm_target_feature), &[]),
163    // This is needed for inline assembly, but shouldn't be stabilized as-is
164    // since it should be enabled per-function using #[instruction_set], not
165    // #[target_feature].
166    ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
167    ("thumb2", Unstable(sym::arm_target_feature), &[]),
168    ("trustzone", Unstable(sym::arm_target_feature), &[]),
169    ("v5te", Unstable(sym::arm_target_feature), &[]),
170    ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
171    ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
172    ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
173    ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
174    ("v8", Unstable(sym::arm_target_feature), &["v7"]),
175    ("vfp2", Unstable(sym::arm_target_feature), &[]),
176    ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
177    ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
178    ("virtualization", Unstable(sym::arm_target_feature), &[]),
179    // tidy-alphabetical-end
180];
181
182static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
183    // tidy-alphabetical-start
184    // FEAT_AES & FEAT_PMULL
185    ("aes", Stable, &["neon"]),
186    // FEAT_BF16
187    ("bf16", Stable, &[]),
188    // FEAT_BTI
189    ("bti", Stable, &[]),
190    // FEAT_CRC
191    ("crc", Stable, &[]),
192    // FEAT_CSSC
193    ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]),
194    // FEAT_DIT
195    ("dit", Stable, &[]),
196    // FEAT_DotProd
197    ("dotprod", Stable, &["neon"]),
198    // FEAT_DPB
199    ("dpb", Stable, &[]),
200    // FEAT_DPB2
201    ("dpb2", Stable, &["dpb"]),
202    // FEAT_ECV
203    ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]),
204    // FEAT_F32MM
205    ("f32mm", Stable, &["sve"]),
206    // FEAT_F64MM
207    ("f64mm", Stable, &["sve"]),
208    // FEAT_FAMINMAX
209    ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]),
210    // FEAT_FCMA
211    ("fcma", Stable, &["neon"]),
212    // FEAT_FHM
213    ("fhm", Stable, &["fp16"]),
214    // FEAT_FLAGM
215    ("flagm", Stable, &[]),
216    // FEAT_FLAGM2
217    ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]),
218    // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`.
219    ("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]),
220    // FEAT_FP16
221    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
222    ("fp16", Stable, &["neon"]),
223    // FEAT_FP8
224    ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]),
225    // FEAT_FP8DOT2
226    ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]),
227    // FEAT_FP8DOT4
228    ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]),
229    // FEAT_FP8FMA
230    ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]),
231    // FEAT_FRINTTS
232    ("frintts", Stable, &[]),
233    // FEAT_HBC
234    ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]),
235    // FEAT_I8MM
236    ("i8mm", Stable, &[]),
237    // FEAT_JSCVT
238    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
239    ("jsconv", Stable, &["neon"]),
240    // FEAT_LOR
241    ("lor", Stable, &[]),
242    // FEAT_LSE
243    ("lse", Stable, &[]),
244    // FEAT_LSE128
245    ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]),
246    // FEAT_LSE2
247    ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]),
248    // FEAT_LUT
249    ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]),
250    // FEAT_MOPS
251    ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]),
252    // FEAT_MTE & FEAT_MTE2
253    ("mte", Stable, &[]),
254    // FEAT_AdvSimd & FEAT_FP
255    ("neon", Stable, &[]),
256    // FEAT_PAUTH (address authentication)
257    ("paca", Stable, &[]),
258    // FEAT_PAUTH (generic authentication)
259    ("pacg", Stable, &[]),
260    // FEAT_PAN
261    ("pan", Stable, &[]),
262    // FEAT_PAuth_LR
263    ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
264    // FEAT_PMUv3
265    ("pmuv3", Stable, &[]),
266    // FEAT_RNG
267    ("rand", Stable, &[]),
268    // FEAT_RAS & FEAT_RASv1p1
269    ("ras", Stable, &[]),
270    // FEAT_LRCPC
271    ("rcpc", Stable, &[]),
272    // FEAT_LRCPC2
273    ("rcpc2", Stable, &["rcpc"]),
274    // FEAT_LRCPC3
275    ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
276    // FEAT_RDM
277    ("rdm", Stable, &["neon"]),
278    // This is needed for inline assembly, but shouldn't be stabilized as-is
279    // since it should be enabled globally using -Zfixed-x18, not
280    // #[target_feature].
281    // Note that cfg(target_feature = "reserve-x18") is currently not set for
282    // targets that reserve x18 by default.
283    ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]),
284    // FEAT_SB
285    ("sb", Stable, &[]),
286    // FEAT_SHA1 & FEAT_SHA256
287    ("sha2", Stable, &["neon"]),
288    // FEAT_SHA512 & FEAT_SHA3
289    ("sha3", Stable, &["sha2"]),
290    // FEAT_SM3 & FEAT_SM4
291    ("sm4", Stable, &["neon"]),
292    // FEAT_SME
293    ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
294    // FEAT_SME_B16B16
295    ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]),
296    // FEAT_SME_F16F16
297    ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
298    // FEAT_SME_F64F64
299    ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
300    // FEAT_SME_F8F16
301    ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]),
302    // FEAT_SME_F8F32
303    ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
304    // FEAT_SME_FA64
305    ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]),
306    // FEAT_SME_I16I64
307    ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
308    // FEAT_SME_LUTv2
309    ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]),
310    // FEAT_SME2
311    ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
312    // FEAT_SME2p1
313    ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
314    // FEAT_SPE
315    ("spe", Stable, &[]),
316    // FEAT_SSBS & FEAT_SSBS2
317    ("ssbs", Stable, &[]),
318    // FEAT_SSVE_FP8FDOT2
319    ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]),
320    // FEAT_SSVE_FP8FDOT4
321    ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]),
322    // FEAT_SSVE_FP8FMA
323    ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
324    // FEAT_SVE
325    // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
326    //
327    // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
328    // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
329    //
330    // "For backwards compatibility, Neon and VFP are required in the latest architectures."
331    ("sve", Stable, &["neon"]),
332    // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions)
333    ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
334    // FEAT_SVE2
335    ("sve2", Stable, &["sve"]),
336    // FEAT_SVE_AES & FEAT_SVE_PMULL128
337    ("sve2-aes", Stable, &["sve2", "aes"]),
338    // FEAT_SVE2_BitPerm
339    ("sve2-bitperm", Stable, &["sve2"]),
340    // FEAT_SVE2_SHA3
341    ("sve2-sha3", Stable, &["sve2", "sha3"]),
342    // FEAT_SVE2_SM4
343    ("sve2-sm4", Stable, &["sve2", "sm4"]),
344    // FEAT_SVE2p1
345    ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]),
346    // FEAT_TME
347    ("tme", Stable, &[]),
348    (
349        "v8.1a",
350        Unstable(sym::aarch64_ver_target_feature),
351        &["crc", "lse", "rdm", "pan", "lor", "vh"],
352    ),
353    ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
354    (
355        "v8.3a",
356        Unstable(sym::aarch64_ver_target_feature),
357        &["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
358    ),
359    ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
360    ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
361    ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
362    ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]),
363    ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]),
364    ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]),
365    ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]),
366    ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]),
367    ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]),
368    ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]),
369    ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]),
370    ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "sve2"]),
371    // FEAT_VHE
372    ("vh", Stable, &[]),
373    // FEAT_WFxT
374    ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]),
375    // tidy-alphabetical-end
376];
377
378const AARCH64_TIED_FEATURES: &[&[&str]] = &[
379    &["paca", "pacg"], // Together these represent `pauth` in LLVM
380];
381
382static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
383    // tidy-alphabetical-start
384    ("adx", Stable, &[]),
385    ("aes", Stable, &["sse2"]),
386    ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
387    ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
388    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
389    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
390    ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
391    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
392    ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
393    ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
394    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
395    ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
396    ("apxf", Unstable(sym::apx_target_feature), &[]),
397    ("avx", Stable, &["sse4.2"]),
398    (
399        "avx10.1",
400        Unstable(sym::avx10_target_feature),
401        &[
402            "avx512bf16",
403            "avx512bitalg",
404            "avx512bw",
405            "avx512cd",
406            "avx512dq",
407            "avx512f",
408            "avx512fp16",
409            "avx512ifma",
410            "avx512vbmi",
411            "avx512vbmi2",
412            "avx512vl",
413            "avx512vnni",
414            "avx512vpopcntdq",
415        ],
416    ),
417    ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]),
418    ("avx2", Stable, &["avx"]),
419    ("avx512bf16", Stable, &["avx512bw"]),
420    ("avx512bitalg", Stable, &["avx512bw"]),
421    ("avx512bw", Stable, &["avx512f"]),
422    ("avx512cd", Stable, &["avx512f"]),
423    ("avx512dq", Stable, &["avx512f"]),
424    ("avx512f", Stable, &["avx2", "fma", "f16c"]),
425    ("avx512fp16", Stable, &["avx512bw"]),
426    ("avx512ifma", Stable, &["avx512f"]),
427    ("avx512vbmi", Stable, &["avx512bw"]),
428    ("avx512vbmi2", Stable, &["avx512bw"]),
429    ("avx512vl", Stable, &["avx512f"]),
430    ("avx512vnni", Stable, &["avx512f"]),
431    ("avx512vp2intersect", Stable, &["avx512f"]),
432    ("avx512vpopcntdq", Stable, &["avx512f"]),
433    ("avxifma", Stable, &["avx2"]),
434    ("avxneconvert", Stable, &["avx2"]),
435    ("avxvnni", Stable, &["avx2"]),
436    ("avxvnniint16", Stable, &["avx2"]),
437    ("avxvnniint8", Stable, &["avx2"]),
438    ("bmi1", Stable, &[]),
439    ("bmi2", Stable, &[]),
440    ("cmpxchg16b", Stable, &[]),
441    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
442    ("f16c", Stable, &["avx"]),
443    ("fma", Stable, &["avx"]),
444    ("fxsr", Stable, &[]),
445    ("gfni", Stable, &["sse2"]),
446    ("kl", Unstable(sym::keylocker_x86), &["sse2"]),
447    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
448    ("lzcnt", Stable, &[]),
449    ("movbe", Stable, &[]),
450    ("movrs", Unstable(sym::movrs_target_feature), &[]),
451    ("pclmulqdq", Stable, &["sse2"]),
452    ("popcnt", Stable, &[]),
453    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
454    ("rdrand", Stable, &[]),
455    ("rdseed", Stable, &[]),
456    ("rtm", Unstable(sym::rtm_target_feature), &[]),
457    ("sha", Stable, &["sse2"]),
458    ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
459    ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
460    ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
461    // This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
462    // stabilize. It must be in this list for the ABI check to be able to use it.
463    ("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
464    ("sse", Stable, &[]),
465    ("sse2", Stable, &["sse"]),
466    ("sse3", Stable, &["sse2"]),
467    ("sse4.1", Stable, &["ssse3"]),
468    ("sse4.2", Stable, &["sse4.1"]),
469    ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
470    ("ssse3", Stable, &["sse3"]),
471    ("tbm", Unstable(sym::tbm_target_feature), &[]),
472    ("vaes", Stable, &["avx2", "aes"]),
473    ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]),
474    ("widekl", Unstable(sym::keylocker_x86), &["kl"]),
475    ("x87", Unstable(sym::x87_target_feature), &[]),
476    ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
477    ("xsave", Stable, &[]),
478    ("xsavec", Stable, &["xsave"]),
479    ("xsaveopt", Stable, &["xsave"]),
480    ("xsaves", Stable, &["xsave"]),
481    // tidy-alphabetical-end
482];
483
484const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
485    // tidy-alphabetical-start
486    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
487    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
488    // tidy-alphabetical-end
489];
490
491static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
492    // tidy-alphabetical-start
493    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
494    ("msync", Unstable(sym::powerpc_target_feature), &[]),
495    ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
496    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
497    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
498    ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
499    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
500    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
501    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
502    ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]),
503    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
504    // tidy-alphabetical-end
505];
506
507const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
508    // tidy-alphabetical-start
509    ("fp64", Unstable(sym::mips_target_feature), &[]),
510    ("msa", Unstable(sym::mips_target_feature), &[]),
511    ("virt", Unstable(sym::mips_target_feature), &[]),
512    // tidy-alphabetical-end
513];
514
515static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
516    // tidy-alphabetical-start
517    ("a", Stable, &["zaamo", "zalrsc"]),
518    ("b", Unstable(sym::riscv_target_feature), &["zba", "zbb", "zbs"]),
519    ("c", Stable, &["zca"]),
520    ("d", Unstable(sym::riscv_target_feature), &["f"]),
521    ("e", Unstable(sym::riscv_target_feature), &[]),
522    ("f", Unstable(sym::riscv_target_feature), &["zicsr"]),
523    (
524        "forced-atomics",
525        Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
526        &[],
527    ),
528    ("m", Stable, &[]),
529    ("relax", Unstable(sym::riscv_target_feature), &[]),
530    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
531    ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]),
532    ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]),
533    ("za128rs", Unstable(sym::riscv_target_feature), &[]),
534    ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs
535    ("zaamo", Unstable(sym::riscv_target_feature), &[]),
536    ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
537    ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]),
538    ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
539    ("zama16b", Unstable(sym::riscv_target_feature), &[]),
540    ("zawrs", Unstable(sym::riscv_target_feature), &[]),
541    ("zba", Stable, &[]),
542    ("zbb", Stable, &[]),
543    ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc
544    ("zbkb", Stable, &[]),
545    ("zbkc", Stable, &[]),
546    ("zbkx", Stable, &[]),
547    ("zbs", Stable, &[]),
548    ("zca", Unstable(sym::riscv_target_feature), &[]),
549    ("zcb", Unstable(sym::riscv_target_feature), &["zca"]),
550    ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]),
551    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
552    ("zfa", Unstable(sym::riscv_target_feature), &["f"]),
553    ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin
554    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
555    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
556    ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]),
557    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
558    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
559    ("zic64b", Unstable(sym::riscv_target_feature), &[]),
560    ("zicbom", Unstable(sym::riscv_target_feature), &[]),
561    ("zicbop", Unstable(sym::riscv_target_feature), &[]),
562    ("zicboz", Unstable(sym::riscv_target_feature), &[]),
563    ("ziccamoa", Unstable(sym::riscv_target_feature), &[]),
564    ("ziccif", Unstable(sym::riscv_target_feature), &[]),
565    ("zicclsm", Unstable(sym::riscv_target_feature), &[]),
566    ("ziccrse", Unstable(sym::riscv_target_feature), &[]),
567    ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]),
568    ("zicond", Unstable(sym::riscv_target_feature), &[]),
569    ("zicsr", Unstable(sym::riscv_target_feature), &[]),
570    ("zifencei", Unstable(sym::riscv_target_feature), &[]),
571    ("zihintntl", Unstable(sym::riscv_target_feature), &[]),
572    ("zihintpause", Unstable(sym::riscv_target_feature), &[]),
573    ("zihpm", Unstable(sym::riscv_target_feature), &["zicsr"]),
574    ("zimop", Unstable(sym::riscv_target_feature), &[]),
575    ("zk", Stable, &["zkn", "zkr", "zkt"]),
576    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
577    ("zknd", Stable, &[]),
578    ("zkne", Stable, &[]),
579    ("zknh", Stable, &[]),
580    ("zkr", Stable, &[]),
581    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
582    ("zksed", Stable, &[]),
583    ("zksh", Stable, &[]),
584    ("zkt", Stable, &[]),
585    ("ztso", Unstable(sym::riscv_target_feature), &[]),
586    ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb
587    ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
588    ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
589    ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]),
590    ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]),
591    ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]),
592    ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]),
593    ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
594    ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]),
595    ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin
596    ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
597    ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]),
598    ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]),
599    ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]),
600    ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]),
601    ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]),
602    ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]),
603    ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]),
604    ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha
605    ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]),
606    ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]),
607    ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]),
608    ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]),
609    ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]),
610    ("zvkt", Unstable(sym::riscv_target_feature), &[]),
611    ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]),
612    ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]),
613    ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]),
614    ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]),
615    ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]),
616    ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]),
617    ("zvl32b", Unstable(sym::riscv_target_feature), &[]),
618    ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]),
619    ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]),
620    ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]),
621    ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]),
622    ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]),
623    // tidy-alphabetical-end
624];
625
626static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
627    // tidy-alphabetical-start
628    ("atomics", Unstable(sym::wasm_target_feature), &[]),
629    ("bulk-memory", Stable, &[]),
630    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
631    ("extended-const", Stable, &[]),
632    ("multivalue", Stable, &[]),
633    ("mutable-globals", Stable, &[]),
634    ("nontrapping-fptoint", Stable, &[]),
635    ("reference-types", Stable, &[]),
636    ("relaxed-simd", Stable, &["simd128"]),
637    ("sign-ext", Stable, &[]),
638    ("simd128", Stable, &[]),
639    ("tail-call", Stable, &[]),
640    ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
641    // tidy-alphabetical-end
642];
643
644const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
645    &[("alu32", Unstable(sym::bpf_target_feature), &[])];
646
647static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
648    // tidy-alphabetical-start
649    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
650    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
651    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
652    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
653    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
654    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
655    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
656    ("cache", Unstable(sym::csky_target_feature), &[]),
657    ("doloop", Unstable(sym::csky_target_feature), &[]),
658    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
659    ("dspe60", Unstable(sym::csky_target_feature), &[]),
660    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
661    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
662    ("edsp", Unstable(sym::csky_target_feature), &[]),
663    ("elrw", Unstable(sym::csky_target_feature), &[]),
664    ("float1e2", Unstable(sym::csky_target_feature), &[]),
665    ("float1e3", Unstable(sym::csky_target_feature), &[]),
666    ("float3e4", Unstable(sym::csky_target_feature), &[]),
667    ("float7e60", Unstable(sym::csky_target_feature), &[]),
668    ("floate1", Unstable(sym::csky_target_feature), &[]),
669    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
670    ("high-registers", Unstable(sym::csky_target_feature), &[]),
671    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
672    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
673    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
674    ("nvic", Unstable(sym::csky_target_feature), &[]),
675    ("trust", Unstable(sym::csky_target_feature), &[]),
676    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
677    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
678    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
679    // tidy-alphabetical-end
680    //fpu
681    // tidy-alphabetical-start
682    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
683    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
684    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
685    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
686    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
687    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
688    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
689    ("hard-float", Unstable(sym::csky_target_feature), &[]),
690    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
691    // tidy-alphabetical-end
692];
693
694static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
695    // tidy-alphabetical-start
696    ("d", Stable, &["f"]),
697    ("div32", Unstable(sym::loongarch_target_feature), &[]),
698    ("f", Stable, &[]),
699    ("frecipe", Stable, &[]),
700    ("lam-bh", Unstable(sym::loongarch_target_feature), &[]),
701    ("lamcas", Unstable(sym::loongarch_target_feature), &[]),
702    ("lasx", Stable, &["lsx"]),
703    ("lbt", Stable, &[]),
704    ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]),
705    ("lsx", Stable, &["d"]),
706    ("lvz", Stable, &[]),
707    ("relax", Unstable(sym::loongarch_target_feature), &[]),
708    ("scq", Unstable(sym::loongarch_target_feature), &[]),
709    ("ual", Unstable(sym::loongarch_target_feature), &[]),
710    // tidy-alphabetical-end
711];
712
713#[rustfmt::skip]
714const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
715    // tidy-alphabetical-start
716    ("backchain", Unstable(sym::s390x_target_feature), &[]),
717    ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
718    ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
719    ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]),
720    ("guarded-storage", Unstable(sym::s390x_target_feature), &[]),
721    ("high-word", Unstable(sym::s390x_target_feature), &[]),
722    // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11.
723    ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]),
724    ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]),
725    ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]),
726    ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]),
727    ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]),
728    ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]),
729    ("miscellaneous-extensions-2", Unstable(sym::s390x_target_feature), &[]),
730    ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]),
731    ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]),
732    ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]),
733    ("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
734    ("vector", Unstable(sym::s390x_target_feature), &[]),
735    ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]),
736    ("vector-enhancements-2", Unstable(sym::s390x_target_feature), &["vector-enhancements-1"]),
737    ("vector-enhancements-3", Unstable(sym::s390x_target_feature), &["vector-enhancements-2"]),
738    ("vector-packed-decimal", Unstable(sym::s390x_target_feature), &["vector"]),
739    ("vector-packed-decimal-enhancement", Unstable(sym::s390x_target_feature), &["vector-packed-decimal"]),
740    ("vector-packed-decimal-enhancement-2", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement"]),
741    ("vector-packed-decimal-enhancement-3", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement-2"]),
742    // tidy-alphabetical-end
743];
744
745const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
746    // tidy-alphabetical-start
747    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
748    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
749    ("v9", Unstable(sym::sparc_target_feature), &[]),
750    // tidy-alphabetical-end
751];
752
753static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
754    // tidy-alphabetical-start
755    ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
756    ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
757    ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]),
758    ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]),
759    ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
760    ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]),
761    // FPU
762    ("isa-68881", Unstable(sym::m68k_target_feature), &[]),
763    ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]),
764    // tidy-alphabetical-end
765];
766
767/// When rustdoc is running, provide a list of all known features so that all their respective
768/// primitives may be documented.
769///
770/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
771pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
772    std::iter::empty()
773        .chain(ARM_FEATURES.iter())
774        .chain(AARCH64_FEATURES.iter())
775        .chain(X86_FEATURES.iter())
776        .chain(HEXAGON_FEATURES.iter())
777        .chain(POWERPC_FEATURES.iter())
778        .chain(MIPS_FEATURES.iter())
779        .chain(RISCV_FEATURES.iter())
780        .chain(WASM_FEATURES.iter())
781        .chain(BPF_FEATURES.iter())
782        .chain(CSKY_FEATURES)
783        .chain(LOONGARCH_FEATURES)
784        .chain(IBMZ_FEATURES)
785        .chain(SPARC_FEATURES)
786        .chain(M68K_FEATURES)
787        .cloned()
788        .map(|(f, s, _)| (f, s))
789}
790
791// These arrays represent the least-constraining feature that is required for vector types up to a
792// certain size to have their "proper" ABI on each architecture.
793// Note that they must be kept sorted by vector size.
794const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
795    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
796const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
797
798// We might want to add "helium" too.
799const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
800
801const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
802const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
803const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
804const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
805    (32, "zvl32b"),
806    (64, "zvl64b"),
807    (128, "zvl128b"),
808    (256, "zvl256b"),
809    (512, "zvl512b"),
810    (1024, "zvl1024b"),
811    (2048, "zvl2048b"),
812    (4096, "zvl4096b"),
813    (8192, "zvl8192b"),
814    (16384, "zvl16384b"),
815    (32768, "zvl32768b"),
816    (65536, "zvl65536b"),
817];
818// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
819const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
820
821const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
822    &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
823const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
824const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
825const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
826    &[(128, "lsx"), (256, "lasx")];
827
828#[derive(Copy, Clone, Debug)]
829pub struct FeatureConstraints {
830    /// Features that must be enabled.
831    pub required: &'static [&'static str],
832    /// Features that must be disabled.
833    pub incompatible: &'static [&'static str],
834}
835
836impl Target {
837    pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
838        match &*self.arch {
839            "arm" => ARM_FEATURES,
840            "aarch64" | "arm64ec" => AARCH64_FEATURES,
841            "x86" | "x86_64" => X86_FEATURES,
842            "hexagon" => HEXAGON_FEATURES,
843            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES,
844            "powerpc" | "powerpc64" => POWERPC_FEATURES,
845            "riscv32" | "riscv64" => RISCV_FEATURES,
846            "wasm32" | "wasm64" => WASM_FEATURES,
847            "bpf" => BPF_FEATURES,
848            "csky" => CSKY_FEATURES,
849            "loongarch64" => LOONGARCH_FEATURES,
850            "s390x" => IBMZ_FEATURES,
851            "sparc" | "sparc64" => SPARC_FEATURES,
852            "m68k" => M68K_FEATURES,
853            _ => &[],
854        }
855    }
856
857    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
858        match &*self.arch {
859            "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
860            "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
861            "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
862            "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
863            "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
864            "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
865            "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
866            "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
867            "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
868            "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
869            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
870            "bpf" | "m68k" => &[], // no vector ABI
871            "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
872            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
873            // when passing args in vector registers.
874            _ => &[],
875        }
876    }
877
878    pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
879        match &*self.arch {
880            "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES,
881            _ => &[],
882        }
883    }
884
885    // Note: the returned set includes `base_feature`.
886    pub fn implied_target_features<'a>(&self, base_feature: &'a str) -> FxHashSet<&'a str> {
887        let implied_features =
888            self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>();
889
890        // Implied target features have their own implied target features, so we traverse the
891        // map until there are no more features to add.
892        let mut features = FxHashSet::default();
893        let mut new_features = vec![base_feature];
894        while let Some(new_feature) = new_features.pop() {
895            if features.insert(new_feature) {
896                if let Some(implied_features) = implied_features.get(&new_feature) {
897                    new_features.extend(implied_features.iter().copied())
898                }
899            }
900        }
901        features
902    }
903
904    /// Returns two lists of features:
905    /// the first list contains target features that must be enabled for ABI reasons,
906    /// and the second list contains target feature that must be disabled for ABI reasons.
907    ///
908    /// These features are automatically appended to whatever the target spec sets as default
909    /// features for the target.
910    ///
911    /// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
912    /// against this. We also check any implied features, based on the information above. If LLVM
913    /// implicitly enables more implied features than we do, that could bypass this check!
914    pub fn abi_required_features(&self) -> FeatureConstraints {
915        const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
916        // Some architectures don't have a clean explicit ABI designation; instead, the ABI is
917        // defined by target features. When that is the case, those target features must be
918        // "forbidden" in the list above to ensure that there is a consistent answer to the
919        // questions "which ABI is used".
920        match &*self.arch {
921            "x86" => {
922                // We use our own ABI indicator here; LLVM does not have anything native.
923                // Every case should require or forbid `soft-float`!
924                match self.rustc_abi {
925                    None => {
926                        // Default hardfloat ABI.
927                        // x87 must be enabled, soft-float must be disabled.
928                        FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
929                    }
930                    Some(RustcAbi::X86Sse2) => {
931                        // Extended hardfloat ABI. x87 and SSE2 must be enabled, soft-float must be disabled.
932                        FeatureConstraints {
933                            required: &["x87", "sse2"],
934                            incompatible: &["soft-float"],
935                        }
936                    }
937                    Some(RustcAbi::X86Softfloat) => {
938                        // Softfloat ABI, requires corresponding target feature. That feature trumps
939                        // `x87` and all other FPU features so those do not matter.
940                        // Note that this one requirement is the entire implementation of the ABI!
941                        // LLVM handles the rest.
942                        FeatureConstraints { required: &["soft-float"], incompatible: &[] }
943                    }
944                }
945            }
946            "x86_64" => {
947                // We use our own ABI indicator here; LLVM does not have anything native.
948                // Every case should require or forbid `soft-float`!
949                match self.rustc_abi {
950                    None => {
951                        // Default hardfloat ABI. On x86-64, this always includes SSE2.
952                        FeatureConstraints {
953                            required: &["x87", "sse2"],
954                            incompatible: &["soft-float"],
955                        }
956                    }
957                    Some(RustcAbi::X86Softfloat) => {
958                        // Softfloat ABI, requires corresponding target feature. That feature trumps
959                        // `x87` and all other FPU features so those do not matter.
960                        // Note that this one requirement is the entire implementation of the ABI!
961                        // LLVM handles the rest.
962                        FeatureConstraints { required: &["soft-float"], incompatible: &[] }
963                    }
964                    Some(r) => panic!("invalid Rust ABI for x86_64: {r:?}"),
965                }
966            }
967            "arm" => {
968                // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate
969                // to LLVM which ABI we are going for.
970                match self.llvm_floatabi.unwrap() {
971                    FloatAbi::Soft => {
972                        // Nothing special required, will use soft-float ABI throughout.
973                        // We can even allow `-soft-float` here; in fact that is useful as it lets
974                        // people use FPU instructions with a softfloat ABI (corresponds to
975                        // `-mfloat-abi=softfp` in GCC/clang).
976                        NOTHING
977                    }
978                    FloatAbi::Hard => {
979                        // Must have `fpregs` and must not have `soft-float`.
980                        FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
981                    }
982                }
983            }
984            "aarch64" | "arm64ec" => {
985                // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
986                // the use of soft-float, so all we can do here is some crude hacks.
987                match &*self.abi {
988                    "softfloat" => {
989                        // LLVM will use float registers when `fp-armv8` is available, e.g. for
990                        // calls to built-ins. The only way to ensure a consistent softfloat ABI
991                        // on aarch64 is to never enable `fp-armv8`, so we enforce that.
992                        // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the
993                        // feature we have to mark as incompatible.
994                        FeatureConstraints { required: &[], incompatible: &["neon"] }
995                    }
996                    _ => {
997                        // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
998                        // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
999                        FeatureConstraints { required: &["neon"], incompatible: &[] }
1000                    }
1001                }
1002            }
1003            "riscv32" | "riscv64" => {
1004                // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1005                // about what the intended ABI is.
1006                match &*self.llvm_abiname {
1007                    "ilp32d" | "lp64d" => {
1008                        // Requires d (which implies f), incompatible with e and zfinx.
1009                        FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] }
1010                    }
1011                    "ilp32f" | "lp64f" => {
1012                        // Requires f, incompatible with e and zfinx.
1013                        FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] }
1014                    }
1015                    "ilp32" | "lp64" => {
1016                        // Requires nothing, incompatible with e.
1017                        FeatureConstraints { required: &[], incompatible: &["e"] }
1018                    }
1019                    "ilp32e" => {
1020                        // ilp32e is documented to be incompatible with features that need aligned
1021                        // load/stores > 32 bits, like `d`. (One could also just generate more
1022                        // complicated code to align the stack when needed, but the RISCV
1023                        // architecture manual just explicitly rules out this combination so we
1024                        // might as well.)
1025                        // Note that the `e` feature is not required: the ABI treats the extra
1026                        // registers as caller-save, so it is safe to use them only in some parts of
1027                        // a program while the rest doesn't know they even exist.
1028                        FeatureConstraints { required: &[], incompatible: &["d"] }
1029                    }
1030                    "lp64e" => {
1031                        // As above, `e` is not required.
1032                        NOTHING
1033                    }
1034                    _ => unreachable!(),
1035                }
1036            }
1037            "loongarch64" => {
1038                // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1039                // about what the intended ABI is.
1040                match &*self.llvm_abiname {
1041                    "ilp32d" | "lp64d" => {
1042                        // Requires d (which implies f), incompatible with nothing.
1043                        FeatureConstraints { required: &["d"], incompatible: &[] }
1044                    }
1045                    "ilp32f" | "lp64f" => {
1046                        // Requires f, incompatible with nothing.
1047                        FeatureConstraints { required: &["f"], incompatible: &[] }
1048                    }
1049                    "ilp32s" | "lp64s" => {
1050                        // The soft-float ABI does not require any features and is also not
1051                        // incompatible with any features. Rust targets explicitly specify the
1052                        // LLVM ABI names, which allows for enabling hard-float support even on
1053                        // soft-float targets, and ensures that the ABI behavior is as expected.
1054                        NOTHING
1055                    }
1056                    _ => unreachable!(),
1057                }
1058            }
1059            _ => NOTHING,
1060        }
1061    }
1062}