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 {
            Self::Stable => ::core::fmt::Formatter::write_str(f, "Stable"),
            Self::CfgStableToggleUnstable(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "CfgStableToggleUnstable", &__self_0),
            Self::Unstable(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Unstable", &__self_0),
            Self::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) -> 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) {
                ::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", Stable, &["f"]),
684    ("e", Unstable(sym::riscv_target_feature), &[]), // negative feature! needs special care.
685    ("f", Stable, &["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    // According to the RISC-V spec, the M ISA extension (integer multiplication/division) is supported only when the M bit
696    // of the misa register is 1, while Zmmul means integer multiplication is always supported.
697    //
698    // The Rust/LLVM "m" target feature means something slightly different: with "m" enabled, it is assumed that integer
699    // multiplication and division will always be available (M bit will be 1 in misa), so "m" implies "zmmul".
700    //
701    // See discussion in the PR adding Zmmul: https://github.com/rust-lang/rust/pull/162552
702    ("m", Stable, &["zmmul"]),
703    ("relax", Unstable(sym::riscv_target_feature), &[]),
704    (
705        "rva23u64",
706        Unstable(sym::riscv_target_feature),
707        &[
708            "m",
709            "a",
710            "f",
711            "d",
712            "c",
713            "b",
714            "v",
715            "zicsr",
716            "zicntr",
717            "zihpm",
718            "ziccif",
719            "ziccrse",
720            "ziccamoa",
721            "zicclsm",
722            "zic64b",
723            "za64rs",
724            "zihintpause",
725            "zba",
726            "zbb",
727            "zbs",
728            "zicbom",
729            "zicbop",
730            "zicboz",
731            "zfhmin",
732            "zkt",
733            "zvfhmin",
734            "zvbb",
735            "zvkt",
736            "zihintntl",
737            "zicond",
738            "zimop",
739            "zcmop",
740            "zcb",
741            "zfa",
742            "zawrs",
743            "supm",
744        ],
745    ),
746    ("supm", Unstable(sym::riscv_target_feature), &[]),
747    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
748    ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]),
749    ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]),
750    ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs
751    ("za128rs", Stable, &[]),
752    ("zaamo", Stable, &[]),
753    ("zabha", Stable, &["zaamo"]),
754    ("zacas", Stable, &["zaamo"]),
755    ("zalrsc", Stable, &[]),
756    ("zama16b", Stable, &[]),
757    ("zawrs", Stable, &[]),
758    ("zba", Stable, &[]),
759    ("zbb", Stable, &[]),
760    ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc
761    ("zbkb", Stable, &[]),
762    ("zbkc", Stable, &[]),
763    ("zbkx", Stable, &[]),
764    ("zbs", Stable, &[]),
765    ("zca", Stable, &[]),
766    ("zcb", Stable, &["zca"]),
767    ("zcmop", Stable, &["zca"]),
768    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
769    ("zfa", Unstable(sym::riscv_target_feature), &["f"]),
770    ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin
771    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
772    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
773    ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]),
774    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
775    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
776    ("zic64b", Stable, &[]),
777    ("zicbom", Stable, &[]),
778    ("zicbop", Stable, &[]),
779    ("zicboz", Stable, &[]),
780    ("ziccamoa", Stable, &[]),
781    ("ziccif", Stable, &[]),
782    ("zicclsm", Stable, &[]),
783    ("ziccrse", Stable, &[]),
784    ("zicntr", Stable, &["zicsr"]),
785    ("zicond", Stable, &[]),
786    ("zicsr", Stable, &[]),
787    ("zifencei", Stable, &[]),
788    ("zihintntl", Stable, &[]),
789    ("zihintpause", Stable, &[]),
790    ("zihpm", Stable, &["zicsr"]),
791    ("zimop", Stable, &[]),
792    ("zk", Stable, &["zkn", "zkr", "zkt"]),
793    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
794    ("zknd", Stable, &["zkne_or_zknd"]),
795    ("zkne", Stable, &["zkne_or_zknd"]),
796    ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension
797    ("zknh", Stable, &[]),
798    ("zkr", Stable, &[]),
799    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
800    ("zksed", Stable, &[]),
801    ("zksh", Stable, &[]),
802    ("zkt", Stable, &[]),
803    ("zmmul", Unstable(sym::riscv_target_feature), &[]),
804    ("ztso", Stable, &[]),
805    ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb
806    ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
807    ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
808    ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]),
809    ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]),
810    ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]),
811    ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]),
812    ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
813    ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]),
814    ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin
815    ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
816    ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]),
817    ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]),
818    ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]),
819    ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]),
820    ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]),
821    ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]),
822    ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]),
823    ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha
824    ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]),
825    ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]),
826    ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]),
827    ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]),
828    ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]),
829    ("zvkt", Unstable(sym::riscv_target_feature), &[]),
830    ("zvl32b", Unstable(sym::riscv_target_feature), &[]),
831    ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]),
832    ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]),
833    ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]),
834    ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]),
835    ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]),
836    ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]),
837    ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]),
838    ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]),
839    ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]),
840    ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]),
841    ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]),
842    // tidy-alphabetical-end
843];
844
845static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
846    // tidy-alphabetical-start
847    ("atomics", Unstable(sym::wasm_target_feature), &[]),
848    ("bulk-memory", Stable, &[]),
849    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
850    ("extended-const", Stable, &[]),
851    ("gc", Unstable(sym::wasm_target_feature), &["reference-types"]),
852    ("multivalue", Stable, &[]),
853    ("mutable-globals", Stable, &[]),
854    ("nontrapping-fptoint", Stable, &[]),
855    ("reference-types", Stable, &[]),
856    ("relaxed-simd", Stable, &["simd128"]),
857    ("sign-ext", Stable, &[]),
858    ("simd128", Stable, &[]),
859    ("tail-call", Stable, &[]),
860    ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
861    // tidy-alphabetical-end
862];
863
864const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
865    ("alu32", Unstable(sym::bpf_target_feature), &[]),
866    ("allows-misaligned-mem-access", Unstable(sym::bpf_target_feature), &[]),
867];
868
869static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
870    // tidy-alphabetical-start
871    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
872    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
873    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
874    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
875    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
876    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
877    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
878    ("cache", Unstable(sym::csky_target_feature), &[]),
879    ("doloop", Unstable(sym::csky_target_feature), &[]),
880    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
881    ("dspe60", Unstable(sym::csky_target_feature), &[]),
882    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
883    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
884    ("edsp", Unstable(sym::csky_target_feature), &[]),
885    ("elrw", Unstable(sym::csky_target_feature), &[]),
886    ("float1e2", Unstable(sym::csky_target_feature), &[]),
887    ("float1e3", Unstable(sym::csky_target_feature), &[]),
888    ("float3e4", Unstable(sym::csky_target_feature), &[]),
889    ("float7e60", Unstable(sym::csky_target_feature), &[]),
890    ("floate1", Unstable(sym::csky_target_feature), &[]),
891    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
892    ("high-registers", Unstable(sym::csky_target_feature), &[]),
893    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
894    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
895    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
896    ("nvic", Unstable(sym::csky_target_feature), &[]),
897    ("trust", Unstable(sym::csky_target_feature), &[]),
898    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
899    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
900    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
901    // tidy-alphabetical-end
902    //fpu
903    // tidy-alphabetical-start
904    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
905    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
906    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
907    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
908    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
909    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
910    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
911    ("hard-float", Unstable(sym::csky_target_feature), &[]),
912    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
913    // tidy-alphabetical-end
914];
915
916static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
917    // tidy-alphabetical-start
918    ("32s", Unstable(sym::loongarch_target_feature), &[]),
919    ("d", Stable, &["f"]),
920    ("div32", Stable, &[]),
921    ("f", Stable, &[]),
922    ("frecipe", Stable, &[]),
923    ("lam-bh", Stable, &[]),
924    ("lamcas", Stable, &[]),
925    ("lasx", Stable, &["lsx"]),
926    ("lbt", Stable, &[]),
927    ("ld-seq-sa", Stable, &[]),
928    ("lsx", Stable, &["d"]),
929    ("lvz", Stable, &[]),
930    ("relax", Unstable(sym::loongarch_target_feature), &[]),
931    ("scq", Stable, &[]),
932    ("ual", Unstable(sym::loongarch_target_feature), &[]),
933    // tidy-alphabetical-end
934];
935
936#[rustfmt::skip]
937const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
938    // tidy-alphabetical-start
939    // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker
940    ("backchain", Unstable(sym::s390x_target_feature), &[]),
941    ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
942    ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
943    ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]),
944    ("guarded-storage", Unstable(sym::s390x_target_feature), &[]),
945    ("high-word", Unstable(sym::s390x_target_feature), &[]),
946    // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11.
947    ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]),
948    ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]),
949    ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]),
950    ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]),
951    ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]),
952    ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]),
953    ("miscellaneous-extensions-2", Stable, &[]),
954    ("miscellaneous-extensions-3", Stable, &[]),
955    ("miscellaneous-extensions-4", Stable, &[]),
956    ("nnp-assist", Stable, &["vector"]),
957    // Pinned down by [`Target::abi_required_features`].
958    ("soft-float", InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, &[]),
959    ("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
960    ("vector", Stable, &[]),
961    ("vector-enhancements-1", Stable, &["vector"]),
962    ("vector-enhancements-2", Stable, &["vector-enhancements-1"]),
963    ("vector-enhancements-3", Stable, &["vector-enhancements-2"]),
964    ("vector-packed-decimal", Stable, &["vector"]),
965    ("vector-packed-decimal-enhancement", Stable, &["vector-packed-decimal"]),
966    ("vector-packed-decimal-enhancement-2", Stable, &["vector-packed-decimal-enhancement"]),
967    ("vector-packed-decimal-enhancement-3", Stable, &["vector-packed-decimal-enhancement-2"]),
968    // tidy-alphabetical-end
969];
970
971const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
972    // tidy-alphabetical-start
973    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
974    (
975        "soft-float",
976        InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false },
977        &[],
978    ),
979    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
980    // FIXME: It's unclear what this feature means when `v8plus` is disabled on 32-bit SPARC. See
981    // the discussion around https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355.
982    ("v9", Unstable(sym::sparc_target_feature), &[]),
983    // tidy-alphabetical-end
984];
985
986static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
987    // tidy-alphabetical-start
988    ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
989    ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
990    ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]),
991    ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]),
992    ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
993    ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]),
994    // FPU
995    ("isa-68881", Unstable(sym::m68k_target_feature), &[]),
996    ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]),
997    // tidy-alphabetical-end
998];
999
1000static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
1001    // tidy-alphabetical-start
1002    ("addsubiw", Unstable(sym::avr_target_feature), &[]),
1003    ("break", Unstable(sym::avr_target_feature), &[]),
1004    ("eijmpcall", Unstable(sym::avr_target_feature), &[]),
1005    ("elpm", Unstable(sym::avr_target_feature), &[]),
1006    ("elpmx", Unstable(sym::avr_target_feature), &[]),
1007    ("ijmpcall", Unstable(sym::avr_target_feature), &[]),
1008    ("jmpcall", Unstable(sym::avr_target_feature), &[]),
1009    ("lowbytefirst", Unstable(sym::avr_target_feature), &[]),
1010    ("lpm", Unstable(sym::avr_target_feature), &[]),
1011    ("lpmx", Unstable(sym::avr_target_feature), &[]),
1012    ("movw", Unstable(sym::avr_target_feature), &[]),
1013    ("mul", Unstable(sym::avr_target_feature), &[]),
1014    ("rmw", Unstable(sym::avr_target_feature), &[]),
1015    ("spm", Unstable(sym::avr_target_feature), &[]),
1016    ("spmx", Unstable(sym::avr_target_feature), &[]),
1017    (
1018        "sram",
1019        // Pinned down by [`Target::abi_required_features`].
1020        InternalOnly { reason: "devices that have no SRAM are unsupported", hard_error: false },
1021        &[],
1022    ),
1023    ("tinyencoding", Unstable(sym::avr_target_feature), &[]),
1024    // tidy-alphabetical-end
1025];
1026
1027const XTENSA_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
1028    ("bool", Unstable(sym::xtensa_target_feature), &[]),
1029    ("fp", Unstable(sym::xtensa_target_feature), &["bool", "coprocessor"]),
1030    ("coprocessor", Unstable(sym::xtensa_target_feature), &[]),
1031    ("highpriinterrupts", Unstable(sym::xtensa_target_feature), &["interrupt"]),
1032    ("interrupt", Unstable(sym::xtensa_target_feature), &["exception"]),
1033    (
1034        "windowed",
1035        // Pinned down by [`Target::abi_required_features`].
1036        InternalOnly {
1037            reason: "windowed changes the Xtensa calling convention",
1038            hard_error: false,
1039        },
1040        &["exception"],
1041    ),
1042    ("loop", Unstable(sym::xtensa_target_feature), &[]),
1043    ("sext", Unstable(sym::xtensa_target_feature), &[]),
1044    ("nsa", Unstable(sym::xtensa_target_feature), &[]),
1045    ("mul32", Unstable(sym::xtensa_target_feature), &[]),
1046    ("mul32high", Unstable(sym::xtensa_target_feature), &["mul32"]),
1047    ("div32", Unstable(sym::xtensa_target_feature), &[]),
1048    ("mac16", Unstable(sym::xtensa_target_feature), &[]),
1049    ("s32c1i", Unstable(sym::xtensa_target_feature), &[]),
1050    ("threadptr", Unstable(sym::xtensa_target_feature), &[]),
1051    ("extendedl32r", Unstable(sym::xtensa_target_feature), &[]),
1052    ("debug", Unstable(sym::xtensa_target_feature), &["exception"]),
1053    ("exception", Unstable(sym::xtensa_target_feature), &[]),
1054    ("rvector", Unstable(sym::xtensa_target_feature), &["exception"]),
1055    ("prid", Unstable(sym::xtensa_target_feature), &[]),
1056    ("regprotect", Unstable(sym::xtensa_target_feature), &[]),
1057    ("miscsr", Unstable(sym::xtensa_target_feature), &[]),
1058];
1059
1060/// When rustdoc is running, provide a list of all known features so that all their respective
1061/// primitives may be documented.
1062///
1063/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
1064pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
1065    std::iter::empty()
1066        .chain(ARM_FEATURES)
1067        .chain(AARCH64_FEATURES)
1068        .chain(X86_FEATURES)
1069        .chain(HEXAGON_FEATURES)
1070        .chain(POWERPC_FEATURES)
1071        .chain(MIPS_FEATURES)
1072        .chain(NVPTX_FEATURES)
1073        .chain(RISCV_FEATURES)
1074        .chain(WASM_FEATURES)
1075        .chain(BPF_FEATURES)
1076        .chain(XTENSA_FEATURES)
1077        .chain(CSKY_FEATURES)
1078        .chain(LOONGARCH_FEATURES)
1079        .chain(IBMZ_FEATURES)
1080        .chain(SPARC_FEATURES)
1081        .chain(M68K_FEATURES)
1082        .chain(AVR_FEATURES)
1083        .cloned()
1084        .map(|(f, s, _)| (f, s))
1085}
1086
1087/// Find which target architectures a feature belongs to.
1088/// Returns arch display names for all targets where this feature name appears.
1089/// Returns empty vec if feature unknown on any target.
1090pub fn feature_to_arch_names(feature: &str) -> Vec<&'static str> {
1091    let mut arches = Vec::new();
1092    macro_rules! check_arch_feats {
1093        ($arch_name:expr, $feats:expr) => {
1094            if $feats.iter().any(|(f, _, _)| *f == feature) {
1095                arches.push($arch_name);
1096            }
1097        };
1098    }
1099    if ARM_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("arm"); };check_arch_feats!("arm", ARM_FEATURES);
1100    if AARCH64_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("aarch64");
};check_arch_feats!("aarch64", AARCH64_FEATURES);
1101    if X86_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("x86"); };check_arch_feats!("x86", X86_FEATURES);
1102    if HEXAGON_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("hexagon");
};check_arch_feats!("hexagon", HEXAGON_FEATURES);
1103    if MIPS_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("mips");
};check_arch_feats!("mips", MIPS_FEATURES);
1104    if NVPTX_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("nvptx64");
};check_arch_feats!("nvptx64", NVPTX_FEATURES);
1105    if POWERPC_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("powerpc");
};check_arch_feats!("powerpc", POWERPC_FEATURES);
1106    if RISCV_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("riscv");
};check_arch_feats!("riscv", RISCV_FEATURES);
1107    if WASM_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("wasm");
};check_arch_feats!("wasm", WASM_FEATURES);
1108    if BPF_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("bpf"); };check_arch_feats!("bpf", BPF_FEATURES);
1109    if CSKY_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("csky");
};check_arch_feats!("csky", CSKY_FEATURES);
1110    if LOONGARCH_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("loongarch");
};check_arch_feats!("loongarch", LOONGARCH_FEATURES);
1111    if IBMZ_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("s390x");
};check_arch_feats!("s390x", IBMZ_FEATURES);
1112    if SPARC_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("sparc");
};check_arch_feats!("sparc", SPARC_FEATURES);
1113    if M68K_FEATURES.iter().any(|(f, _, _)| *f == feature) {
    arches.push("m68k");
};check_arch_feats!("m68k", M68K_FEATURES);
1114    if AVR_FEATURES.iter().any(|(f, _, _)| *f == feature) { arches.push("avr"); };check_arch_feats!("avr", AVR_FEATURES);
1115    arches.sort();
1116    arches.dedup();
1117    arches
1118}
1119
1120// These arrays represent the least-constraining feature that is required for vector types up to a
1121// certain size to have their "proper" ABI on each architecture. An empty feature name means
1122// that the given length is unconditionally available.
1123// Note that they must be kept sorted by vector size.
1124const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1125    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
1126const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1127    &[(128, "neon")];
1128
1129const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1130    &[(128, "neon"), (128, "mve")];
1131
1132const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1133    &[(1024, "")];
1134const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1135    &[(128, "altivec")];
1136const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1137    &[(128, "simd128")];
1138const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1139    &[(128, "vector")];
1140const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
1141    (32, "zvl32b"),
1142    (64, "zvl64b"),
1143    (128, "zvl128b"),
1144    (256, "zvl256b"),
1145    (512, "zvl512b"),
1146    (1024, "zvl1024b"),
1147    (2048, "zvl2048b"),
1148    (4096, "zvl4096b"),
1149    (8192, "zvl8192b"),
1150    (16384, "zvl16384b"),
1151    (32768, "zvl32768b"),
1152    (65536, "zvl65536b"),
1153];
1154// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
1155const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1156    &[/*(64, "vis")*/];
1157
1158const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
1159    (512, "hvx-length64b"),   // HvxVector in 64-byte mode
1160    (1024, "hvx-length128b"), // HvxVector in 128-byte mode, or HvxVectorPair in 64-byte mode
1161    (2048, "hvx-length128b"), // HvxVectorPair in 128-byte mode
1162];
1163const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1164    &[(128, "msa")];
1165const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1166    &[(128, "vdspv1")];
1167const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
1168    &[(128, "lsx"), (256, "lasx")];
1169
1170#[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) -> 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]
    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)]
