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