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-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
384    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
385    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
386    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
387    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
388    ("avx", Stable, &["sse4.2"]),
389    ("avx2", Stable, &["avx"]),
390    ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
391    ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
392    ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
393    ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
394    ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
395    ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
396    ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
397    ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
398    ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
399    ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
400    ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
401    ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
402    ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
403    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
404    ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
405    ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
406    ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
407    ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
408    ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
409    ("bmi1", Stable, &[]),
410    ("bmi2", Stable, &[]),
411    ("cmpxchg16b", Stable, &[]),
412    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
413    ("f16c", Stable, &["avx"]),
414    ("fma", Stable, &["avx"]),
415    ("fxsr", Stable, &[]),
416    ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
417    ("kl", Unstable(sym::keylocker_x86), &["sse2"]),
418    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
419    ("lzcnt", Stable, &[]),
420    ("movbe", Stable, &[]),
421    ("pclmulqdq", Stable, &["sse2"]),
422    ("popcnt", Stable, &[]),
423    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
424    ("rdrand", Stable, &[]),
425    ("rdseed", Stable, &[]),
426    ("rtm", Unstable(sym::rtm_target_feature), &[]),
427    ("sha", Stable, &["sse2"]),
428    ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
429    ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
430    ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
431    // This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to
432    // stabilize. It must be in this list for the ABI check to be able to use it.
433    ("soft-float", Stability::Unstable(sym::x87_target_feature), &[]),
434    ("sse", Stable, &[]),
435    ("sse2", Stable, &["sse"]),
436    ("sse3", Stable, &["sse2"]),
437    ("sse4.1", Stable, &["ssse3"]),
438    ("sse4.2", Stable, &["sse4.1"]),
439    ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
440    ("ssse3", Stable, &["sse3"]),
441    ("tbm", Unstable(sym::tbm_target_feature), &[]),
442    ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
443    ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
444    ("widekl", Unstable(sym::keylocker_x86), &["kl"]),
445    ("x87", Unstable(sym::x87_target_feature), &[]),
446    ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
447    ("xsave", Stable, &[]),
448    ("xsavec", Stable, &["xsave"]),
449    ("xsaveopt", Stable, &["xsave"]),
450    ("xsaves", Stable, &["xsave"]),
451    // tidy-alphabetical-end
452];
453
454const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
455    // tidy-alphabetical-start
456    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
457    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
458    // tidy-alphabetical-end
459];
460
461static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
462    // tidy-alphabetical-start
463    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
464    ("msync", Unstable(sym::powerpc_target_feature), &[]),
465    ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
466    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
467    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
468    ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
469    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
470    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
471    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
472    ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]),
473    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
474    // tidy-alphabetical-end
475];
476
477const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
478    // tidy-alphabetical-start
479    ("fp64", Unstable(sym::mips_target_feature), &[]),
480    ("msa", Unstable(sym::mips_target_feature), &[]),
481    ("virt", Unstable(sym::mips_target_feature), &[]),
482    // tidy-alphabetical-end
483];
484
485static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
486    // tidy-alphabetical-start
487    ("a", Stable, &["zaamo", "zalrsc"]),
488    ("c", Stable, &[]),
489    ("d", Unstable(sym::riscv_target_feature), &["f"]),
490    ("e", Unstable(sym::riscv_target_feature), &[]),
491    ("f", Unstable(sym::riscv_target_feature), &[]),
492    (
493        "forced-atomics",
494        Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
495        &[],
496    ),
497    ("m", Stable, &[]),
498    ("relax", Unstable(sym::riscv_target_feature), &[]),
499    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
500    ("v", Unstable(sym::riscv_target_feature), &[]),
501    ("za128rs", Unstable(sym::riscv_target_feature), &[]),
502    ("za64rs", Unstable(sym::riscv_target_feature), &[]),
503    ("zaamo", Unstable(sym::riscv_target_feature), &[]),
504    ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
505    ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]),
506    ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
507    ("zama16b", Unstable(sym::riscv_target_feature), &[]),
508    ("zawrs", Unstable(sym::riscv_target_feature), &[]),
509    ("zba", Stable, &[]),
510    ("zbb", Stable, &[]),
511    ("zbc", Stable, &[]),
512    ("zbkb", Stable, &[]),
513    ("zbkc", Stable, &[]),
514    ("zbkx", Stable, &[]),
515    ("zbs", Stable, &[]),
516    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
517    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
518    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
519    ("zfinx", Unstable(sym::riscv_target_feature), &[]),
520    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
521    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
522    ("zk", Stable, &["zkn", "zkr", "zkt"]),
523    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
524    ("zknd", Stable, &[]),
525    ("zkne", Stable, &[]),
526    ("zknh", Stable, &[]),
527    ("zkr", Stable, &[]),
528    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
529    ("zksed", Stable, &[]),
530    ("zksh", Stable, &[]),
531    ("zkt", Stable, &[]),
532    // tidy-alphabetical-end
533];
534
535static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
536    // tidy-alphabetical-start
537    ("atomics", Unstable(sym::wasm_target_feature), &[]),
538    ("bulk-memory", Stable, &[]),
539    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
540    ("extended-const", Stable, &[]),
541    ("multivalue", Stable, &[]),
542    ("mutable-globals", Stable, &[]),
543    ("nontrapping-fptoint", Stable, &[]),
544    ("reference-types", Stable, &[]),
545    ("relaxed-simd", Stable, &["simd128"]),
546    ("sign-ext", Stable, &[]),
547    ("simd128", Stable, &[]),
548    ("tail-call", Stable, &[]),
549    ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
550    // tidy-alphabetical-end
551];
552
553const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
554    &[("alu32", Unstable(sym::bpf_target_feature), &[])];
555
556static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
557    // tidy-alphabetical-start
558    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
559    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
560    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
561    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
562    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
563    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
564    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
565    ("cache", Unstable(sym::csky_target_feature), &[]),
566    ("doloop", Unstable(sym::csky_target_feature), &[]),
567    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
568    ("dspe60", Unstable(sym::csky_target_feature), &[]),
569    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
570    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
571    ("edsp", Unstable(sym::csky_target_feature), &[]),
572    ("elrw", Unstable(sym::csky_target_feature), &[]),
573    ("float1e2", Unstable(sym::csky_target_feature), &[]),
574    ("float1e3", Unstable(sym::csky_target_feature), &[]),
575    ("float3e4", Unstable(sym::csky_target_feature), &[]),
576    ("float7e60", Unstable(sym::csky_target_feature), &[]),
577    ("floate1", Unstable(sym::csky_target_feature), &[]),
578    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
579    ("high-registers", Unstable(sym::csky_target_feature), &[]),
580    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
581    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
582    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
583    ("nvic", Unstable(sym::csky_target_feature), &[]),
584    ("trust", Unstable(sym::csky_target_feature), &[]),
585    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
586    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
587    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
588    // tidy-alphabetical-end
589    //fpu
590    // tidy-alphabetical-start
591    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
592    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
593    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
594    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
595    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
596    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
597    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
598    ("hard-float", Unstable(sym::csky_target_feature), &[]),
599    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
600    // tidy-alphabetical-end
601];
602
603static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
604    // tidy-alphabetical-start
605    ("d", Unstable(sym::loongarch_target_feature), &["f"]),
606    ("div32", Unstable(sym::loongarch_target_feature), &[]),
607    ("f", Unstable(sym::loongarch_target_feature), &[]),
608    ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
609    ("lam-bh", Unstable(sym::loongarch_target_feature), &[]),
610    ("lamcas", Unstable(sym::loongarch_target_feature), &[]),
611    ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
612    ("lbt", Unstable(sym::loongarch_target_feature), &[]),
613    ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]),
614    ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
615    ("lvz", Unstable(sym::loongarch_target_feature), &[]),
616    ("relax", Unstable(sym::loongarch_target_feature), &[]),
617    ("scq", Unstable(sym::loongarch_target_feature), &[]),
618    ("ual", Unstable(sym::loongarch_target_feature), &[]),
619    // tidy-alphabetical-end
620];
621
622const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
623    // tidy-alphabetical-start
624    ("backchain", Unstable(sym::s390x_target_feature), &[]),
625    ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
626    ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]),
627    ("guarded-storage", Unstable(sym::s390x_target_feature), &[]),
628    ("high-word", Unstable(sym::s390x_target_feature), &[]),
629    ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]),
630    ("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
631    ("vector", Unstable(sym::s390x_target_feature), &[]),
632    ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]),
633    ("vector-enhancements-2", Unstable(sym::s390x_target_feature), &["vector-enhancements-1"]),
634    ("vector-packed-decimal", Unstable(sym::s390x_target_feature), &["vector"]),
635    (
636        "vector-packed-decimal-enhancement",
637        Unstable(sym::s390x_target_feature),
638        &["vector-packed-decimal"],
639    ),
640    (
641        "vector-packed-decimal-enhancement-2",
642        Unstable(sym::s390x_target_feature),
643        &["vector-packed-decimal-enhancement"],
644    ),
645    // tidy-alphabetical-end
646];
647
648const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
649    // tidy-alphabetical-start
650    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
651    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
652    ("v9", Unstable(sym::sparc_target_feature), &[]),
653    // tidy-alphabetical-end
654];
655
656static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
657    // tidy-alphabetical-start
658    ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
659    ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
660    ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]),
661    ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]),
662    ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
663    ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]),
664    // FPU
665    ("isa-68881", Unstable(sym::m68k_target_feature), &[]),
666    ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]),
667    // tidy-alphabetical-end
668];
669
670/// When rustdoc is running, provide a list of all known features so that all their respective
671/// primitives may be documented.
672///
673/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
674pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
675    std::iter::empty()
676        .chain(ARM_FEATURES.iter())
677        .chain(AARCH64_FEATURES.iter())
678        .chain(X86_FEATURES.iter())
679        .chain(HEXAGON_FEATURES.iter())
680        .chain(POWERPC_FEATURES.iter())
681        .chain(MIPS_FEATURES.iter())
682        .chain(RISCV_FEATURES.iter())
683        .chain(WASM_FEATURES.iter())
684        .chain(BPF_FEATURES.iter())
685        .chain(CSKY_FEATURES)
686        .chain(LOONGARCH_FEATURES)
687        .chain(IBMZ_FEATURES)
688        .chain(SPARC_FEATURES)
689        .chain(M68K_FEATURES)
690        .cloned()
691        .map(|(f, s, _)| (f, s))
692}
693
694// These arrays represent the least-constraining feature that is required for vector types up to a
695// certain size to have their "proper" ABI on each architecture.
696// Note that they must be kept sorted by vector size.
697const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
698    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
699const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
700
701// We might want to add "helium" too.
702const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
703
704const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
705const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
706const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
707const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
708    &[/*(64, "zvl64b"), */ (128, "v")];
709// Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
710const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
711
712const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
713    &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
714const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
715const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
716const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
717    &[(128, "lsx"), (256, "lasx")];
718
719#[derive(Copy, Clone, Debug)]
720pub struct FeatureConstraints {
721    /// Features that must be enabled.
722    pub required: &'static [&'static str],
723    /// Features that must be disabled.
724    pub incompatible: &'static [&'static str],
725}
726
727impl Target {
728    pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
729        match &*self.arch {
730            "arm" => ARM_FEATURES,
731            "aarch64" | "arm64ec" => AARCH64_FEATURES,
732            "x86" | "x86_64" => X86_FEATURES,
733            "hexagon" => HEXAGON_FEATURES,
734            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES,
735            "powerpc" | "powerpc64" => POWERPC_FEATURES,
736            "riscv32" | "riscv64" => RISCV_FEATURES,
737            "wasm32" | "wasm64" => WASM_FEATURES,
738            "bpf" => BPF_FEATURES,
739            "csky" => CSKY_FEATURES,
740            "loongarch64" => LOONGARCH_FEATURES,
741            "s390x" => IBMZ_FEATURES,
742            "sparc" | "sparc64" => SPARC_FEATURES,
743            "m68k" => M68K_FEATURES,
744            _ => &[],
745        }
746    }
747
748    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
749        match &*self.arch {
750            "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
751            "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
752            "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
753            "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
754            "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
755            "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
756            "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
757            "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
758            "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
759            "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
760            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
761            "bpf" | "m68k" => &[], // no vector ABI
762            "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
763            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
764            // when passing args in vector registers.
765            _ => &[],
766        }
767    }
768
769    pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
770        match &*self.arch {
771            "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES,
772            _ => &[],
773        }
774    }
775
776    // Note: the returned set includes `base_feature`.
777    pub fn implied_target_features<'a>(&self, base_feature: &'a str) -> FxHashSet<&'a str> {
778        let implied_features =
779            self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>();
780
781        // Implied target features have their own implied target features, so we traverse the
782        // map until there are no more features to add.
783        let mut features = FxHashSet::default();
784        let mut new_features = vec![base_feature];
785        while let Some(new_feature) = new_features.pop() {
786            if features.insert(new_feature) {
787                if let Some(implied_features) = implied_features.get(&new_feature) {
788                    new_features.extend(implied_features.iter().copied())
789                }
790            }
791        }
792        features
793    }
794
795    /// Returns two lists of features:
796    /// the first list contains target features that must be enabled for ABI reasons,
797    /// and the second list contains target feature that must be disabled for ABI reasons.
798    ///
799    /// These features are automatically appended to whatever the target spec sets as default
800    /// features for the target.
801    ///
802    /// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
803    /// against this. We also check any implied features, based on the information above. If LLVM
804    /// implicitly enables more implied features than we do, that could bypass this check!
805    pub fn abi_required_features(&self) -> FeatureConstraints {
806        const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
807        // Some architectures don't have a clean explicit ABI designation; instead, the ABI is
808        // defined by target features. When that is the case, those target features must be
809        // "forbidden" in the list above to ensure that there is a consistent answer to the
810        // questions "which ABI is used".
811        match &*self.arch {
812            "x86" => {
813                // We use our own ABI indicator here; LLVM does not have anything native.
814                // Every case should require or forbid `soft-float`!
815                match self.rustc_abi {
816                    None => {
817                        // Default hardfloat ABI.
818                        // x87 must be enabled, soft-float must be disabled.
819                        FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] }
820                    }
821                    Some(RustcAbi::X86Sse2) => {
822                        // Extended hardfloat ABI. x87 and SSE2 must be enabled, soft-float must be disabled.
823                        FeatureConstraints {
824                            required: &["x87", "sse2"],
825                            incompatible: &["soft-float"],
826                        }
827                    }
828                    Some(RustcAbi::X86Softfloat) => {
829                        // Softfloat ABI, requires corresponding target feature. That feature trumps
830                        // `x87` and all other FPU features so those do not matter.
831                        // Note that this one requirement is the entire implementation of the ABI!
832                        // LLVM handles the rest.
833                        FeatureConstraints { required: &["soft-float"], incompatible: &[] }
834                    }
835                }
836            }
837            "x86_64" => {
838                // We use our own ABI indicator here; LLVM does not have anything native.
839                // Every case should require or forbid `soft-float`!
840                match self.rustc_abi {
841                    None => {
842                        // Default hardfloat ABI. On x86-64, this always includes SSE2.
843                        FeatureConstraints {
844                            required: &["x87", "sse2"],
845                            incompatible: &["soft-float"],
846                        }
847                    }
848                    Some(RustcAbi::X86Softfloat) => {
849                        // Softfloat ABI, requires corresponding target feature. That feature trumps
850                        // `x87` and all other FPU features so those do not matter.
851                        // Note that this one requirement is the entire implementation of the ABI!
852                        // LLVM handles the rest.
853                        FeatureConstraints { required: &["soft-float"], incompatible: &[] }
854                    }
855                    Some(r) => panic!("invalid Rust ABI for x86_64: {r:?}"),
856                }
857            }
858            "arm" => {
859                // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate
860                // to LLVM which ABI we are going for.
861                match self.llvm_floatabi.unwrap() {
862                    FloatAbi::Soft => {
863                        // Nothing special required, will use soft-float ABI throughout.
864                        // We can even allow `-soft-float` here; in fact that is useful as it lets
865                        // people use FPU instructions with a softfloat ABI (corresponds to
866                        // `-mfloat-abi=softfp` in GCC/clang).
867                        NOTHING
868                    }
869                    FloatAbi::Hard => {
870                        // Must have `fpregs` and must not have `soft-float`.
871                        FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
872                    }
873                }
874            }
875            "aarch64" | "arm64ec" => {
876                // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
877                // the use of soft-float, so all we can do here is some crude hacks.
878                match &*self.abi {
879                    "softfloat" => {
880                        // This is not fully correct, LLVM actually doesn't let us enforce the softfloat
881                        // ABI properly... see <https://github.com/rust-lang/rust/issues/134375>.
882                        // FIXME: should we forbid "neon" here? But that would be a breaking change.
883                        NOTHING
884                    }
885                    _ => {
886                        // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
887                        // These are Rust feature names and we use "neon" to control both of them.
888                        FeatureConstraints { required: &["neon"], incompatible: &[] }
889                    }
890                }
891            }
892            "riscv32" | "riscv64" => {
893                // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname`
894                // about what the intended ABI is.
895                match &*self.llvm_abiname {
896                    "ilp32d" | "lp64d" => {
897                        // Requires d (which implies f), incompatible with e.
898                        FeatureConstraints { required: &["d"], incompatible: &["e"] }
899                    }
900                    "ilp32f" | "lp64f" => {
901                        // Requires f, incompatible with e.
902                        FeatureConstraints { required: &["f"], incompatible: &["e"] }
903                    }
904                    "ilp32" | "lp64" => {
905                        // Requires nothing, incompatible with e.
906                        FeatureConstraints { required: &[], incompatible: &["e"] }
907                    }
908                    "ilp32e" => {
909                        // ilp32e is documented to be incompatible with features that need aligned
910                        // load/stores > 32 bits, like `d`. (One could also just generate more
911                        // complicated code to align the stack when needed, but the RISCV
912                        // architecture manual just explicitly rules out this combination so we
913                        // might as well.)
914                        // Note that the `e` feature is not required: the ABI treats the extra
915                        // registers as caller-save, so it is safe to use them only in some parts of
916                        // a program while the rest doesn't know they even exist.
917                        FeatureConstraints { required: &[], incompatible: &["d"] }
918                    }
919                    "lp64e" => {
920                        // As above, `e` is not required.
921                        NOTHING
922                    }
923                    _ => unreachable!(),
924                }
925            }
926            "loongarch64" => {
927                // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
928                // about what the intended ABI is.
929                match &*self.llvm_abiname {
930                    "ilp32d" | "lp64d" => {
931                        // Requires d (which implies f), incompatible with nothing.
932                        FeatureConstraints { required: &["d"], incompatible: &[] }
933                    }
934                    "ilp32f" | "lp64f" => {
935                        // Requires f, incompatible with nothing.
936                        FeatureConstraints { required: &["f"], incompatible: &[] }
937                    }
938                    "ilp32s" | "lp64s" => {
939                        // The soft-float ABI does not require any features and is also not
940                        // incompatible with any features. Rust targets explicitly specify the
941                        // LLVM ABI names, which allows for enabling hard-float support even on
942                        // soft-float targets, and ensures that the ABI behavior is as expected.
943                        NOTHING
944                    }
945                    _ => unreachable!(),
946                }
947            }
948            _ => NOTHING,
949        }
950    }
951}