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