rustc_target/
target_features.rs

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