1171pub struct FeatureConstraints {
1172    /// Features that must be enabled.
1173    pub required: &'static [&'static str],
1174    /// Features that must be disabled.
1175    pub incompatible: &'static [&'static str],
1176}
1177
1178impl Target {
1179    pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
1180        match &self.arch {
1181            Arch::Arm => ARM_FEATURES,
1182            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES,
1183            Arch::X86 | Arch::X86_64 => X86_FEATURES,
1184            Arch::Hexagon => HEXAGON_FEATURES,
1185            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => MIPS_FEATURES,
1186            Arch::Nvptx64 => NVPTX_FEATURES,
1187            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES,
1188            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES,
1189            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES,
1190            Arch::Bpf => BPF_FEATURES,
1191            Arch::CSky => CSKY_FEATURES,
1192            Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES,
1193            Arch::S390x => IBMZ_FEATURES,
1194            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES,
1195            Arch::M68k => M68K_FEATURES,
1196            Arch::Avr => AVR_FEATURES,
1197            Arch::Xtensa => XTENSA_FEATURES,
1198            Arch::AmdGpu | Arch::Msp430 | Arch::SpirV | Arch::Other(_) => &[],
1199        }
1200    }
1201
1202    /// Computes a map mapping each Rust target feature to the features it implies.
1203    pub fn rust_target_features_map(
1204        &self,
1205    ) -> FxHashMap<&'static str, (Stability, ImpliedFeatures)> {
1206        self.rust_target_features()
1207            .iter()
1208            .map(|&(f, s, i)| (f, (s, i)))
1209            .collect::<FxHashMap<_, _>>()
1210    }
1211
1212    pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
1213        match &self.arch {
1214            Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1215            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1216            Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1217            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1218            Arch::LoongArch32 | Arch::LoongArch64 => {
1219                LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
1220            }
1221            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1222            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1223            Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1224            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1225            Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1226            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
1227                MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
1228            }
1229            Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1230            Arch::Nvptx64 | Arch::Bpf | Arch::M68k | Arch::Avr => &[], // no vector ABI
1231            Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
1232            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
1233            // when passing args in vector registers.
1234            Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[],
1235        }
1236    }
1237
1238    pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
1239        match &self.arch {
1240            Arch::AArch64 | Arch::Arm64EC => Some("sve"),
1241            // Other targets have no scalable vectors or they are unimplemented.
1242            _ => None,
1243        }
1244    }
1245
1246    pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
1247        match &self.arch {
1248            Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES,
1249            _ => &[],
1250        }
1251    }
1252
1253    /// Note: the returned set includes `base_feature`.
1254    #[track_caller]
1255    pub fn implied_target_features<'a>(
1256        &self,
1257        base_feature: &'a str,
1258        target_features_map: &FxHashMap<&'static str, (Stability, ImpliedFeatures)>,
1259    ) -> FxHashSet<&'a str> {
1260        // Implied target features have their own implied target features, so we traverse the
1261        // map until there are no more features to add.
1262        let mut features = FxHashSet::default();
1263        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];
1264        while let Some(new_feature) = new_features.pop() {
1265            if features.insert(new_feature) {
1266                let (_, implied_features) = target_features_map
1267                    .get(&new_feature)
1268                    .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}"));
1269                new_features.extend(implied_features.iter().copied());
1270            }
1271        }
1272        features
1273    }
1274
1275    /// Returns two lists of features:
1276    /// the first list contains target features that must be enabled for ABI reasons,
1277    /// and the second list contains target feature that must be disabled for ABI reasons.
1278    ///
1279    /// These features are checked against the target features reported by LLVM based on
1280    /// `-Ctarget-cpu` and `-Ctarget-features`. Constraint violations result in a warning.
1281    ///
1282    /// We also check features enabled via `#[target_feature(..)]` (and here, constraint violations
1283    /// emit a hard error), including features enabled indirectly via implications -- but if LLVM
1284    /// considers more features to be implied than we do, that could bypass this check!
1285    pub fn abi_required_features(&self) -> FeatureConstraints {
1286        const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
1287        // Some architectures don't have a clean explicit ABI designation; instead, the ABI is
1288        // defined by target features. When that is the case, those target features must be
1289        // "internal-only" in the list above to ensure that there is a consistent answer to the
1290        // questions "which ABI is used".
1291        match &self.arch {
1292            Arch::X86 => {
1293                // We use our own ABI indicator here; LLVM does not have anything native.
1294                // Every case should require or forbid `soft-float`!
1295                match self.rustc_abi {
1296                    None => {
1297                        // Default hardfloat ABI.
1298                        // x87 must be enabled, soft-float must be disabled.
1299                        FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
1300                    }
1301                    Some(RustcAbi::X86Sse2) => {
1302                        // Extended hardfloat ABI. x87 and SSE2 must be enabled, soft-float must be disabled.
1303                        FeatureConstraints {
1304                            required: &["x87", "sse2"],
1305                            incompatible: &["soft-float"],
1306                        }
1307                    }
1308                    Some(RustcAbi::Softfloat) => {
1309                        // Softfloat ABI, requires corresponding target feature. That feature trumps
1310                        // `x87` and all other FPU features so those do not matter.
1311                        // Note that this one requirement is the entire implementation of the ABI!
1312                        // LLVM handles the rest.
1313                        // We mark "sse" as incompatible since LLVM likes to crash when both
1314                        // "soft-float" and "sse" are enabled.
1315                        FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] }
1316                    }
1317                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1318                }
1319            }
1320            Arch::X86_64 => {
1321                // We use our own ABI indicator here; LLVM does not have anything native.
1322                // Every case should require or forbid `soft-float`!
1323                match self.rustc_abi {
1324                    None => {
1325                        // Default hardfloat ABI. On x86-64, this always includes SSE2.
1326                        FeatureConstraints {
1327                            required: &["x87", "sse2"],
1328                            incompatible: &["soft-float"],
1329                        }
1330                    }
1331                    Some(RustcAbi::Softfloat) => {
1332                        // Softfloat ABI, requires corresponding target feature. That feature trumps
1333                        // `x87` and all other FPU features so those do not matter.
1334                        // Note that this one requirement is the entire implementation of the ABI!
1335                        // LLVM handles the rest.
1336                        // We mark "sse" as incompatible since LLVM likes to crash when both
1337                        // "soft-float" and "sse" are enabled.
1338                        FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] }
1339                    }
1340                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1341                }
1342            }
1343            Arch::Arm => {
1344                // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate
1345                // to LLVM which ABI we are going for.
1346                match self.llvm_floatabi.unwrap() {
1347                    FloatAbi::Soft => {
1348                        // Nothing special required, will use soft-float ABI throughout.
1349                        // We can even allow `-soft-float` here; in fact that is useful as it lets
1350                        // people use FPU instructions with a softfloat ABI (corresponds to
1351                        // `-mfloat-abi=softfp` in GCC/clang).
1352                        NOTHING
1353                    }
1354                    FloatAbi::Hard => {
1355                        // Must have `fpregs` and must not have `soft-float`.
1356                        FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
1357                    }
1358                }
1359            }
1360            Arch::AArch64 | Arch::Arm64EC => {
1361                // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
1362                // the use of soft-float, so all we can do here is some crude hacks.
1363                match self.rustc_abi {
1364                    Some(RustcAbi::Softfloat) => {
1365                        // LLVM will use float registers when `fp-armv8` is available, e.g. for
1366                        // calls to built-ins. The only way to ensure a consistent softfloat ABI
1367                        // on aarch64 is to never enable `fp-armv8`, so we enforce that.
1368                        // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is also
1369                        // marked as incompatible.
1370                        FeatureConstraints { required: &[], incompatible: &["neon", "fp-armv8"] }
1371                    }
1372                    None => {
1373                        // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
1374                        // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
1375                        FeatureConstraints { required: &["neon"], incompatible: &[] }
1376                    }
1377                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1378                }
1379            }
1380            Arch::RiscV32 | Arch::RiscV64 => {
1381                // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1382                // about what the intended ABI is.
1383                match &self.llvm_abiname {
1384                    LlvmAbi::Ilp32d | LlvmAbi::Lp64d => {
1385                        // Requires d (which implies f), incompatible with e and zfinx.
1386                        FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] }
1387                    }
1388                    LlvmAbi::Ilp32f | LlvmAbi::Lp64f => {
1389                        // Requires f, incompatible with e and zfinx.
1390                        FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] }
1391                    }
1392                    LlvmAbi::Ilp32 | LlvmAbi::Lp64 => {
1393                        // Requires nothing, incompatible with e.
1394                        FeatureConstraints { required: &[], incompatible: &["e"] }
1395                    }
1396                    LlvmAbi::Ilp32e => {
1397                        // ilp32e is documented to be incompatible with features that need aligned
1398                        // load/stores > 32 bits, like `d`. (One could also just generate more
1399                        // complicated code to align the stack when needed, but the RISCV
1400                        // architecture manual just explicitly rules out this combination so we
1401                        // might as well.)
1402                        // Note that the `e` feature is not required: the ABI treats the extra
1403                        // registers as caller-save, so it is safe to use them only in some parts of
1404                        // a program while the rest doesn't know they even exist.
1405                        FeatureConstraints { required: &[], incompatible: &["d"] }
1406                    }
1407                    LlvmAbi::Lp64e => {
1408                        // As above, `e` is not required.
1409                        NOTHING
1410                    }
1411                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1412                }
1413            }
1414            Arch::LoongArch32 | Arch::LoongArch64 => {
1415                // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
1416                // about what the intended ABI is.
1417                match &self.llvm_abiname {
1418                    LlvmAbi::Ilp32d | LlvmAbi::Lp64d => {
1419                        // Requires d (which implies f), incompatible with nothing.
1420                        FeatureConstraints { required: &["d"], incompatible: &[] }
1421                    }
1422                    LlvmAbi::Ilp32f | LlvmAbi::Lp64f => {
1423                        // Requires f, incompatible with nothing.
1424                        FeatureConstraints { required: &["f"], incompatible: &[] }
1425                    }
1426                    LlvmAbi::Ilp32s | LlvmAbi::Lp64s => {
1427                        // The soft-float ABI does not require any features and is also not
1428                        // incompatible with any features. Rust targets explicitly specify the
1429                        // LLVM ABI names, which allows for enabling hard-float support even on
1430                        // soft-float targets, and ensures that the ABI behavior is as expected.
1431                        NOTHING
1432                    }
1433                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1434                }
1435            }
1436            Arch::S390x => {
1437                // Same as x86, We use our own ABI indicator here;
1438                // LLVM does not have anything native and will switch ABI based
1439                // on the soft-float target feature.
1440                // Every case should require or forbid `soft-float`!
1441                // The "vector" target feature may only be used without soft-float
1442                // because the float and vector registers overlap and the
1443                // standard s390x C ABI may pass vectors via these registers.
1444                match self.rustc_abi {
1445                    None => {
1446                        // Default hardfloat ABI.
1447                        FeatureConstraints { required: &[], incompatible: &["soft-float"] }
1448                    }
1449                    Some(RustcAbi::Softfloat) => {
1450                        // Softfloat ABI, requires corresponding target feature.
1451                        // llvm will switch to soft-float ABI just based on this feature.
1452                        FeatureConstraints { required: &["soft-float"], incompatible: &["vector"] }
1453                    }
1454                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1455                }
1456            }
1457            Arch::PowerPC => {
1458                // The main ABI-relevant target features are "hard-float" and "spe". We use our own
1459                // ABI indicator here.
1460                match self.rustc_abi {
1461                    None => {
1462                        // Default hardfloat ABI.
1463                        FeatureConstraints { required: &["hard-float"], incompatible: &["spe"] }
1464                    }
1465                    Some(RustcAbi::PowerPcSpe) => {
1466                        // "efpu2" (which disables some register use in LLVM) *should* be okay
1467                        // because SPE uses soft-float ABI's parameter passing rules and passes
1468                        // floats via GPRs.
1469                        // <https://github.com/rust-lang/rust/pull/157085#discussion_r3349260222>
1470                        FeatureConstraints { required: &["hard-float", "spe"], incompatible: &[] }
1471                    }
1472                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1473                }
1474            }
1475            Arch::PowerPC64 => {
1476                // There's no SPE for PowerPC64, and we currently don't support any soft-float
1477                // targets. (If we ever add one, we need to match on `RustcAbi::Softfloat` similar
1478                // to other targets above.)
1479                FeatureConstraints { required: &["hard-float"], incompatible: &["spe"] }
1480            }
1481            Arch::Sparc => {
1482                // We currently don't have a soft-float target for SPARC.
1483                // We need to pin down v8plus as it is a separate ABI (indicated in object files so
1484                // things cannot be linked across ABI boundaries).
1485                match self.rustc_abi {
1486                    None => FeatureConstraints {
1487                        required: &[],
1488                        incompatible: &["soft-float", "v8plus"],
1489                    },
1490                    Some(RustcAbi::SparcV8Plus) => {
1491                        FeatureConstraints { required: &["v8plus"], incompatible: &["soft-float"] }
1492                    }
1493                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1494                }
1495            }
1496            Arch::Sparc64 => {
1497                // We currently don't have a soft-float target for SPARC64.
1498                // v8plus is for 32bit SPARC only.
1499                FeatureConstraints { required: &[], incompatible: &["soft-float", "v8plus"] }
1500            }
1501            Arch::Avr => {
1502                // We only support one ABI on AVR at the moment.
1503                // SRAM is minimum requirement for C/C++ in both avr-gcc and Clang,
1504                // and backends of them only support assembly for devices have no SRAM.
1505                // See the discussion in https://github.com/rust-lang/rust/pull/146900 for more.
1506                FeatureConstraints { required: &["sram"], incompatible: &[] }
1507            }
1508            Arch::Wasm32 | Arch::Wasm64 => {
1509                // We only support one ABI on wasm at the moment.
1510                // No ABI-relevant target features have been identified thus far.
1511                NOTHING
1512            }
1513            Arch::Xtensa => {
1514                // All Rust-supported Xtensa targets use the windowed register ABI
1515                // (esp32 and later). Non-windowed (historical esp8266 / CALL0) is not
1516                // a supported Rust ABI. Requiring `windowed` here means selecting a
1517                // -Ctarget-cpu that does not provide windowed produces an ABI mismatch
1518                // warning rather than silent UB when mixed with windowed code.
1519                //
1520                // `windowed` implies `exception` in XTENSA_FEATURES, so exception is
1521                // always enabled for this ABI; list it explicitly for complete constraints.
1522                FeatureConstraints { required: &["windowed", "exception"], incompatible: &[] }
1523            }
1524            _ => NOTHING,
1525        }
1526    }
1527}