Skip to main content

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.
4//!
5//! The target features listed here can be used in `#[target_feature]` and `#[cfg(target_feature)]`.
6//! They also do not trigger any warnings when used with `-Ctarget-feature`.
7//!
8//! Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature`
9//! on stable. Using a feature not on the list of Rust target features only emits a warning.
10//! Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating.
11//! `cfg(target_feature)` for unstable features just works on nightly without any feature gate.
12//! `#[target_feature]` requires a feature gate.
13//!
14//! When adding features to the below lists
15//! check whether they're named already elsewhere in rust
16//! e.g. in stdarch and whether the given name matches LLVM's
17//! if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted.
18//! Additionally, if the feature is not available in older version of LLVM supported by the current
19//! rust, the same function must be updated to filter out these features to avoid triggering
20//! warnings.
21//!
22//! Also note that all target features listed here must be purely additive: for target_feature 1.1 to
23//! be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a
24//! per-function level, since we would then allow safe calls from functions with `+soft-float` to
25//! functions without that feature!
26//!
27//! It is important for soundness to consider the interaction of target features and the function
28//! call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
29//! arguments, so letting people toggle that feature would be unsound. To this end, the
30//! [`Target::abi_required_features`] function computes which target features must and must not be
31//! enabled for any given target, and individual features can also be marked as [`InternalOnly`].
32//! See <https://github.com/rust-lang/rust/issues/116344> for some more context.
33//!
34//! The one exception to features that change the ABI is features that enable larger vector
35//! registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store
36//! information about which target feature is ABI-required for which vector size; this is used to
37//! ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For
38//! the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.)
39//! Also see <https://github.com/rust-lang/rust/issues/116558>.
40//!
41//! Stabilizing a target feature requires t-lang approval.
42use rustc_data_structures::fx::{FxHashMap, FxHashSet};
43use rustc_macros::StableHash;
44use rustc_span::{Symbol, sym};
45
46use crate::spec::{Arch, FloatAbi, LlvmAbi, RustcAbi, Target};
47
48/// Features that control behaviour of rustc, rather than the codegen. Not to be included in
49/// `cfg(target_feature)`, `sess.internal_target_features`, or the backend's feature list.
50/// These exist globally and are not in the target-specific lists below.
51pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
52
53/// Stability information for target features.
54#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Stability {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Stability::Stable =>
                ::core::fmt::Formatter::write_str(f, "Stable"),
            Stability::CfgStableToggleUnstable(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "CfgStableToggleUnstable", &__self_0),
            Stability::Unstable(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Unstable", &__self_0),
            Stability::InternalOnly { reason: __self_0, hard_error: __self_1 }
                =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "InternalOnly", "reason", __self_0, "hard_error",
                    &__self_1),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for Stability { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Stability { }
#[automatically_derived]
impl ::core::clone::Clone for Stability {
    #[inline]
    fn clone(&self) -> Stability {
        let _: ::core::clone::AssertParamIsClone<Symbol>;
        let _: ::core::clone::AssertParamIsClone<&'static str>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for Stability {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    Stability::Stable => {}
                    Stability::CfgStableToggleUnstable(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    Stability::Unstable(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    Stability::InternalOnly {
                        reason: ref __binding_0, hard_error: ref __binding_1 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash)]
55pub enum Stability {
56    /// This target feature is stable, it can be used in `#[target_feature]` and
57    /// `#[cfg(target_feature)]`.
58    Stable,
59    /// This target feature is cfg-stable. It can be used for `#[cfg(target_feature)]` on stable,
60    /// but using it in `#[target_feature]` requires the given nightly feature.
61    CfgStableToggleUnstable(
62        /// This must be a *language* feature, or else rustc will ICE when reporting a missing
63        /// feature gate!
64        Symbol,
65    ),
66    /// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on
67    /// nightly and using it in `#[target_feature]` requires enabling the given nightly feature.
68    Unstable(
69        /// This must be a *language* feature, or else rustc will ICE when reporting a missing
70        /// feature gate!
71        Symbol,
72    ),
73    /// This is not actually something we expose as a "target feature" to our users.
74    /// We just manage it internally as a target feature since that's how LLVM represents it.
75    /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be
76    /// set in the target spec. It is never set in `cfg(target_feature)`. Used in particular for
77    /// features are actually ABI configuration flags (such as "soft-float" on many targets).
78    ///
79    /// However, "internal" target features can still sometimes be enabled or disabled via
80    /// `-Ctarget-cpu` or Rust/LLVM target feature implications. Make sure nothing implies this
81    /// target feature and nothing is implied by this target feature (except for other internal-only
82    /// features). Ideally, ABI-relevant target features are pinned down (marked as required or
83    /// incompatible) in [`Target::abi_required_features`].
84    InternalOnly {
85        reason: &'static str,
86        /// True if this is always an error, false if this can be reported as a warning when set via
87        /// `-Ctarget-feature` (and a hard error when set via `#[target_feature]`).
88        hard_error: bool,
89    },
90}
91use Stability::*;
92
93impl Stability {
94    /// Returns whether the feature can be used in `cfg(target_feature)` ever.
95    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
96    /// `requires_nightly`.)
97    pub fn in_cfg(&self) -> bool {
98        #[allow(non_exhaustive_omitted_patterns)] match self {
    Stability::Stable | Stability::CfgStableToggleUnstable { .. } |
        Stability::Unstable { .. } => true,
    _ => false,
}matches!(
99            self,
100            Stability::Stable
101                | Stability::CfgStableToggleUnstable { .. }
102                | Stability::Unstable { .. }
103        )
104    }
105
106    /// Returns the nightly feature that is required to toggle this target feature via
107    /// `#[target_feature]`/`-Ctarget-feature` or to test it via `cfg(target_feature)`.
108    /// (For `cfg` we only care whether the feature is nightly or not, we don't require
109    /// the feature gate to actually be enabled when using a nightly compiler.)
110    ///
111    /// Before calling this, ensure the feature is even permitted for this use:
112    /// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()`
113    /// - for `cfg(target_feature)`, check `in_cfg()`
114    ///
115    /// The `in_cfg` parameter is used to determine whether it will be used in
116    /// `cfg(target_feature)` (true) or `#[target_feature]`/`-Ctarget-feature` (false)
117    pub fn requires_nightly(&self, in_cfg: bool) -> Option<Symbol> {
118        match *self {
119            Stability::Unstable(nightly_feature) => Some(nightly_feature),
120            Stability::CfgStableToggleUnstable(nightly_feature) => {
121                if in_cfg {
122                    None
123                } else {
124                    Some(nightly_feature)
125                }
126            }
127            Stability::Stable { .. } => None,
128            Stability::InternalOnly { .. } => {
129                {
    ::core::panicking::panic_fmt(format_args!("internal-only features should not reach this far"));
}panic!("internal-only features should not reach this far")
130            }
131        }
132    }
133
134    /// Returns whether the feature is cfg-stable but still requires a nightly feature gate to
135    /// be used in `#[target_feature]`/`-Ctarget-feature`.
136    pub fn is_cfg_stable_toggle_unstable(&self) -> bool {
137        #[allow(non_exhaustive_omitted_patterns)] match self {
    Stability::CfgStableToggleUnstable { .. } => true,
    _ => false,
}matches!(self, Stability::CfgStableToggleUnstable { .. })
138    }
139
140    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
141    /// (It might still be nightly-only even if this returns `Ok(())`, so make sure to also check
142    /// `requires_nightly`.)
143    pub fn toggle_allowed(&self) -> Result<(), &'static str> {
144        match self {
145            Stability::Unstable(_)
146            | Stability::CfgStableToggleUnstable(_)
147            | Stability::Stable { .. } => Ok(()),
148            Stability::InternalOnly { reason, hard_error: _ } => Err(reason),
149        }
150    }
151}
152
153/// If feature A "implies" feature B, then:
154/// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B
155/// - when B gets disabled (via `-Ctarget-feature`), we also disable A
156///
157/// Both of these are also applied transitively.
158type ImpliedFeatures = &'static [&'static str];
159
160static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
161    // tidy-alphabetical-start
162    ("aclass", Unstable(sym::arm_target_feature), &[]),
163    ("acquire-release", Unstable(sym::arm_target_feature), &[]),
164    ("aes", Unstable(sym::arm_target_feature), &["neon"]),
165    (
166        "atomics-32",
167        // Not implied by any CPU model or other feature.
168        Stability::InternalOnly {
169            reason: "unsound because it changes the ABI of atomic operations",
170            hard_error: false,
171        },
172        &[],
173    ),
174    ("crc", Unstable(sym::arm_target_feature), &[]),
175    ("d32", Unstable(sym::arm_target_feature), &[]),
176    ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
177    ("dsp", Unstable(sym::arm_target_feature), &[]),
178    ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
179    ("fp16", Unstable(sym::arm_target_feature), &["neon"]),
180    ("fp64", Unstable(sym::arm_target_feature), &[]),
181    ("fpregs", Unstable(sym::arm_target_feature), &[]),
182    ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
183    ("mclass", Unstable(sym::arm_target_feature), &[]),
184    ("mve", Unstable(sym::arm_target_feature), &["v8.1m.main", "dsp", "fpregs"]),
185    ("mve.fp", Unstable(sym::arm_target_feature), &["mve"]),
186    ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
187    ("rclass", Unstable(sym::arm_target_feature), &[]),
188    ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
189    // This can be *disabled* on non-`hf` targets to enable the use
190    // of hardfloats while keeping the softfloat ABI.
191    // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of
192    // matching the odd negative feature LLVM uses?
193    ("soft-float", Unstable(sym::arm_target_feature), &[]),
194    // This is needed for inline assembly, but shouldn't be stabilized as-is
195    // since it should be enabled per-function using #[instruction_set], not
196    // #[target_feature].
197    ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
198    ("thumb2", Unstable(sym::arm_target_feature), &[]),
199    ("trustzone", Unstable(sym::arm_target_feature), &[]),
200    ("v5te", Unstable(sym::arm_target_feature), &[]),
201    ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
202    ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
203    ("v6m", Unstable(sym::arm_target_feature), &["v6"]),
204    ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]),
205    ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
206    ("v8", Unstable(sym::arm_target_feature), &["v7", "acquire-release"]),
207    ("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]),
208    ("v8m", Unstable(sym::arm_target_feature), &["v6m"]),
209    ("v8m.main", Unstable(sym::arm_target_feature), &["v7"]),
210    ("vfp2", Unstable(sym::arm_target_feature), &["vfp2sp", "fp64"]),
211    ("vfp2sp", Unstable(sym::arm_target_feature), &["fpregs"]),
212    ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
213    ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
214    ("virtualization", Unstable(sym::arm_target_feature), &[]),
215    // tidy-alphabetical-end
216];
217
218static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
219    // tidy-alphabetical-start
220    // FEAT_AES & FEAT_PMULL
221    ("aes", Stable, &["neon"]),
222    // FEAT_BF16
223    ("bf16", Stable, &[]),
224    // FEAT_BTI
225    ("bti", Stable, &[]),
226    // FEAT_CRC
227    ("crc", Stable, &[]),
228    // FEAT_CSSC
229    ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]),
230    // FEAT_DIT
231    ("dit", Stable, &[]),
232    // FEAT_DotProd
233    ("dotprod", Stable, &["neon"]),
234    // FEAT_DPB
235    ("dpb", Stable, &[]),
236    // FEAT_DPB2
237    ("dpb2", Stable, &["dpb"]),
238    // FEAT_ECV
239    ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]),
240    // FEAT_F32MM
241    ("f32mm", Stable, &["sve"]),
242    // FEAT_F64MM
243    ("f64mm", Stable, &["sve"]),
244    // FEAT_FAMINMAX
245    ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]),
246    // FEAT_FCMA
247    ("fcma", Stable, &["neon"]),
248    // FEAT_FHM
249    ("fhm", Stable, &["fp16"]),
250    // FEAT_FLAGM
251    ("flagm", Stable, &[]),
252    // FEAT_FLAGM2
253    ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]),
254    // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`.
255    (
256        "fp-armv8",
257        // Pinned down by [`Target::abi_required_features`] when needed.
258        Stability::InternalOnly { reason: "Rust ties `fp-armv8` to `neon`", hard_error: false },
259        &[],
260    ),
261    // FEAT_FP8
262    ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]),
263    // FEAT_FP8DOT2
264    ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]),
265    // FEAT_FP8DOT4
266    ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]),
267    // FEAT_FP8FMA
268    ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]),
269    // FEAT_FP16
270    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
271    ("fp16", Stable, &["neon"]),
272    // FEAT_FRINTTS
273    ("frintts", Stable, &[]),
274    // FEAT_HBC
275    ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]),
276    // FEAT_I8MM
277    ("i8mm", Stable, &[]),
278    // FEAT_JSCVT
279    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
280    ("jsconv", Stable, &["neon"]),
281    // FEAT_LOR
282    ("lor", Stable, &[]),
283    // FEAT_LSE
284    ("lse", Stable, &[]),
285    // FEAT_LSE2
286    ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]),
287    // FEAT_LSE128
288    ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]),
289    // FEAT_LUT
290    ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]),
291    // FEAT_MOPS
292    ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]),
293    // FEAT_MTE & FEAT_MTE2
294    ("mte", Stable, &[]),
295    // FEAT_AdvSimd & FEAT_FP
296    ("neon", Stable, &[]),
297    // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be
298    // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally
299    // using slower non-LSE operations. Unstable since it doesn't need to user-togglable.
300    ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]),
301    // FEAT_PAUTH (address authentication)
302    ("paca", Stable, &[]),
303    // FEAT_PAUTH (generic authentication)
304    ("pacg", Stable, &[]),
305    // FEAT_PAN
306    ("pan", Stable, &[]),
307    // FEAT_PAuth_LR
308    ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
309    // FEAT_PMUv3
310    ("pmuv3", Stable, &[]),
311    // FEAT_RNG
312    ("rand", Stable, &[]),
313    // FEAT_RAS & FEAT_RASv1p1
314    ("ras", Stable, &[]),
315    // FEAT_LRCPC
316    ("rcpc", Stable, &[]),
317    // FEAT_LRCPC2
318    ("rcpc2", Stable, &["rcpc"]),
319    // FEAT_LRCPC3
320    ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
321    // FEAT_RDM
322    ("rdm", Stable, &["neon"]),
323    (
324        "reserve-x18",
325        // Not implied by any CPU model or other feature; the compiler flag is a target modifier.
326        InternalOnly { reason: "use `-Zfixed-x18` compiler flag instead", hard_error: false },
327        &[],
328    ),
329    // FEAT_SB
330    ("sb", Stable, &[]),
331    // FEAT_SHA1 & FEAT_SHA256
332    ("sha2", Stable, &["neon"]),
333    // FEAT_SHA512 & FEAT_SHA3
334    ("sha3", Stable, &["sha2"]),
335    // FEAT_SM3 & FEAT_SM4
336    ("sm4", Stable, &["neon"]),
337    // FEAT_SME
338    ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
339    // FEAT_SME_B16B16
340    ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]),
341    // FEAT_SME_F8F16
342    ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]),
343    // FEAT_SME_F8F32
344    ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
345    // FEAT_SME_F16F16
346    ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
347    // FEAT_SME_F64F64
348    ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
349    // FEAT_SME_FA64
350    ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]),
351    // FEAT_SME_I16I64
352    ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
353    // FEAT_SME_LUTv2
354    ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]),
355    // FEAT_SME2
356    ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
357    // FEAT_SME2p1
358    ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
359    // FEAT_SPE
360    ("spe", Stable, &[]),
361    // FEAT_SSBS & FEAT_SSBS2
362    ("ssbs", Stable, &[]),
363    // FEAT_SSVE_FP8FDOT2
364    ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]),
365    // FEAT_SSVE_FP8FDOT4
366    ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]),
367    // FEAT_SSVE_FP8FMA
368    ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
369    // FEAT_SVE
370    // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
371    //
372    // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
373    // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
374    //
375    // "For backwards compatibility, Neon and VFP are required in the latest architectures."
376    ("sve", Stable, &["neon", "fp16"]),
377    // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions)
378    ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
379    // FEAT_SVE2
380    ("sve2", Stable, &["sve"]),
381    // FEAT_SVE_AES & FEAT_SVE_PMULL128
382    ("sve2-aes", Stable, &["sve2", "aes"]),
383    // FEAT_SVE2_BitPerm
384    ("sve2-bitperm", Stable, &["sve2"]),
385    // FEAT_SVE2_SHA3
386    ("sve2-sha3", Stable, &["sve2", "sha3"]),
387    // FEAT_SVE2_SM4
388    ("sve2-sm4", Stable, &["sve2", "sm4"]),
389    // FEAT_SVE2p1
390    ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]),
391    // FEAT_TME
392    ("tme", Stable, &[]),
393    (
394        "v8.1a",
395        Unstable(sym::aarch64_ver_target_feature),
396        &["crc", "lse", "rdm", "pan", "lor", "vh"],
397    ),
398    ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
399    (
400        "v8.3a",
401        Unstable(sym::aarch64_ver_target_feature),
402        &["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
403    ),
404    ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
405    ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
406    ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
407    ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]),
408    ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]),
409    ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]),
410    ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]),
411    ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]),
412    ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]),
413    ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]),
414    ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]),
415    ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a"]),
416    // FEAT_VHE
417    ("vh", Stable, &[]),
418    // FEAT_WFxT
419    ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]),
420    // tidy-alphabetical-end
421];
422
423const AARCH64_TIED_FEATURES: &[&[&str]] = &[
424    &["paca", "pacg"], // Together these represent `pauth` in LLVM
425];
426
427static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
428    // tidy-alphabetical-start
429    ("adx", Stable, &[]),
430    ("aes", Stable, &["sse2"]),
431    ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
432    ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
433    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
434    ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
435    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
436    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
437    ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
438    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
439    ("apxf", Unstable(sym::apx_target_feature), &[]),
440    ("avx", Stable, &["sse4.2"]),
441    ("avx2", Stable, &["avx"]),
442    (
443        "avx10.1",
444        Unstable(sym::avx10_target_feature),
445        &[
446            "avx512bf16",
447            "avx512bitalg",
448            "avx512bw",
449            "avx512cd",
450            "avx512dq",
451            "avx512f",
452            "avx512fp16",
453            "avx512ifma",
454            "avx512vbmi",
455            "avx512vbmi2",
456            "avx512vl",
457            "avx512vnni",
458            "avx512vpopcntdq",
459        ],
460    ),
461    (
462        "avx10.2",
463        Unstable(sym::avx10_target_feature),
464        &["avx10.1", "avxvnni", "avxvnniint8", "avxvnniint16"],
465    ),
466    ("avx512bf16", Stable, &["avx512bw"]),
467    ("avx512bitalg", Stable, &["avx512bw"]),
468    ("avx512bw", Stable, &["avx512f"]),
469    ("avx512cd", Stable, &["avx512f"]),
470    ("avx512dq", Stable, &["avx512f"]),
471    ("avx512f", Stable, &["avx2", "fma", "f16c"]),
472    ("avx512fp16", Stable, &["avx512bw"]),
473    ("avx512ifma", Stable, &["avx512f"]),
474    ("avx512vbmi", Stable, &["avx512bw"]),
475    ("avx512vbmi2", Stable, &["avx512bw"]),
476    ("avx512vl", Stable, &["avx512f"]),
477    ("avx512vnni", Stable, &["avx512f"]),
478    ("avx512vp2intersect", Stable, &["avx512f"]),
479    ("avx512vpopcntdq", Stable, &["avx512f"]),
480    ("avxifma", Stable, &["avx2"]),
481    ("avxneconvert", Stable, &["avx2"]),
482    ("avxvnni", Stable, &["avx2"]),
483    ("avxvnniint8", Stable, &["avx2"]),
484    ("avxvnniint16", Stable, &["avx2"]),
485    ("bmi1", Stable, &[]),
486    ("bmi2", Stable, &[]),
487    ("clflushopt", Unstable(sym::clflushopt_target_feature), &[]),
488    ("cmpxchg16b", Stable, &[]),
489    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
490    ("f16c", Stable, &["avx"]),
491    ("fma", Stable, &["avx"]),
492    ("fma4", Unstable(sym::fma4_target_feature), &["avx", "sse4a"]),
493    ("fxsr", Stable, &[]),
494    ("gfni", Stable, &["sse2"]),
495    ("kl", Stable, &["sse2"]),
496    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
497    ("lzcnt", Stable, &[]),
498    ("movbe", Stable, &[]),
499    ("movrs", Unstable(sym::movrs_target_feature), &[]),
500    ("pclmulqdq", Stable, &["sse2"]),
501    ("popcnt", Stable, &[]),
502    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
503    ("rdrand", Stable, &[]),
504    ("rdseed", Stable, &[]),
505    (
506        "retpoline-external-thunk",
507        // Not implied by any CPU model or other feature; the compiler flag is a target modifier.
508        Stability::InternalOnly {
509            reason: "use `-Zretpoline-external-thunk` compiler flag instead",
510            hard_error: false,
511        },
512        &[],
513    ),
514    (
515        "retpoline-indirect-branches",
516        // Not implied by any CPU model or other feature; the compiler flag is a target modifier.
517        Stability::InternalOnly {
518            reason: "use `-Zretpoline` compiler flag instead",
519            hard_error: false,
520        },
521        &[],
522    ),
523    (
524        "retpoline-indirect-calls",
525        // Not implied by any CPU model or other feature; the compiler flag is a target modifier.
526        Stability::InternalOnly {
527            reason: "use `-Zretpoline` compiler flag instead",
528            hard_error: false,
529        },
530        &[],
531    ),
532    ("rtm", Unstable(sym::rtm_target_feature), &[]),
533    ("sha", Stable, &["sse2"]),
534    ("sha512", Stable, &["avx2"]),
535    ("sm3", Stable, &["avx"]),
536    ("sm4", Stable, &["avx2"]),
537    (
538        "soft-float",
539        // Pinned down by [`Target::abi_required_features`].
540        Stability::InternalOnly { reason: "use a soft-float target instead", hard_error: false },
541        &[],
542    ),
543    ("sse", Stable, &[]),
544    ("sse2", Stable, &["sse"]),
545    ("sse3", Stable, &["sse2"]),
546    ("sse4.1", Stable, &["ssse3"]),
547    ("sse4.2", Stable, &["sse4.1"]),
548    ("sse4a", Stable, &["sse3"]),
549    ("ssse3", Stable, &["sse3"]),
550    ("tbm", Stable, &[]),
551    ("vaes", Stable, &["avx2", "aes"]),
552    ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]),
553    ("widekl", Stable, &["kl"]),
554    ("x87", Unstable(sym::x87_target_feature), &[]),
555    ("xop", Unstable(sym::xop_target_feature), &["fma4", "avx", "sse4a"]),
556    ("xsave", Stable, &[]),
557    ("xsavec", Stable, &["xsave"]),
558    ("xsaveopt", Stable, &["xsave"]),
559    ("xsaves", Stable, &["xsave"]),
560    // tidy-alphabetical-end
561];
562
563const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
564    // tidy-alphabetical-start
565    ("audio", Unstable(sym::hexagon_target_feature), &[]),
566    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
567    ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]),
568    ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]),
569    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
570    ("hvx-qfloat", Unstable(sym::hexagon_target_feature), &["hvx"]),
571    ("hvxv60", Unstable(sym::hexagon_target_feature), &["hvx"]),
572    ("hvxv62", Unstable(sym::hexagon_target_feature), &["hvxv60"]),
573    ("hvxv65", Unstable(sym::hexagon_target_feature), &["hvxv62"]),
574    ("hvxv66", Unstable(sym::hexagon_target_feature), &["hvxv65", "zreg"]),
575    ("hvxv67", Unstable(sym::hexagon_target_feature), &["hvxv66"]),
576    ("hvxv68", Unstable(sym::hexagon_target_feature), &["hvxv67"]),
577    ("hvxv69", Unstable(sym::hexagon_target_feature), &["hvxv68"]),
578    ("hvxv71", Unstable(sym::hexagon_target_feature), &["hvxv69"]),
579    ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]),
580    ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]),
581    ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]),
582    ("v60", Unstable(sym::hexagon_target_feature), &[]),
583    ("v62", Unstable(sym::hexagon_target_feature), &["v60"]),
584    ("v65", Unstable(sym::hexagon_target_feature), &["v62"]),
585    ("v66", Unstable(sym::hexagon_target_feature), &["v65"]),
586    ("v67", Unstable(sym::hexagon_target_feature), &["v66"]),
587    ("v68", Unstable(sym::hexagon_target_feature), &["v67"]),
588    ("v69", Unstable(sym::hexagon_target_feature), &["v68"]),
589    ("v71", Unstable(sym::hexagon_target_feature), &["v69"]),
590    ("v73", Unstable(sym::hexagon_target_feature), &["v71"]),
591    ("v75", Unstable(sym::hexagon_target_feature), &["v73"]),
592    ("v79", Unstable(sym::hexagon_target_feature), &["v75"]),
593    ("zreg", Unstable(sym::hexagon_target_feature), &[]),
594    // tidy-alphabetical-end
595];
596
597static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
598    // If you are thinking of adding "efpu2" here, please double-check that it really does not
599    // affect the ABI.
600    // tidy-alphabetical-start
601    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
602    (
603        "hard-float",
604        // Pinned down by [`Target::abi_required_features`].
605        InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false },
606        &[],
607    ),
608    ("msync", Unstable(sym::powerpc_target_feature), &[]),
609    ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
610    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
611    ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
612    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
613    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
614    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
615    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
616    ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]),
617    (
618        "spe",
619        // Pinned down by [`Target::abi_required_features`].
620        InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false },
621        &[],
622    ),
623    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
624    // tidy-alphabetical-end
625];
626
627const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
628    // tidy-alphabetical-start
629    ("fp64", Unstable(sym::mips_target_feature), &[]),
630    // FIXME(#150253): msa requires either fp64 or no hard float support at all: LLVM requires fp64
631    // FIXME(#150253): msa requires revision 5 or greater (mips32r5/mips64r5 in LLVM)
632    ("msa", Unstable(sym::mips_target_feature), &[]),
633    ("virt", Unstable(sym::mips_target_feature), &[]),
634    // tidy-alphabetical-end
635];
636
637const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
638    // tidy-alphabetical-start
639    ("sm_70", Unstable(sym::nvptx_target_feature), &[]),
640    ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]),
641    ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]),
642    ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]),
643    ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]),
644    ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]),
645    ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]),
646    ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]),
647    ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]),
648    // tidy-alphabetical-end
649    // tidy-alphabetical-start
650    ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]),
651    ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]),
652    ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]),
653    ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]),
654    ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]),
655    ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]),
656    // tidy-alphabetical-end
657    // tidy-alphabetical-start
658    ("ptx70", Unstable(sym::nvptx_target_feature), &[]),
659    ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]),
660    ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]),
661    ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]),
662    ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]),
663    ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]),
664    ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]),
665    ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]),
666    ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]),
667    ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]),
668    ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]),
669    ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]),
670    ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]),
671    ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]),
672    ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]),
673    ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]),
674    ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]),
675    // tidy-alphabetical-end
676];
677
678static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
679    // tidy-alphabetical-start
680    ("a", Stable, &["zaamo", "zalrsc"]),
681    ("b", Stable, &["zba", "zbb", "zbs"]),
682    ("c", Stable, &["zca"]),
683    ("d", Unstable(sym::riscv_target_feature), &["f"]),
684    ("e", Unstable(sym::riscv_target_feature), &[]),
685    ("f", Unstable(sym::riscv_target_feature), &["zicsr"]),
686    (
687        "forced-atomics",
688        // Not implied by any CPU model or other feature.
689        Stability::InternalOnly {
690            reason: "unsound because it changes the ABI of atomic operations",
691            hard_error: false,
692        },
693        &[],
694    ),
695    ("m", Stable, &[]),
696    ("relax", Unstable(sym::riscv_target_feature), &[]),
697    (
698        "rva23u64",
699        Unstable(sym::riscv_target_feature),
700        &[
701            "m",
702            "a",
703            "f",
704            "d",
705            "c",
706            "b",
707            "v",
708            "zicsr",
709            "zicntr",
710            "zihpm",
711            "ziccif",
712            "ziccrse",
713            "ziccamoa",
714            "zicclsm",
715            "zic64b",
716            "za64rs",
717            "zihintpause",
718            "zba",
719            "zbb",
720            "zbs",
721            "zicbom",
722            "zicbop",
723            "zicboz",
724            "zfhmin",
725            "zkt",
726            "zvfhmin",
727            "zvbb",
728            "zvkt",
729            "zihintntl",
730            "zicond",
731            "zimop",
732            "zcmop",
733            "zcb",
734            "zfa",
735            "zawrs",
736            "supm",
737        ],
738    ),
739    ("supm", Unstable(sym::riscv_target_feature), &[]),
740    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
741    ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]),
742    ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]),
743    ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs
744    ("za128rs", Stable, &[]),
745    ("zaamo", Stable, &[]),
746    ("zabha", Stable, &["zaamo"]),
747    ("zacas", Stable, &["zaamo"]),
748    ("zalrsc", Stable, &[]),
749    ("zama16b", Stable, &[]),
750    ("zawrs", Stable, &[]),
751    ("zba", Stable, &[]),
752    ("zbb", Stable, &[]),
753    ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc
754    ("zbkb", Stable, &[]),
755    ("zbkc", Stable, &[]),
756    ("zbkx", Stable, &[]),
757    ("zbs", Stable, &[]),
758    ("zca", Stable, &[]),
759    ("zcb", Stable, &["zca"]),
760    ("zcmop", Stable, &["zca"]),
761    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
762    ("zfa", Unstable(sym::riscv_target_feature), &["f"]),
763    ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin
764    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
765    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
766    ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]),
767    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
768    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
769    ("zic64b", Stable, &[]),
770    ("zicbom", Stable, &[]),
771    ("zicbop", Stable, &[]),
772    ("zicboz", Stable, &[]),
773    ("ziccamoa", Stable, &[]),
774    ("ziccif", Stable, &[]),
775    ("zicclsm", Stable, &[]),
776    ("ziccrse", Stable, &[]),
777    ("zicntr", Stable, &["zicsr"]),
778    ("zicond", Stable, &[]),
779    ("zicsr", Stable, &[]),
780    ("zifencei", Stable, &[]),
781    ("zihintntl", Stable, &[]),
782    ("zihintpause", Stable, &[]),
783    ("zihpm", Stable, &["zicsr"]),
784    ("zimop", Stable, &[]),
785    ("zk", Stable, &["zkn", "zkr", "zkt"]),
786    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
787    ("zknd", Stable, &["zkne_or_zknd"]),
788    ("zkne", Stable, &["zkne_or_zknd"]),
789    ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension
790    ("zknh", Stable, &[]),
791    ("zkr", Stable, &[]),
792    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
793    ("zksed", Stable, &[]),
794    ("zksh", Stable, &[]),
795    ("zkt", Stable, &[]),
796    ("ztso", Stable, &[]),
797    ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb
798    ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
799    ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
800    ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]),
801    ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]),
802    ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]),
803    ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]),
804    ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
805    ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]),
806    ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin
807    ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
808    ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]),
809    ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]),
810    ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]),
811    ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]),
812    ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]),
813    ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]),
814    ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]),
815    ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha
816    ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]),
817    ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]),
818    ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]),
819    ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]),
820    ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]),
821    ("zvkt", Unstable(sym::riscv_target_feature), &[]),
822    ("zvl32b", Unstable(sym::riscv_target_feature), &[]),
823    ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]),
824    ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]),
825    ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]),
826    ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]),
827    ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]),
828    ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]),
829    ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]),
830    ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]),
831    ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]),
832    ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]),
833    ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]),
834    // tidy-alphabetical-end
835];
836
837static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
838    // tidy-alphabetical-start
839    ("atomics", Unstable(sym::wasm_target_feature), &[]),
840    ("bulk-memory", Stable, &[]),
841    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
842    ("extended-const", Stable, &[]),
843    ("gc", Unstable(sym::wasm_target_feature), &["reference-types"]),
844    ("multivalue", Stable, &[]),
845    ("mutable-globals", Stable, &[]),
846    ("nontrapping-fptoint", Stable, &[]),
847    ("reference-types", Stable, &[]),
848    ("relaxed-simd", Stable, &["simd128"]),
849    ("sign-ext", Stable, &[]),
850    ("simd128", Stable, &[]),
851    ("tail-call", Stable, &[]),
852    ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
853    // tidy-alphabetical-end
854];
855
856const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
857    ("alu32", Unstable(sym::bpf_target_feature), &[]),
858    ("allows-misaligned-mem-access", Unstable(sym::bpf_target_feature), &[]),
859];
860
861static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
862    // tidy-alphabetical-start
863    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
864    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
865    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
866    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
867    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
868    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
869    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
870    ("cache", Unstable(sym::csky_target_feature), &[]),
871    ("doloop", Unstable(sym::csky_target_feature), &[]),
872    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
873    ("dspe60", Unstable(sym::csky_target_feature), &[]),
874    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
875    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
876    ("edsp", Unstable(sym::csky_target_feature), &[]),
877    ("elrw", Unstable(sym::csky_target_feature), &[]),
878    ("float1e2", Unstable(sym::csky_target_feature), &[]),
879    ("float1e3", Unstable(sym::csky_target_feature), &[]),
880    ("float3e4", Unstable(sym::csky_target_feature), &[]),
881    ("float7e60", Unstable(sym::csky_target_feature), &[]),
882    ("floate1", Unstable(sym::csky_target_feature), &[]),
883    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
884    ("high-registers", Unstable(sym::csky_target_feature), &[]),
885    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
886    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
887    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
888    ("nvic", Unstable(sym::csky_target_feature), &[]),
889    ("trust", Unstable(sym::csky_target_feature), &[]),
890    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
891    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
892    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
893    // tidy-alphabetical-end
894    //fpu
895    // tidy-alphabetical-start
896    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
897    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
898    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
899    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
900    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
901    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
902    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
903    ("hard-float", Unstable(sym::csky_target_feature), &[]),
904    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
905    // tidy-alphabetical-end
906];
907
908static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
909    // tidy-alphabetical-start
910    ("32s", Unstable(sym::loongarch_target_feature), &[]),
911    ("d", Stable, &["f"]),
912    ("div32", Stable, &[]),
913    ("f", Stable, &[]),
914    ("frecipe", Stable, &[]),
915    ("lam-bh", Stable, &[]),
916    ("lamcas", Stable, &[]),
917    ("lasx", Stable, &["lsx"]),
918    ("lbt", Stable, &[]),
919    ("ld-seq-sa", Stable, &[]),
920    ("lsx", Stable, &["d"]),
921    ("lvz", Stable, &[]),
922    ("relax", Unstable(sym::loongarch_target_feature), &[]),
923    ("scq", Stable, &[]),
924    ("ual", Unstable(sym::loongarch_target_feature), &[]),
925    // tidy-alphabetical-end
926];
927
928#[rustfmt::skip]
929const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
930    // tidy-alphabetical-start
931    // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker
932    ("backchain", Unstable(sym::s390x_target_feature), &[]),
933    ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
934    ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
935    ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]),
936    ("guarded-storage", Unstable(sym::s390x_target_feature), &[]),
937    ("high-word", Unstable(sym::s390x_target_feature), &[]),
938    // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11.
939    ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]),
940    ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]),
941    ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]),
942    ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]),
943    ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]),
944    ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]),
945    ("miscellaneous-extensions-2", Stable, &[]),
946    ("miscellaneous-extensions-3", Stable, &[]),
947    ("miscellaneous-extensions-4", Stable, &[]),
948    ("nnp-assist", Stable, &["vector"]),
949    // Pinned down by [`Target::abi_required_features`].
950    ("soft-float", InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, &[]),
951    ("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
952    ("vector", Stable, &[]),
953    ("vector-enhancements-1", Stable, &["vector"]),
954    ("vector-enhancements-2", Stable, &["vector-enhancements-1"]),
955    ("vector-enhancements-3", Stable, &["vector-enhancements-2"]),
956    ("vector-packed-decimal", Stable, &["vector"]),
957    ("vector-packed-decimal-enhancement", Stable, &["vector-packed-decimal"]),
958    ("vector-packed-decimal-enhancement-2", Stable, &["vector-packed-decimal-enhancement"]),
959    ("vector-packed-decimal-enhancement-3", Stable, &["vector-packed-decimal-enhancement-2"]),
960    // tidy-alphabetical-end
961];
962
963const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
964    // tidy-alphabetical-start
965    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
966    (
967        "soft-float",
968        InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false },
969        &[],
970    ),
971    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
972    // FIXME: It's unclear what this feature means when `v8plus` is disabled on 32-bit SPARC. See
973    // the discussion around https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355.
974    ("v9", Unstable(sym::sparc_target_feature), &[]),
975    // tidy-alphabetical-end
976];
977
978static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
979    // tidy-alphabetical-start
980    ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
981    ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
982    ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]),
983    ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]),
984    ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
985    ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]),
986    // FPU
987    ("isa-68881", Unstable(sym::m68k_target_feature), &[]),
988    ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]),
989    // tidy-alphabetical-end
990];
991
992static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
993    // tidy-alphabetical-start
994    ("addsubiw", Unstable(sym::avr_target_feature), &[]),
995    ("break", Unstable(sym::avr_target_feature), &[]),
996    ("eijmpcall", Unstable(sym::avr_target_feature), &[]),
997    ("elpm", Unstable(sym::avr_target_feature), &[]),
998    ("elpmx", Unstable(sym::avr_target_feature), &[]),
999    ("ijmpcall", Unstable(sym::avr_target_feature), &[]),
1000    ("jmpcall", Unstable(sym::avr_target_feature), &[]),
1001    ("lowbytefirst", Unstable(sym::avr_target_feature), &[]),
1002    ("lpm", Unstable(sym::avr_target_feature), &[]),
1003    ("lpmx", Unstable(sym::avr_target_feature), &[]),
1004    ("movw", Unstable(sym::avr_target_feature), &[]),
1005    ("mul", Unstable(sym::avr_target_feature), &[]),
1006    ("rmw", Unstable(sym::avr_target_feature), &[]),
1007    ("spm", Unstable(sym::avr_target_feature), &[]),
1008    ("spmx", Unstable(sym::avr_target_feature), &[]),
1009    (
1010        "sram",
1011        // Pinned down by [`Target::abi_required_features`].
1012        InternalOnly { reason: "devices that have no SRAM are unsupported", hard_error: false },
1013        &[],
1014    ),
1015    ("tinyencoding", Unstable(sym::avr_target_feature), &[]),
1016    // tidy-alphabetical-end
1017];
1018
1019const XTENSA_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
1020    ("bool", Unstable(sym::xtensa_target_feature), &[]),
1021    ("fp", Unstable(sym::xtensa_target_feature), &["bool", "coprocessor"]),
1022    ("coprocessor", Unstable(sym::xtensa_target_feature), &[]),
1023    ("highpriinterrupts", Unstable(sym::xtensa_target_feature), &["interrupt"]),
1024    ("interrupt", Unstable(sym::xtensa_target_feature), &["exception"]),
1025    (
1026        "windowed",
1027        // Pinned down by [`Target::abi_required_features`].
1028        InternalOnly {
1029            reason: "windowed changes the Xtensa calling convention",
1030            hard_error: false,
1031        },
1032        &["exception"],
1033    ),
1034    ("loop", Unstable(sym::xtensa_target_feature), &[]),
1035    ("sext", Unstable(sym::xtensa_target_feature), &[]),
1036    ("nsa", Unstable(sym::xtensa_target_feature), &[]),
1037    ("mul32", Unstable(sym::xtensa_target_feature), &[]),
1038    ("mul32high", Unstable(sym::xtensa_target_feature), &["mul32"]),
1039    ("div32", Unstable(sym::xtensa_target_feature), &[]),
1040    ("mac16", Unstable(sym::xtensa_target_feature), &[]),
1041    ("s32c1i", Unstable(sym::xtensa_target_feature), &[]),
1042    ("threadptr", Unstable(sym::xtensa_target_feature), &[]),
1043    ("extendedl32r", Unstable(sym::xtensa_target_feature), &[]),
1044    ("debug", Unstable(sym::xtensa_target_feature), &["exception"]),
1045    ("exception", Unstable(sym::xtensa_target_feature), &[]),
1046    ("rvector", Unstable(sym::xtensa_target_feature), &["exception"]),
1047    ("prid", Unstable(sym::xtensa_target_feature), &[]),
1048    ("regprotect", Unstable(sym::xtensa_target_feature), &[]),
1049    ("miscsr", Unstable(sym::xtensa_target_feature), &[]),
1050];
1051
1052/// When rustdoc is running, provide a list of all known features so that all their respective
1053/// primitives may be documented.
1054///
1055/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
1056pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
1057    std::iter::empty()
1058        .chain(ARM_FEATURES)
1059        .chain(AARCH64_FEATURES)
1060        .chain(X86_FEATURES)
1061        .chain(HEXAGON_FEATURES)
1062        .chain(POWERPC_FEATURES)
1063        .chain(MIPS_FEATURES)
1064        .chain(NVPTX_FEATURES)
1065        .chain(RISCV_FEATURES)
1066        .chain(WASM_FEATURES)
1067        .chain(BPF_FEATURES)
1068        .chain(XTENSA_FEATURES)
1069        .chain(CSKY_FEATURES)
1070        .chain(LOONGARCH_FEATURES)
1071        .chain(IBMZ_FEATURES)
1072        .chain(SPARC_FEATURES)
1073        .chain(M68K_FEATURES)
1074        .chain(AVR_FEATURES)
1075        .cloned()
1076        .map(|(f, s, _)| (f, s))
1077}
1078
1079/// Find which target architectures a feature belongs to.
1080/// Returns arch display names for all targets where this feature name appears.
1081/// Returns empty vec if feature unknown on any target.
1082pub fn feature_to_arch_names(feature: &str) -> Vec<&'static str> {
1083    let mut arches = Vec::new();
1084    macro_rules! check_arch_feats {
1085        ($arch_name:expr, $feats:expr) => {
1086            if $feats.iter().any(|(f, _, _)| *f == feature) {
1087                arches.push($arch_name);
1088            }
1089        };
1090    }
1091    if ARM_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("arm"); };check_arch_feats!("arm", ARM_FEATURES);
1092    if AARCH64_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("aarch64");
};check_arch_feats!("aarch64", AARCH64_FEATURES);
1093    if X86_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("x86"); };check_arch_feats!("x86", X86_FEATURES);
1094    if HEXAGON_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("hexagon");
};check_arch_feats!("hexagon", HEXAGON_FEATURES);
1095    if MIPS_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("mips");
};check_arch_feats!("mips", MIPS_FEATURES);
1096    if NVPTX_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("nvptx64");
};check_arch_feats!("nvptx64", NVPTX_FEATURES);
1097    if POWERPC_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("powerpc");
};check_arch_feats!("powerpc", POWERPC_FEATURES);
1098    if RISCV_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("riscv");
};check_arch_feats!("riscv", RISCV_FEATURES);
1099    if WASM_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("wasm");
};check_arch_feats!("wasm", WASM_FEATURES);
1100    if BPF_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("bpf"); };check_arch_feats!("bpf", BPF_FEATURES);
1101    if CSKY_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("csky");
};check_arch_feats!("csky", CSKY_FEATURES);
1102    if LOONGARCH_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("loongarch");
};check_arch_feats!("loongarch", LOONGARCH_FEATURES);
1103    if IBMZ_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("s390x");
};check_arch_feats!("s390x", IBMZ_FEATURES);
1104    if SPARC_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("sparc");
};check_arch_feats!("sparc", SPARC_FEATURES);
1105    if M68K_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("m68k");
};check_arch_feats!("m68k", M68K_FEATURES);
1106    if AVR_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("avr"); };check_arch_feats!("avr", AVR_FEATURES);
1107    arches.sort();
1108    arches.dedup();
1109    arches
1110}
1111
1112// These arrays represent the least-constraining feature that is required for vector types up to a
1113// certain size to have their "proper" ABI on each architecture. An empty feature name means
1114// that the given length is unconditionally available.
1115// Note that they must be kept sorted by vector size.
1116const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1117    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
1118const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1119    &[(128, "neon")];
1120
1121const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1122    &[(128, "neon"), (128, "mve")];
1123
1124const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1125    &[(1024, "")];
1126const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1127    &[(128, "altivec")];
1128const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1129    &[(128, "simd128")];
1130const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1131    &[(128, "vector")];
1132const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
1133    (32, "zvl32b"),
1134    (64, "zvl64b"),
1135    (128, "zvl128b"),
1136    (256, "zvl256b"),
1137    (512, "zvl512b"),
1138    (1024, "zvl1024b"),
1139    (2048, "zvl2048b"),
1140    (4096, "zvl4096b"),
1141    (8192, "zvl8192b"),
1142    (16384, "zvl16384b"),
1143    (32768, "zvl32768b"),
1144    (65536, "zvl65536b"),
1145];
1146// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
1147const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1148    &[/*(64, "vis")*/];
1149
1150const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
1151    (512, "hvx-length64b"),   // HvxVector in 64-byte mode
1152    (1024, "hvx-length128b"), // HvxVector in 128-byte mode, or HvxVectorPair in 64-byte mode
1153    (2048, "hvx-length128b"), // HvxVectorPair in 128-byte mode
1154];
1155const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1156    &[(128, "msa")];
1157const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1158    &[(128, "vdspv1")];
1159const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1160    &[(128, "lsx"), (256, "lasx")];
1161
1162#[derive(#[automatically_derived]
impl ::core::marker::Copy for FeatureConstraints { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FeatureConstraints { }
#[automatically_derived]
impl ::core::clone::Clone for FeatureConstraints {
    #[inline]
    fn clone(&self) -> FeatureConstraints {
        let _: ::core::clone::AssertParamIsClone<&'static [&'static str]>;
        let _: ::core::clone::AssertParamIsClone<&'static [&'static str]>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for FeatureConstraints {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "FeatureConstraints", "required", &self.required, "incompatible",
            &&self.incompatible)
    }
}Debug)]
1163pub struct FeatureConstraints {
1164    /// Features that must be enabled.
1165    pub required: &'static [&'static str],
1166    /// Features that must be disabled.
1167    pub incompatible: &'static [&'static str],
1168}
1169
1170impl Target {
1171    pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
1172        match &self.arch {
1173            Arch::Arm => ARM_FEATURES,
1174            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES,
1175            Arch::X86 | Arch::X86_64 => X86_FEATURES,
1176            Arch::Hexagon => HEXAGON_FEATURES,
1177            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => MIPS_FEATURES,
1178            Arch::Nvptx64 => NVPTX_FEATURES,
1179            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES,
1180            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES,
1181            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES,
1182            Arch::Bpf => BPF_FEATURES,
1183            Arch::CSky => CSKY_FEATURES,
1184            Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES,
1185            Arch::S390x => IBMZ_FEATURES,
1186            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES,
1187            Arch::M68k => M68K_FEATURES,
1188            Arch::Avr => AVR_FEATURES,
1189            Arch::Xtensa => XTENSA_FEATURES,
1190            Arch::AmdGpu | Arch::Msp430 | Arch::SpirV | Arch::Other(_) => &[],
1191        }
1192    }
1193
1194    /// Computes a map mapping each Rust target feature to the features it implies.
1195    pub fn rust_target_features_map(
1196        &self,
1197    ) -> FxHashMap<&'static str, (Stability, ImpliedFeatures)> {
1198        self.rust_target_features()
1199            .iter()
1200            .map(|&(f, s, i)| (f, (s, i)))
1201            .collect::<FxHashMap<_, _>>()
1202    }
1203
1204    pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
1205        match &self.arch {
1206            Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1207            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1208            Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1209            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1210            Arch::LoongArch32 | Arch::LoongArch64 => {
1211                LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
1212            }
1213            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1214            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1215            Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1216            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1217            Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1218            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
1219                MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
1220            }
1221            Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1222            Arch::Nvptx64 | Arch::Bpf | Arch::M68k | Arch::Avr => &[], // no vector ABI
1223            Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1224            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
1225            // when passing args in vector registers.
1226            Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
1227        }
1228    }
1229
1230    pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
1231        match &self.arch {
1232            Arch::AArch64 | Arch::Arm64EC => Some("sve"),
1233            // Other targets have no scalable vectors or they are unimplemented.
1234            _ => None,
1235        }
1236    }
1237
1238    pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
1239        match &self.arch {
1240            Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES,
1241            _ => &[],
1242        }
1243    }
1244
1245    /// Note: the returned set includes `base_feature`.
1246    #[track_caller]
1247    pub fn implied_target_features<'a>(
1248        &self,
1249        base_feature: &'a str,
1250        target_features_map: &FxHashMap<&'static str, (Stability, ImpliedFeatures)>,
1251    ) -> FxHashSet<&'a str> {
1252        // Implied target features have their own implied target features, so we traverse the
1253        // map until there are no more features to add.
1254        let mut features = FxHashSet::default();
1255        let mut new_features = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [base_feature]))vec![base_feature];
1256        while let Some(new_feature) = new_features.pop() {
1257            if features.insert(new_feature) {
1258                let (_, implied_features) = target_features_map
1259                    .get(&new_feature)
1260                    .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("encountered non-Rust target feature {0}",
            new_feature));
}panic!("encountered non-Rust target feature {new_feature}"));
1261                new_features.extend(implied_features.iter().copied());
1262            }
1263        }
1264        features
1265    }
1266
1267    /// Returns two lists of features:
1268    /// the first list contains target features that must be enabled for ABI reasons,
1269    /// and the second list contains target feature that must be disabled for ABI reasons.
1270    ///
1271    /// These features are checked against the target features reported by LLVM based on
1272    /// `-Ctarget-cpu` and `-Ctarget-features`. Constraint violations result in a warning.
1273    ///
1274    /// We also check features enabled via `#[target_feature(..)]` (and here, constraint violations
1275    /// emit a hard error), including features enabled indirectly via implications -- but if LLVM
1276    /// considers more features to be implied than we do, that could bypass this check!
1277    pub fn abi_required_features(&self) -> FeatureConstraints {
1278        const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
1279        // Some architectures don't have a clean explicit ABI designation; instead, the ABI is
1280        // defined by target features. When that is the case, those target features must be
1281        // "internal-only" in the list above to ensure that there is a consistent answer to the
1282        // questions "which ABI is used".
1283        match &self.arch {
1284            Arch::X86 => {
1285                // We use our own ABI indicator here; LLVM does not have anything native.
1286                // Every case should require or forbid `soft-float`!
1287                match self.rustc_abi {
1288                    None => {
1289                        // Default hardfloat ABI.
1290                        // x87 must be enabled, soft-float must be disabled.
1291                        FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
1292                    }
1293                    Some(RustcAbi::X86Sse2) => {
1294                        // Extended hardfloat ABI. x87 and SSE2 must be enabled, soft-float must be disabled.
1295                        FeatureConstraints {
1296                            required: &["x87", "sse2"],
1297                            incompatible: &["soft-float"],
1298                        }
1299                    }
1300                    Some(RustcAbi::Softfloat) => {
1301                        // Softfloat ABI, requires corresponding target feature. That feature trumps
1302                        // `x87` and all other FPU features so those do not matter.
1303                        // Note that this one requirement is the entire implementation of the ABI!
1304                        // LLVM handles the rest.
1305                        // We mark "sse" as incompatible since LLVM likes to crash when both
1306                        // "soft-float" and "sse" are enabled.
1307                        FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] }
1308                    }
1309                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1310                }
1311            }
1312            Arch::X86_64 => {
1313                // We use our own ABI indicator here; LLVM does not have anything native.
1314                // Every case should require or forbid `soft-float`!
1315                match self.rustc_abi {
1316                    None => {
1317                        // Default hardfloat ABI. On x86-64, this always includes SSE2.
1318                        FeatureConstraints {
1319                            required: &["x87", "sse2"],
1320                            incompatible: &["soft-float"],
1321                        }
1322                    }
1323                    Some(RustcAbi::Softfloat) => {
1324                        // Softfloat ABI, requires corresponding target feature. That feature trumps
1325                        // `x87` and all other FPU features so those do not matter.
1326                        // Note that this one requirement is the entire implementation of the ABI!
1327                        // LLVM handles the rest.
1328                        // We mark "sse" as incompatible since LLVM likes to crash when both
1329                        // "soft-float" and "sse" are enabled.
1330                        FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] }
1331                    }
1332                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1333                }
1334            }
1335            Arch::Arm => {
1336                // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate
1337                // to LLVM which ABI we are going for.
1338                match self.llvm_floatabi.unwrap() {
1339                    FloatAbi::Soft => {
1340                        // Nothing special required, will use soft-float ABI throughout.
1341                        // We can even allow `-soft-float` here; in fact that is useful as it lets
1342                        // people use FPU instructions with a softfloat ABI (corresponds to
1343                        // `-mfloat-abi=softfp` in GCC/clang).
1344                        NOTHING
1345                    }
1346                    FloatAbi::Hard => {
1347                        // Must have `fpregs` and must not have `soft-float`.
1348                        FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
1349                    }
1350                }
1351            }
1352            Arch::AArch64 | Arch::Arm64EC => {
1353                // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
1354                // the use of soft-float, so all we can do here is some crude hacks.
1355                match self.rustc_abi {
1356                    Some(RustcAbi::Softfloat) => {
1357                        // LLVM will use float registers when `fp-armv8` is available, e.g. for
1358                        // calls to built-ins. The only way to ensure a consistent softfloat ABI
1359                        // on aarch64 is to never enable `fp-armv8`, so we enforce that.
1360                        // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is also
1361                        // marked as incompatible.
1362                        FeatureConstraints { required: &[], incompatible: &["neon", "fp-armv8"] }
1363                    }
1364                    None => {
1365                        // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
1366                        // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
1367                        FeatureConstraints { required: &["neon"], incompatible: &[] }
1368                    }
1369                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1370                }
1371            }
1372            Arch::RiscV32 | Arch::RiscV64 => {
1373                // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1374                // about what the intended ABI is.
1375                match &self.llvm_abiname {
1376                    LlvmAbi::Ilp32d | LlvmAbi::Lp64d => {
1377                        // Requires d (which implies f), incompatible with e and zfinx.
1378                        FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] }
1379                    }
1380                    LlvmAbi::Ilp32f | LlvmAbi::Lp64f => {
1381                        // Requires f, incompatible with e and zfinx.
1382                        FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] }
1383                    }
1384                    LlvmAbi::Ilp32 | LlvmAbi::Lp64 => {
1385                        // Requires nothing, incompatible with e.
1386                        FeatureConstraints { required: &[], incompatible: &["e"] }
1387                    }
1388                    LlvmAbi::Ilp32e => {
1389                        // ilp32e is documented to be incompatible with features that need aligned
1390                        // load/stores > 32 bits, like `d`. (One could also just generate more
1391                        // complicated code to align the stack when needed, but the RISCV
1392                        // architecture manual just explicitly rules out this combination so we
1393                        // might as well.)
1394                        // Note that the `e` feature is not required: the ABI treats the extra
1395                        // registers as caller-save, so it is safe to use them only in some parts of
1396                        // a program while the rest doesn't know they even exist.
1397                        FeatureConstraints { required: &[], incompatible: &["d"] }
1398                    }
1399                    LlvmAbi::Lp64e => {
1400                        // As above, `e` is not required.
1401                        NOTHING
1402                    }
1403                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1404                }
1405            }
1406            Arch::LoongArch32 | Arch::LoongArch64 => {
1407                // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1408                // about what the intended ABI is.
1409                match &self.llvm_abiname {
1410                    LlvmAbi::Ilp32d | LlvmAbi::Lp64d => {
1411                        // Requires d (which implies f), incompatible with nothing.
1412                        FeatureConstraints { required: &["d"], incompatible: &[] }
1413                    }
1414                    LlvmAbi::Ilp32f | LlvmAbi::Lp64f => {
1415                        // Requires f, incompatible with nothing.
1416                        FeatureConstraints { required: &["f"], incompatible: &[] }
1417                    }
1418                    LlvmAbi::Ilp32s | LlvmAbi::Lp64s => {
1419                        // The soft-float ABI does not require any features and is also not
1420                        // incompatible with any features. Rust targets explicitly specify the
1421                        // LLVM ABI names, which allows for enabling hard-float support even on
1422                        // soft-float targets, and ensures that the ABI behavior is as expected.
1423                        NOTHING
1424                    }
1425                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1426                }
1427            }
1428            Arch::S390x => {
1429                // Same as x86, We use our own ABI indicator here;
1430                // LLVM does not have anything native and will switch ABI based
1431                // on the soft-float target feature.
1432                // Every case should require or forbid `soft-float`!
1433                // The "vector" target feature may only be used without soft-float
1434                // because the float and vector registers overlap and the
1435                // standard s390x C ABI may pass vectors via these registers.
1436                match self.rustc_abi {
1437                    None => {
1438                        // Default hardfloat ABI.
1439                        FeatureConstraints { required: &[], incompatible: &["soft-float"] }
1440                    }
1441                    Some(RustcAbi::Softfloat) => {
1442                        // Softfloat ABI, requires corresponding target feature.
1443                        // llvm will switch to soft-float ABI just based on this feature.
1444                        FeatureConstraints { required: &["soft-float"], incompatible: &["vector"] }
1445                    }
1446                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1447                }
1448            }
1449            Arch::PowerPC => {
1450                // The main ABI-relevant target features are "hard-float" and "spe". We use our own
1451                // ABI indicator here.
1452                match self.rustc_abi {
1453                    None => {
1454                        // Default hardfloat ABI.
1455                        FeatureConstraints { required: &["hard-float"], incompatible: &["spe"] }
1456                    }
1457                    Some(RustcAbi::PowerPcSpe) => {
1458                        // "efpu2" (which disables some register use in LLVM) *should* be okay
1459                        // because SPE uses soft-float ABI's parameter passing rules and passes
1460                        // floats via GPRs.
1461                        // <https://github.com/rust-lang/rust/pull/157085#discussion_r3349260222>
1462                        FeatureConstraints { required: &["hard-float", "spe"], incompatible: &[] }
1463                    }
1464                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1465                }
1466            }
1467            Arch::PowerPC64 => {
1468                // There's no SPE for PowerPC64, and we currently don't support any soft-float
1469                // targets. (If we ever add one, we need to match on `RustcAbi::Softfloat` similar
1470                // to other targets above.)
1471                FeatureConstraints { required: &["hard-float"], incompatible: &["spe"] }
1472            }
1473            Arch::Sparc => {
1474                // We currently don't have a soft-float target for SPARC.
1475                // We need to pin down v8plus as it is a separate ABI (indicated in object files so
1476                // things cannot be linked across ABI boundaries).
1477                match self.rustc_abi {
1478                    None => FeatureConstraints {
1479                        required: &[],
1480                        incompatible: &["soft-float", "v8plus"],
1481                    },
1482                    Some(RustcAbi::SparcV8Plus) => {
1483                        FeatureConstraints { required: &["v8plus"], incompatible: &["soft-float"] }
1484                    }
1485                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1486                }
1487            }
1488            Arch::Sparc64 => {
1489                // We currently don't have a soft-float target for SPARC64.
1490                // v8plus is for 32bit SPARC only.
1491                FeatureConstraints { required: &[], incompatible: &["soft-float", "v8plus"] }
1492            }
1493            Arch::Avr => {
1494                // We only support one ABI on AVR at the moment.
1495                // SRAM is minimum requirement for C/C++ in both avr-gcc and Clang,
1496                // and backends of them only support assembly for devices have no SRAM.
1497                // See the discussion in https://github.com/rust-lang/rust/pull/146900 for more.
1498                FeatureConstraints { required: &["sram"], incompatible: &[] }
1499            }
1500            Arch::Wasm32 | Arch::Wasm64 => {
1501                // We only support one ABI on wasm at the moment.
1502                // No ABI-relevant target features have been identified thus far.
1503                NOTHING
1504            }
1505            Arch::Xtensa => {
1506                // All Rust-supported Xtensa targets use the windowed register ABI
1507                // (esp32 and later). Non-windowed (historical esp8266 / CALL0) is not
1508                // a supported Rust ABI. Requiring `windowed` here means selecting a
1509                // -Ctarget-cpu that does not provide windowed produces an ABI mismatch
1510                // warning rather than silent UB when mixed with windowed code.
1511                //
1512                // `windowed` implies `exception` in XTENSA_FEATURES, so exception is
1513                // always enabled for this ABI; list it explicitly for complete constraints.
1514                FeatureConstraints { required: &["windowed", "exception"], incompatible: &[] }
1515            }
1516            _ => NOTHING,
1517        }
1518    }
1519}