| //! Declares Rust's target feature names for each target. | |
| //! Note that these are similar to but not always identical to LLVM's feature names, | |
| //! and Rust adds some features that do not correspond to LLVM features at all. | |
| use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
| use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
| use rustc_span::{Symbol, sym}; | |
| use crate::spec::{Abi, Arch, FloatAbi, RustcAbi, Target}; | |
| /// Features that control behaviour of rustc, rather than the codegen. | |
| /// These exist globally and are not in the target-specific lists below. | |
| pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; | |
| /// Stability information for target features. | |
| #[derive(Debug, Copy, Clone)] | |
| pub enum Stability { | |
| /// This target feature is stable, it can be used in `#[target_feature]` and | |
| /// `#[cfg(target_feature)]`. | |
| Stable, | |
| /// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on | |
| /// nightly and using it in `#[target_feature]` requires enabling the given nightly feature. | |
| Unstable( | |
| /// This must be a *language* feature, or else rustc will ICE when reporting a missing | |
| /// feature gate! | |
| Symbol, | |
| ), | |
| /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be | |
| /// set in the target spec. It is never set in `cfg(target_feature)`. Used in | |
| /// particular for features are actually ABI configuration flags (not all targets are as nice as | |
| /// RISC-V and have an explicit way to set the ABI separate from target features). | |
| Forbidden { reason: &'static str }, | |
| } | |
| use Stability::*; | |
| impl<CTX> HashStable<CTX> for Stability { | |
| #[inline] | |
| fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { | |
| std::mem::discriminant(self).hash_stable(hcx, hasher); | |
| match self { | |
| Stability::Stable => {} | |
| Stability::Unstable(nightly_feature) => { | |
| nightly_feature.hash_stable(hcx, hasher); | |
| } | |
| Stability::Forbidden { reason } => { | |
| reason.hash_stable(hcx, hasher); | |
| } | |
| } | |
| } | |
| } | |
| impl Stability { | |
| /// Returns whether the feature can be used in `cfg(target_feature)` ever. | |
| /// (It might still be nightly-only even if this returns `true`, so make sure to also check | |
| /// `requires_nightly`.) | |
| pub fn in_cfg(&self) -> bool { | |
| matches!(self, Stability::Stable | Stability::Unstable { .. }) | |
| } | |
| /// Returns the nightly feature that is required to toggle this target feature via | |
| /// `#[target_feature]`/`-Ctarget-feature` or to test it via `cfg(target_feature)`. | |
| /// (For `cfg` we only care whether the feature is nightly or not, we don't require | |
| /// the feature gate to actually be enabled when using a nightly compiler.) | |
| /// | |
| /// Before calling this, ensure the feature is even permitted for this use: | |
| /// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()` | |
| /// - for `cfg(target_feature)`, check `in_cfg()` | |
| pub fn requires_nightly(&self) -> Option<Symbol> { | |
| match *self { | |
| Stability::Unstable(nightly_feature) => Some(nightly_feature), | |
| Stability::Stable { .. } => None, | |
| Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), | |
| } | |
| } | |
| /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. | |
| /// (It might still be nightly-only even if this returns `true`, so make sure to also check | |
| /// `requires_nightly`.) | |
| pub fn toggle_allowed(&self) -> Result<(), &'static str> { | |
| match self { | |
| Stability::Unstable(_) | Stability::Stable { .. } => Ok(()), | |
| Stability::Forbidden { reason } => Err(reason), | |
| } | |
| } | |
| } | |
| // Here we list target features that rustc "understands": they can be used in `#[target_feature]` | |
| // and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with | |
| // `-Ctarget-feature`. | |
| // | |
| // Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature` | |
| // on stable. Using a feature not on the list of Rust target features only emits a warning. | |
| // Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating. | |
| // `cfg(target_feature)` for unstable features just works on nightly without any feature gate. | |
| // `#[target_feature]` requires a feature gate. | |
| // | |
| // When adding features to the below lists | |
| // check whether they're named already elsewhere in rust | |
| // e.g. in stdarch and whether the given name matches LLVM's | |
| // if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. | |
| // Additionally, if the feature is not available in older version of LLVM supported by the current | |
| // rust, the same function must be updated to filter out these features to avoid triggering | |
| // warnings. | |
| // | |
| // Also note that all target features listed here must be purely additive: for target_feature 1.1 to | |
| // be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a | |
| // per-function level, since we would then allow safe calls from functions with `+soft-float` to | |
| // functions without that feature! | |
| // | |
| // It is important for soundness to consider the interaction of targets features and the function | |
| // call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as | |
| // arguments, so letting people toggle that feature would be unsound. To this end, the | |
| // `abi_required_features` function computes which target features must and must not be enabled for | |
| // any given target, and individual features can also be marked as `Forbidden`. | |
| // See https://github.com/rust-lang/rust/issues/116344 for some more context. | |
| // | |
| // The one exception to features that change the ABI is features that enable larger vector | |
| // registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store | |
| // information about which target feature is ABI-required for which vector size; this is used to | |
| // ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For | |
| // the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.) | |
| // Also see https://github.com/rust-lang/rust/issues/116558. | |
| // | |
| // Stabilizing a target feature requires t-lang approval. | |
| // If feature A "implies" feature B, then: | |
| // - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B | |
| // - when B gets disabled (via `-Ctarget-feature`), we also disable A | |
| // | |
| // Both of these are also applied transitively. | |
| type ImpliedFeatures = &'static [&'static str]; | |
| static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("aclass", Unstable(sym::arm_target_feature), &[]), | |
| ("aes", Unstable(sym::arm_target_feature), &["neon"]), | |
| ( | |
| "atomics-32", | |
| Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" }, | |
| &[], | |
| ), | |
| ("crc", Unstable(sym::arm_target_feature), &[]), | |
| ("d32", Unstable(sym::arm_target_feature), &[]), | |
| ("dotprod", Unstable(sym::arm_target_feature), &["neon"]), | |
| ("dsp", Unstable(sym::arm_target_feature), &[]), | |
| ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]), | |
| ("fp16", Unstable(sym::arm_target_feature), &["neon"]), | |
| ("fpregs", Unstable(sym::arm_target_feature), &[]), | |
| ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), | |
| ("mclass", Unstable(sym::arm_target_feature), &[]), | |
| ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), | |
| ("rclass", Unstable(sym::arm_target_feature), &[]), | |
| ("sha2", Unstable(sym::arm_target_feature), &["neon"]), | |
| // This can be *disabled* on non-`hf` targets to enable the use | |
| // of hardfloats while keeping the softfloat ABI. | |
| // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of | |
| // matching the odd negative feature LLVM uses? | |
| ("soft-float", Unstable(sym::arm_target_feature), &[]), | |
| // This is needed for inline assembly, but shouldn't be stabilized as-is | |
| // since it should be enabled per-function using #[instruction_set], not | |
| // #[target_feature]. | |
| ("thumb-mode", Unstable(sym::arm_target_feature), &[]), | |
| ("thumb2", Unstable(sym::arm_target_feature), &[]), | |
| ("trustzone", Unstable(sym::arm_target_feature), &[]), | |
| ("v5te", Unstable(sym::arm_target_feature), &[]), | |
| ("v6", Unstable(sym::arm_target_feature), &["v5te"]), | |
| ("v6k", Unstable(sym::arm_target_feature), &["v6"]), | |
| ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]), | |
| ("v7", Unstable(sym::arm_target_feature), &["v6t2"]), | |
| ("v8", Unstable(sym::arm_target_feature), &["v7"]), | |
| ("vfp2", Unstable(sym::arm_target_feature), &[]), | |
| ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]), | |
| ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]), | |
| ("virtualization", Unstable(sym::arm_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| // FEAT_AES & FEAT_PMULL | |
| ("aes", Stable, &["neon"]), | |
| // FEAT_BF16 | |
| ("bf16", Stable, &[]), | |
| // FEAT_BTI | |
| ("bti", Stable, &[]), | |
| // FEAT_CRC | |
| ("crc", Stable, &[]), | |
| // FEAT_CSSC | |
| ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_DIT | |
| ("dit", Stable, &[]), | |
| // FEAT_DotProd | |
| ("dotprod", Stable, &["neon"]), | |
| // FEAT_DPB | |
| ("dpb", Stable, &[]), | |
| // FEAT_DPB2 | |
| ("dpb2", Stable, &["dpb"]), | |
| // FEAT_ECV | |
| ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_F32MM | |
| ("f32mm", Stable, &["sve"]), | |
| // FEAT_F64MM | |
| ("f64mm", Stable, &["sve"]), | |
| // FEAT_FAMINMAX | |
| ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_FCMA | |
| ("fcma", Stable, &["neon"]), | |
| // FEAT_FHM | |
| ("fhm", Stable, &["fp16"]), | |
| // FEAT_FLAGM | |
| ("flagm", Stable, &[]), | |
| // FEAT_FLAGM2 | |
| ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`. | |
| ("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]), | |
| // FEAT_FP8 | |
| ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), | |
| // FEAT_FP8DOT2 | |
| ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), | |
| // FEAT_FP8DOT4 | |
| ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), | |
| // FEAT_FP8FMA | |
| ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), | |
| // FEAT_FP16 | |
| // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 | |
| ("fp16", Stable, &["neon"]), | |
| // FEAT_FRINTTS | |
| ("frintts", Stable, &[]), | |
| // FEAT_HBC | |
| ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_I8MM | |
| ("i8mm", Stable, &[]), | |
| // FEAT_JSCVT | |
| // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 | |
| ("jsconv", Stable, &["neon"]), | |
| // FEAT_LOR | |
| ("lor", Stable, &[]), | |
| // FEAT_LSE | |
| ("lse", Stable, &[]), | |
| // FEAT_LSE2 | |
| ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_LSE128 | |
| ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), | |
| // FEAT_LUT | |
| ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_MOPS | |
| ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_MTE & FEAT_MTE2 | |
| ("mte", Stable, &[]), | |
| // FEAT_AdvSimd & FEAT_FP | |
| ("neon", Stable, &[]), | |
| // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be | |
| // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally | |
| // using slower non-LSE operations. Unstable since it doesn't need to user-togglable. | |
| ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_PAUTH (address authentication) | |
| ("paca", Stable, &[]), | |
| // FEAT_PAUTH (generic authentication) | |
| ("pacg", Stable, &[]), | |
| // FEAT_PAN | |
| ("pan", Stable, &[]), | |
| // FEAT_PAuth_LR | |
| ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_PMUv3 | |
| ("pmuv3", Stable, &[]), | |
| // FEAT_RNG | |
| ("rand", Stable, &[]), | |
| // FEAT_RAS & FEAT_RASv1p1 | |
| ("ras", Stable, &[]), | |
| // FEAT_LRCPC | |
| ("rcpc", Stable, &[]), | |
| // FEAT_LRCPC2 | |
| ("rcpc2", Stable, &["rcpc"]), | |
| // FEAT_LRCPC3 | |
| ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), | |
| // FEAT_RDM | |
| ("rdm", Stable, &["neon"]), | |
| ("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]), | |
| // FEAT_SB | |
| ("sb", Stable, &[]), | |
| // FEAT_SHA1 & FEAT_SHA256 | |
| ("sha2", Stable, &["neon"]), | |
| // FEAT_SHA512 & FEAT_SHA3 | |
| ("sha3", Stable, &["sha2"]), | |
| // FEAT_SM3 & FEAT_SM4 | |
| ("sm4", Stable, &["neon"]), | |
| // FEAT_SME | |
| ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), | |
| // FEAT_SME_B16B16 | |
| ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), | |
| // FEAT_SME_F8F16 | |
| ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), | |
| // FEAT_SME_F8F32 | |
| ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), | |
| // FEAT_SME_F16F16 | |
| ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), | |
| // FEAT_SME_F64F64 | |
| ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), | |
| // FEAT_SME_FA64 | |
| ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), | |
| // FEAT_SME_I16I64 | |
| ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), | |
| // FEAT_SME_LUTv2 | |
| ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // FEAT_SME2 | |
| ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), | |
| // FEAT_SME2p1 | |
| ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), | |
| // FEAT_SPE | |
| ("spe", Stable, &[]), | |
| // FEAT_SSBS & FEAT_SSBS2 | |
| ("ssbs", Stable, &[]), | |
| // FEAT_SSVE_FP8FDOT2 | |
| ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), | |
| // FEAT_SSVE_FP8FDOT4 | |
| ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), | |
| // FEAT_SSVE_FP8FMA | |
| ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), | |
| // FEAT_SVE | |
| // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608 | |
| // | |
| // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always | |
| // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2 | |
| // | |
| // "For backwards compatibility, Neon and VFP are required in the latest architectures." | |
| ("sve", Stable, &["neon"]), | |
| // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) | |
| ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), | |
| // FEAT_SVE2 | |
| ("sve2", Stable, &["sve"]), | |
| // FEAT_SVE_AES & FEAT_SVE_PMULL128 | |
| ("sve2-aes", Stable, &["sve2", "aes"]), | |
| // FEAT_SVE2_BitPerm | |
| ("sve2-bitperm", Stable, &["sve2"]), | |
| // FEAT_SVE2_SHA3 | |
| ("sve2-sha3", Stable, &["sve2", "sha3"]), | |
| // FEAT_SVE2_SM4 | |
| ("sve2-sm4", Stable, &["sve2", "sm4"]), | |
| // FEAT_SVE2p1 | |
| ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]), | |
| // FEAT_TME | |
| ("tme", Stable, &[]), | |
| ( | |
| "v8.1a", | |
| Unstable(sym::aarch64_ver_target_feature), | |
| &["crc", "lse", "rdm", "pan", "lor", "vh"], | |
| ), | |
| ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]), | |
| ( | |
| "v8.3a", | |
| Unstable(sym::aarch64_ver_target_feature), | |
| &["v8.2a", "rcpc", "paca", "pacg", "jsconv"], | |
| ), | |
| ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]), | |
| ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]), | |
| ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]), | |
| ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]), | |
| ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]), | |
| ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]), | |
| ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]), | |
| ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]), | |
| ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]), | |
| ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]), | |
| ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]), | |
| ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "sve2"]), | |
| // FEAT_VHE | |
| ("vh", Stable, &[]), | |
| // FEAT_WFxT | |
| ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const AARCH64_TIED_FEATURES: &[&[&str]] = &[ | |
| &["paca", "pacg"], // Together these represent `pauth` in LLVM | |
| ]; | |
| static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("adx", Stable, &[]), | |
| ("aes", Stable, &["sse2"]), | |
| ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), | |
| ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), | |
| ("apxf", Unstable(sym::apx_target_feature), &[]), | |
| ("avx", Stable, &["sse4.2"]), | |
| ("avx2", Stable, &["avx"]), | |
| ( | |
| "avx10.1", | |
| Unstable(sym::avx10_target_feature), | |
| &[ | |
| "avx512bf16", | |
| "avx512bitalg", | |
| "avx512bw", | |
| "avx512cd", | |
| "avx512dq", | |
| "avx512f", | |
| "avx512fp16", | |
| "avx512ifma", | |
| "avx512vbmi", | |
| "avx512vbmi2", | |
| "avx512vl", | |
| "avx512vnni", | |
| "avx512vpopcntdq", | |
| ], | |
| ), | |
| ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), | |
| ("avx512bf16", Stable, &["avx512bw"]), | |
| ("avx512bitalg", Stable, &["avx512bw"]), | |
| ("avx512bw", Stable, &["avx512f"]), | |
| ("avx512cd", Stable, &["avx512f"]), | |
| ("avx512dq", Stable, &["avx512f"]), | |
| ("avx512f", Stable, &["avx2", "fma", "f16c"]), | |
| ("avx512fp16", Stable, &["avx512bw"]), | |
| ("avx512ifma", Stable, &["avx512f"]), | |
| ("avx512vbmi", Stable, &["avx512bw"]), | |
| ("avx512vbmi2", Stable, &["avx512bw"]), | |
| ("avx512vl", Stable, &["avx512f"]), | |
| ("avx512vnni", Stable, &["avx512f"]), | |
| ("avx512vp2intersect", Stable, &["avx512f"]), | |
| ("avx512vpopcntdq", Stable, &["avx512f"]), | |
| ("avxifma", Stable, &["avx2"]), | |
| ("avxneconvert", Stable, &["avx2"]), | |
| ("avxvnni", Stable, &["avx2"]), | |
| ("avxvnniint8", Stable, &["avx2"]), | |
| ("avxvnniint16", Stable, &["avx2"]), | |
| ("bmi1", Stable, &[]), | |
| ("bmi2", Stable, &[]), | |
| ("cmpxchg16b", Stable, &[]), | |
| ("ermsb", Unstable(sym::ermsb_target_feature), &[]), | |
| ("f16c", Stable, &["avx"]), | |
| ("fma", Stable, &["avx"]), | |
| ("fxsr", Stable, &[]), | |
| ("gfni", Stable, &["sse2"]), | |
| ("kl", Stable, &["sse2"]), | |
| ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), | |
| ("lzcnt", Stable, &[]), | |
| ("movbe", Stable, &[]), | |
| ("movrs", Unstable(sym::movrs_target_feature), &[]), | |
| ("pclmulqdq", Stable, &["sse2"]), | |
| ("popcnt", Stable, &[]), | |
| ("prfchw", Unstable(sym::prfchw_target_feature), &[]), | |
| ("rdrand", Stable, &[]), | |
| ("rdseed", Stable, &[]), | |
| ( | |
| "retpoline-external-thunk", | |
| Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" }, | |
| &[], | |
| ), | |
| ( | |
| "retpoline-indirect-branches", | |
| Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, | |
| &[], | |
| ), | |
| ( | |
| "retpoline-indirect-calls", | |
| Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, | |
| &[], | |
| ), | |
| ("rtm", Unstable(sym::rtm_target_feature), &[]), | |
| ("sha", Stable, &["sse2"]), | |
| ("sha512", Stable, &["avx2"]), | |
| ("sm3", Stable, &["avx"]), | |
| ("sm4", Stable, &["avx2"]), | |
| ("soft-float", Stability::Forbidden { reason: "use a soft-float target instead" }, &[]), | |
| ("sse", Stable, &[]), | |
| ("sse2", Stable, &["sse"]), | |
| ("sse3", Stable, &["sse2"]), | |
| ("sse4.1", Stable, &["ssse3"]), | |
| ("sse4.2", Stable, &["sse4.1"]), | |
| ("sse4a", Stable, &["sse3"]), | |
| ("ssse3", Stable, &["sse3"]), | |
| ("tbm", Stable, &[]), | |
| ("vaes", Stable, &["avx2", "aes"]), | |
| ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), | |
| ("widekl", Stable, &["kl"]), | |
| ("x87", Unstable(sym::x87_target_feature), &[]), | |
| ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]), | |
| ("xsave", Stable, &[]), | |
| ("xsavec", Stable, &["xsave"]), | |
| ("xsaveopt", Stable, &["xsave"]), | |
| ("xsaves", Stable, &["xsave"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("hvx", Unstable(sym::hexagon_target_feature), &[]), | |
| ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]), | |
| ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]), | |
| ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]), | |
| ("hvx-qfloat", Unstable(sym::hexagon_target_feature), &["hvx"]), | |
| ("hvxv60", Unstable(sym::hexagon_target_feature), &["hvx"]), | |
| ("hvxv62", Unstable(sym::hexagon_target_feature), &["hvxv60"]), | |
| ("hvxv65", Unstable(sym::hexagon_target_feature), &["hvxv62"]), | |
| ("hvxv66", Unstable(sym::hexagon_target_feature), &["hvxv65", "zreg"]), | |
| ("hvxv67", Unstable(sym::hexagon_target_feature), &["hvxv66"]), | |
| ("hvxv68", Unstable(sym::hexagon_target_feature), &["hvxv67"]), | |
| ("hvxv69", Unstable(sym::hexagon_target_feature), &["hvxv68"]), | |
| ("hvxv71", Unstable(sym::hexagon_target_feature), &["hvxv69"]), | |
| ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]), | |
| ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]), | |
| ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]), | |
| ("zreg", Unstable(sym::hexagon_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("altivec", Unstable(sym::powerpc_target_feature), &[]), | |
| ("msync", Unstable(sym::powerpc_target_feature), &[]), | |
| ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), | |
| ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), | |
| ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), | |
| ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]), | |
| ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), | |
| ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]), | |
| ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), | |
| ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), | |
| ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("fp64", Unstable(sym::mips_target_feature), &[]), | |
| ("msa", Unstable(sym::mips_target_feature), &[]), | |
| ("virt", Unstable(sym::mips_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("sm_20", Unstable(sym::nvptx_target_feature), &[]), | |
| ("sm_21", Unstable(sym::nvptx_target_feature), &["sm_20"]), | |
| ("sm_30", Unstable(sym::nvptx_target_feature), &["sm_21"]), | |
| ("sm_32", Unstable(sym::nvptx_target_feature), &["sm_30"]), | |
| ("sm_35", Unstable(sym::nvptx_target_feature), &["sm_32"]), | |
| ("sm_37", Unstable(sym::nvptx_target_feature), &["sm_35"]), | |
| ("sm_50", Unstable(sym::nvptx_target_feature), &["sm_37"]), | |
| ("sm_52", Unstable(sym::nvptx_target_feature), &["sm_50"]), | |
| ("sm_53", Unstable(sym::nvptx_target_feature), &["sm_52"]), | |
| ("sm_60", Unstable(sym::nvptx_target_feature), &["sm_53"]), | |
| ("sm_61", Unstable(sym::nvptx_target_feature), &["sm_60"]), | |
| ("sm_62", Unstable(sym::nvptx_target_feature), &["sm_61"]), | |
| ("sm_70", Unstable(sym::nvptx_target_feature), &["sm_62"]), | |
| ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), | |
| ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), | |
| ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), | |
| ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]), | |
| ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]), | |
| ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]), | |
| ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]), | |
| ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]), | |
| // tidy-alphabetical-end | |
| // tidy-alphabetical-start | |
| ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]), | |
| ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]), | |
| ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]), | |
| ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]), | |
| ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]), | |
| ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), | |
| // tidy-alphabetical-end | |
| // tidy-alphabetical-start | |
| ("ptx32", Unstable(sym::nvptx_target_feature), &[]), | |
| ("ptx40", Unstable(sym::nvptx_target_feature), &["ptx32"]), | |
| ("ptx41", Unstable(sym::nvptx_target_feature), &["ptx40"]), | |
| ("ptx42", Unstable(sym::nvptx_target_feature), &["ptx41"]), | |
| ("ptx43", Unstable(sym::nvptx_target_feature), &["ptx42"]), | |
| ("ptx50", Unstable(sym::nvptx_target_feature), &["ptx43"]), | |
| ("ptx60", Unstable(sym::nvptx_target_feature), &["ptx50"]), | |
| ("ptx61", Unstable(sym::nvptx_target_feature), &["ptx60"]), | |
| ("ptx62", Unstable(sym::nvptx_target_feature), &["ptx61"]), | |
| ("ptx63", Unstable(sym::nvptx_target_feature), &["ptx62"]), | |
| ("ptx64", Unstable(sym::nvptx_target_feature), &["ptx63"]), | |
| ("ptx65", Unstable(sym::nvptx_target_feature), &["ptx64"]), | |
| ("ptx70", Unstable(sym::nvptx_target_feature), &["ptx65"]), | |
| ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), | |
| ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), | |
| ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), | |
| ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]), | |
| ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]), | |
| ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]), | |
| ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]), | |
| ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]), | |
| ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]), | |
| ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]), | |
| ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]), | |
| ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]), | |
| ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]), | |
| ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]), | |
| ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]), | |
| ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("a", Stable, &["zaamo", "zalrsc"]), | |
| ("b", Stable, &["zba", "zbb", "zbs"]), | |
| ("c", Stable, &["zca"]), | |
| ("d", Unstable(sym::riscv_target_feature), &["f"]), | |
| ("e", Unstable(sym::riscv_target_feature), &[]), | |
| ("f", Unstable(sym::riscv_target_feature), &["zicsr"]), | |
| ( | |
| "forced-atomics", | |
| Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" }, | |
| &[], | |
| ), | |
| ("m", Stable, &[]), | |
| ("relax", Unstable(sym::riscv_target_feature), &[]), | |
| ( | |
| "rva23u64", | |
| Unstable(sym::riscv_target_feature), | |
| &[ | |
| "m", | |
| "a", | |
| "f", | |
| "d", | |
| "c", | |
| "b", | |
| "v", | |
| "zicsr", | |
| "zicntr", | |
| "zihpm", | |
| "ziccif", | |
| "ziccrse", | |
| "ziccamoa", | |
| "zicclsm", | |
| "zic64b", | |
| "za64rs", | |
| "zihintpause", | |
| "zba", | |
| "zbb", | |
| "zbs", | |
| "zicbom", | |
| "zicbop", | |
| "zicboz", | |
| "zfhmin", | |
| "zkt", | |
| "zvfhmin", | |
| "zvbb", | |
| "zvkt", | |
| "zihintntl", | |
| "zicond", | |
| "zimop", | |
| "zcmop", | |
| "zcb", | |
| "zfa", | |
| "zawrs", | |
| "supm", | |
| ], | |
| ), | |
| ("supm", Unstable(sym::riscv_target_feature), &[]), | |
| ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), | |
| ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), | |
| ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), | |
| ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs | |
| ("za128rs", Stable, &[]), | |
| ("zaamo", Stable, &[]), | |
| ("zabha", Stable, &["zaamo"]), | |
| ("zacas", Stable, &["zaamo"]), | |
| ("zalrsc", Stable, &[]), | |
| ("zama16b", Stable, &[]), | |
| ("zawrs", Stable, &[]), | |
| ("zba", Stable, &[]), | |
| ("zbb", Stable, &[]), | |
| ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc | |
| ("zbkb", Stable, &[]), | |
| ("zbkc", Stable, &[]), | |
| ("zbkx", Stable, &[]), | |
| ("zbs", Stable, &[]), | |
| ("zca", Stable, &[]), | |
| ("zcb", Stable, &["zca"]), | |
| ("zcmop", Stable, &["zca"]), | |
| ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), | |
| ("zfa", Unstable(sym::riscv_target_feature), &["f"]), | |
| ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin | |
| ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), | |
| ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), | |
| ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), | |
| ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), | |
| ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), | |
| ("zic64b", Stable, &[]), | |
| ("zicbom", Stable, &[]), | |
| ("zicbop", Stable, &[]), | |
| ("zicboz", Stable, &[]), | |
| ("ziccamoa", Stable, &[]), | |
| ("ziccif", Stable, &[]), | |
| ("zicclsm", Stable, &[]), | |
| ("ziccrse", Stable, &[]), | |
| ("zicntr", Stable, &["zicsr"]), | |
| ("zicond", Stable, &[]), | |
| ("zicsr", Stable, &[]), | |
| ("zifencei", Stable, &[]), | |
| ("zihintntl", Stable, &[]), | |
| ("zihintpause", Stable, &[]), | |
| ("zihpm", Stable, &["zicsr"]), | |
| ("zimop", Stable, &[]), | |
| ("zk", Stable, &["zkn", "zkr", "zkt"]), | |
| ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), | |
| ("zknd", Stable, &["zkne_or_zknd"]), | |
| ("zkne", Stable, &["zkne_or_zknd"]), | |
| ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension | |
| ("zknh", Stable, &[]), | |
| ("zkr", Stable, &[]), | |
| ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), | |
| ("zksed", Stable, &[]), | |
| ("zksh", Stable, &[]), | |
| ("zkt", Stable, &[]), | |
| ("ztso", Stable, &[]), | |
| ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb | |
| ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), | |
| ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), | |
| ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]), | |
| ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), | |
| ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), | |
| ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), | |
| ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), | |
| ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), | |
| ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin | |
| ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), | |
| ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]), | |
| ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]), | |
| ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]), | |
| ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha | |
| ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]), | |
| ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]), | |
| ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]), | |
| ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]), | |
| ("zvkt", Unstable(sym::riscv_target_feature), &[]), | |
| ("zvl32b", Unstable(sym::riscv_target_feature), &[]), | |
| ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), | |
| ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]), | |
| ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]), | |
| ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]), | |
| ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), | |
| ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), | |
| ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), | |
| ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]), | |
| ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), | |
| ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), | |
| ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("atomics", Unstable(sym::wasm_target_feature), &[]), | |
| ("bulk-memory", Stable, &[]), | |
| ("exception-handling", Unstable(sym::wasm_target_feature), &[]), | |
| ("extended-const", Stable, &[]), | |
| ("gc", Unstable(sym::wasm_target_feature), &["reference-types"]), | |
| ("multivalue", Stable, &[]), | |
| ("mutable-globals", Stable, &[]), | |
| ("nontrapping-fptoint", Stable, &[]), | |
| ("reference-types", Stable, &[]), | |
| ("relaxed-simd", Stable, &["simd128"]), | |
| ("sign-ext", Stable, &[]), | |
| ("simd128", Stable, &[]), | |
| ("tail-call", Stable, &[]), | |
| ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = | |
| &[("alu32", Unstable(sym::bpf_target_feature), &[])]; | |
| static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("2e3", Unstable(sym::csky_target_feature), &["e2"]), | |
| ("3e3r1", Unstable(sym::csky_target_feature), &[]), | |
| ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]), | |
| ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]), | |
| ("3e7", Unstable(sym::csky_target_feature), &["2e3"]), | |
| ("7e10", Unstable(sym::csky_target_feature), &["3e7"]), | |
| ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), | |
| ("cache", Unstable(sym::csky_target_feature), &[]), | |
| ("doloop", Unstable(sym::csky_target_feature), &[]), | |
| ("dsp1e2", Unstable(sym::csky_target_feature), &[]), | |
| ("dspe60", Unstable(sym::csky_target_feature), &[]), | |
| ("e1", Unstable(sym::csky_target_feature), &["elrw"]), | |
| ("e2", Unstable(sym::csky_target_feature), &["e2"]), | |
| ("edsp", Unstable(sym::csky_target_feature), &[]), | |
| ("elrw", Unstable(sym::csky_target_feature), &[]), | |
| ("float1e2", Unstable(sym::csky_target_feature), &[]), | |
| ("float1e3", Unstable(sym::csky_target_feature), &[]), | |
| ("float3e4", Unstable(sym::csky_target_feature), &[]), | |
| ("float7e60", Unstable(sym::csky_target_feature), &[]), | |
| ("floate1", Unstable(sym::csky_target_feature), &[]), | |
| ("hard-tp", Unstable(sym::csky_target_feature), &[]), | |
| ("high-registers", Unstable(sym::csky_target_feature), &[]), | |
| ("hwdiv", Unstable(sym::csky_target_feature), &[]), | |
| ("mp", Unstable(sym::csky_target_feature), &["2e3"]), | |
| ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]), | |
| ("nvic", Unstable(sym::csky_target_feature), &[]), | |
| ("trust", Unstable(sym::csky_target_feature), &[]), | |
| ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]), | |
| ("vdspv1", Unstable(sym::csky_target_feature), &[]), | |
| ("vdspv2", Unstable(sym::csky_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| //fpu | |
| // tidy-alphabetical-start | |
| ("fdivdu", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv2_df", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv3_df", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]), | |
| ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]), | |
| ("hard-float", Unstable(sym::csky_target_feature), &[]), | |
| ("hard-float-abi", Unstable(sym::csky_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("32s", Unstable(sym::loongarch_target_feature), &[]), | |
| ("d", Stable, &["f"]), | |
| ("div32", Unstable(sym::loongarch_target_feature), &[]), | |
| ("f", Stable, &[]), | |
| ("frecipe", Stable, &[]), | |
| ("lam-bh", Unstable(sym::loongarch_target_feature), &[]), | |
| ("lamcas", Unstable(sym::loongarch_target_feature), &[]), | |
| ("lasx", Stable, &["lsx"]), | |
| ("lbt", Stable, &[]), | |
| ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]), | |
| ("lsx", Stable, &["d"]), | |
| ("lvz", Stable, &[]), | |
| ("relax", Unstable(sym::loongarch_target_feature), &[]), | |
| ("scq", Unstable(sym::loongarch_target_feature), &[]), | |
| ("ual", Unstable(sym::loongarch_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| #[rustfmt::skip] | |
| const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker | |
| ("backchain", Unstable(sym::s390x_target_feature), &[]), | |
| ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), | |
| ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), | |
| ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), | |
| ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), | |
| ("high-word", Unstable(sym::s390x_target_feature), &[]), | |
| // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. | |
| ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), | |
| ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), | |
| ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), | |
| ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), | |
| ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), | |
| ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), | |
| ("miscellaneous-extensions-2", Stable, &[]), | |
| ("miscellaneous-extensions-3", Stable, &[]), | |
| ("miscellaneous-extensions-4", Stable, &[]), | |
| ("nnp-assist", Stable, &["vector"]), | |
| ("soft-float", Forbidden { reason: "unsupported ABI-configuration feature" }, &[]), | |
| ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), | |
| ("vector", Stable, &[]), | |
| ("vector-enhancements-1", Stable, &["vector"]), | |
| ("vector-enhancements-2", Stable, &["vector-enhancements-1"]), | |
| ("vector-enhancements-3", Stable, &["vector-enhancements-2"]), | |
| ("vector-packed-decimal", Stable, &["vector"]), | |
| ("vector-packed-decimal-enhancement", Stable, &["vector-packed-decimal"]), | |
| ("vector-packed-decimal-enhancement-2", Stable, &["vector-packed-decimal-enhancement"]), | |
| ("vector-packed-decimal-enhancement-3", Stable, &["vector-packed-decimal-enhancement-2"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("leoncasa", Unstable(sym::sparc_target_feature), &[]), | |
| ("v8plus", Unstable(sym::sparc_target_feature), &[]), | |
| ("v9", Unstable(sym::sparc_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("isa-68000", Unstable(sym::m68k_target_feature), &[]), | |
| ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]), | |
| ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]), | |
| ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]), | |
| ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]), | |
| ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]), | |
| // FPU | |
| ("isa-68881", Unstable(sym::m68k_target_feature), &[]), | |
| ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]), | |
| // tidy-alphabetical-end | |
| ]; | |
| static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ | |
| // tidy-alphabetical-start | |
| ("addsubiw", Unstable(sym::avr_target_feature), &[]), | |
| ("break", Unstable(sym::avr_target_feature), &[]), | |
| ("eijmpcall", Unstable(sym::avr_target_feature), &[]), | |
| ("elpm", Unstable(sym::avr_target_feature), &[]), | |
| ("elpmx", Unstable(sym::avr_target_feature), &[]), | |
| ("ijmpcall", Unstable(sym::avr_target_feature), &[]), | |
| ("jmpcall", Unstable(sym::avr_target_feature), &[]), | |
| ("lowbytefirst", Unstable(sym::avr_target_feature), &[]), | |
| ("lpm", Unstable(sym::avr_target_feature), &[]), | |
| ("lpmx", Unstable(sym::avr_target_feature), &[]), | |
| ("movw", Unstable(sym::avr_target_feature), &[]), | |
| ("mul", Unstable(sym::avr_target_feature), &[]), | |
| ("rmw", Unstable(sym::avr_target_feature), &[]), | |
| ("spm", Unstable(sym::avr_target_feature), &[]), | |
| ("spmx", Unstable(sym::avr_target_feature), &[]), | |
| ("sram", Forbidden { reason: "devices that have no SRAM are unsupported" }, &[]), | |
| ("tinyencoding", Unstable(sym::avr_target_feature), &[]), | |
| // tidy-alphabetical-end | |
| ]; | |
| /// When rustdoc is running, provide a list of all known features so that all their respective | |
| /// primitives may be documented. | |
| /// | |
| /// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator! | |
| pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> { | |
| std::iter::empty() | |
| .chain(ARM_FEATURES.iter()) | |
| .chain(AARCH64_FEATURES.iter()) | |
| .chain(X86_FEATURES.iter()) | |
| .chain(HEXAGON_FEATURES.iter()) | |
| .chain(POWERPC_FEATURES.iter()) | |
| .chain(MIPS_FEATURES.iter()) | |
| .chain(NVPTX_FEATURES.iter()) | |
| .chain(RISCV_FEATURES.iter()) | |
| .chain(WASM_FEATURES.iter()) | |
| .chain(BPF_FEATURES.iter()) | |
| .chain(CSKY_FEATURES) | |
| .chain(LOONGARCH_FEATURES) | |
| .chain(IBMZ_FEATURES) | |
| .chain(SPARC_FEATURES) | |
| .chain(M68K_FEATURES) | |
| .chain(AVR_FEATURES) | |
| .cloned() | |
| .map(|(f, s, _)| (f, s)) | |
| } | |
| // These arrays represent the least-constraining feature that is required for vector types up to a | |
| // certain size to have their "proper" ABI on each architecture. | |
| // Note that they must be kept sorted by vector size. | |
| const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10. | |
| const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "neon")]; | |
| // We might want to add "helium" too. | |
| const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "neon")]; | |
| const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(1024, "")]; | |
| const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "altivec")]; | |
| const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "simd128")]; | |
| const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "vector")]; | |
| const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[ | |
| (32, "zvl32b"), | |
| (64, "zvl64b"), | |
| (128, "zvl128b"), | |
| (256, "zvl256b"), | |
| (512, "zvl512b"), | |
| (1024, "zvl1024b"), | |
| (2048, "zvl2048b"), | |
| (4096, "zvl4096b"), | |
| (8192, "zvl8192b"), | |
| (16384, "zvl16384b"), | |
| (32768, "zvl32768b"), | |
| (65536, "zvl65536b"), | |
| ]; | |
| // Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment. | |
| const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[/*(64, "vis")*/]; | |
| const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[ | |
| (512, "hvx-length64b"), // HvxVector in 64-byte mode | |
| (1024, "hvx-length128b"), // HvxVector in 128-byte mode, or HvxVectorPair in 64-byte mode | |
| (2048, "hvx-length128b"), // HvxVectorPair in 128-byte mode | |
| ]; | |
| const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "msa")]; | |
| const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "vdspv1")]; | |
| const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = | |
| &[(128, "lsx"), (256, "lasx")]; | |
| #[derive(Copy, Clone, Debug)] | |
| pub struct FeatureConstraints { | |
| /// Features that must be enabled. | |
| pub required: &'static [&'static str], | |
| /// Features that must be disabled. | |
| pub incompatible: &'static [&'static str], | |
| } | |
| impl Target { | |
| pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] { | |
| match &self.arch { | |
| Arch::Arm => ARM_FEATURES, | |
| Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES, | |
| Arch::X86 | Arch::X86_64 => X86_FEATURES, | |
| Arch::Hexagon => HEXAGON_FEATURES, | |
| Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => MIPS_FEATURES, | |
| Arch::Nvptx64 => NVPTX_FEATURES, | |
| Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES, | |
| Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES, | |
| Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES, | |
| Arch::Bpf => BPF_FEATURES, | |
| Arch::CSky => CSKY_FEATURES, | |
| Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES, | |
| Arch::S390x => IBMZ_FEATURES, | |
| Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES, | |
| Arch::M68k => M68K_FEATURES, | |
| Arch::Avr => AVR_FEATURES, | |
| Arch::AmdGpu | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], | |
| } | |
| } | |
| pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] { | |
| match &self.arch { | |
| Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::LoongArch32 | Arch::LoongArch64 => { | |
| LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI | |
| } | |
| Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => { | |
| MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI | |
| } | |
| Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| Arch::Nvptx64 | Arch::Bpf | Arch::M68k | Arch::Avr => &[], // no vector ABI | |
| Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, | |
| // FIXME: for some tier3 targets, we are overly cautious and always give warnings | |
| // when passing args in vector registers. | |
| Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], | |
| } | |
| } | |
| pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> { | |
| match &self.arch { | |
| Arch::AArch64 | Arch::Arm64EC => Some("sve"), | |
| // Other targets have no scalable vectors or they are unimplemented. | |
| _ => None, | |
| } | |
| } | |
| pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { | |
| match &self.arch { | |
| Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES, | |
| _ => &[], | |
| } | |
| } | |
| // Note: the returned set includes `base_feature`. | |
| pub fn implied_target_features<'a>(&self, base_feature: &'a str) -> FxHashSet<&'a str> { | |
| let implied_features = | |
| self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>(); | |
| // Implied target features have their own implied target features, so we traverse the | |
| // map until there are no more features to add. | |
| let mut features = FxHashSet::default(); | |
| let mut new_features = vec![base_feature]; | |
| while let Some(new_feature) = new_features.pop() { | |
| if features.insert(new_feature) { | |
| if let Some(implied_features) = implied_features.get(&new_feature) { | |
| new_features.extend(implied_features.iter().copied()) | |
| } | |
| } | |
| } | |
| features | |
| } | |
| /// Returns two lists of features: | |
| /// the first list contains target features that must be enabled for ABI reasons, | |
| /// and the second list contains target feature that must be disabled for ABI reasons. | |
| /// | |
| /// These features are automatically appended to whatever the target spec sets as default | |
| /// features for the target. | |
| /// | |
| /// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked | |
| /// against this. We also check any implied features, based on the information above. If LLVM | |
| /// implicitly enables more implied features than we do, that could bypass this check! | |
| pub fn abi_required_features(&self) -> FeatureConstraints { | |
| const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] }; | |
| // Some architectures don't have a clean explicit ABI designation; instead, the ABI is | |
| // defined by target features. When that is the case, those target features must be | |
| // "forbidden" in the list above to ensure that there is a consistent answer to the | |
| // questions "which ABI is used". | |
| match &self.arch { | |
| Arch::X86 => { | |
| // We use our own ABI indicator here; LLVM does not have anything native. | |
| // Every case should require or forbid `soft-float`! | |
| match self.rustc_abi { | |
| None => { | |
| // Default hardfloat ABI. | |
| // x87 must be enabled, soft-float must be disabled. | |
| FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] } | |
| } | |
| Some(RustcAbi::X86Sse2) => { | |
| // Extended hardfloat ABI. x87 and SSE2 must be enabled, soft-float must be disabled. | |
| FeatureConstraints { | |
| required: &["x87", "sse2"], | |
| incompatible: &["soft-float"], | |
| } | |
| } | |
| Some(RustcAbi::Softfloat) => { | |
| // Softfloat ABI, requires corresponding target feature. That feature trumps | |
| // `x87` and all other FPU features so those do not matter. | |
| // Note that this one requirement is the entire implementation of the ABI! | |
| // LLVM handles the rest. | |
| FeatureConstraints { required: &["soft-float"], incompatible: &[] } | |
| } | |
| } | |
| } | |
| Arch::X86_64 => { | |
| // We use our own ABI indicator here; LLVM does not have anything native. | |
| // Every case should require or forbid `soft-float`! | |
| match self.rustc_abi { | |
| None => { | |
| // Default hardfloat ABI. On x86-64, this always includes SSE2. | |
| FeatureConstraints { | |
| required: &["x87", "sse2"], | |
| incompatible: &["soft-float"], | |
| } | |
| } | |
| Some(RustcAbi::Softfloat) => { | |
| // Softfloat ABI, requires corresponding target feature. That feature trumps | |
| // `x87` and all other FPU features so those do not matter. | |
| // Note that this one requirement is the entire implementation of the ABI! | |
| // LLVM handles the rest. | |
| FeatureConstraints { required: &["soft-float"], incompatible: &[] } | |
| } | |
| Some(r) => panic!("invalid Rust ABI for x86_64: {r:?}"), | |
| } | |
| } | |
| Arch::Arm => { | |
| // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate | |
| // to LLVM which ABI we are going for. | |
| match self.llvm_floatabi.unwrap() { | |
| FloatAbi::Soft => { | |
| // Nothing special required, will use soft-float ABI throughout. | |
| // We can even allow `-soft-float` here; in fact that is useful as it lets | |
| // people use FPU instructions with a softfloat ABI (corresponds to | |
| // `-mfloat-abi=softfp` in GCC/clang). | |
| NOTHING | |
| } | |
| FloatAbi::Hard => { | |
| // Must have `fpregs` and must not have `soft-float`. | |
| FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] } | |
| } | |
| } | |
| } | |
| Arch::AArch64 | Arch::Arm64EC => { | |
| // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force | |
| // the use of soft-float, so all we can do here is some crude hacks. | |
| if self.abi == Abi::SoftFloat { | |
| // LLVM will use float registers when `fp-armv8` is available, e.g. for | |
| // calls to built-ins. The only way to ensure a consistent softfloat ABI | |
| // on aarch64 is to never enable `fp-armv8`, so we enforce that. | |
| // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the | |
| // feature we have to mark as incompatible. | |
| FeatureConstraints { required: &[], incompatible: &["neon"] } | |
| } else { | |
| // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. | |
| // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up. | |
| FeatureConstraints { required: &["neon"], incompatible: &[] } | |
| } | |
| } | |
| Arch::RiscV32 | Arch::RiscV64 => { | |
| // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname` | |
| // about what the intended ABI is. | |
| match &*self.llvm_abiname { | |
| "ilp32d" | "lp64d" => { | |
| // Requires d (which implies f), incompatible with e and zfinx. | |
| FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] } | |
| } | |
| "ilp32f" | "lp64f" => { | |
| // Requires f, incompatible with e and zfinx. | |
| FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] } | |
| } | |
| "ilp32" | "lp64" => { | |
| // Requires nothing, incompatible with e. | |
| FeatureConstraints { required: &[], incompatible: &["e"] } | |
| } | |
| "ilp32e" => { | |
| // ilp32e is documented to be incompatible with features that need aligned | |
| // load/stores > 32 bits, like `d`. (One could also just generate more | |
| // complicated code to align the stack when needed, but the RISCV | |
| // architecture manual just explicitly rules out this combination so we | |
| // might as well.) | |
| // Note that the `e` feature is not required: the ABI treats the extra | |
| // registers as caller-save, so it is safe to use them only in some parts of | |
| // a program while the rest doesn't know they even exist. | |
| FeatureConstraints { required: &[], incompatible: &["d"] } | |
| } | |
| "lp64e" => { | |
| // As above, `e` is not required. | |
| NOTHING | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| Arch::LoongArch32 | Arch::LoongArch64 => { | |
| // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname` | |
| // about what the intended ABI is. | |
| match &*self.llvm_abiname { | |
| "ilp32d" | "lp64d" => { | |
| // Requires d (which implies f), incompatible with nothing. | |
| FeatureConstraints { required: &["d"], incompatible: &[] } | |
| } | |
| "ilp32f" | "lp64f" => { | |
| // Requires f, incompatible with nothing. | |
| FeatureConstraints { required: &["f"], incompatible: &[] } | |
| } | |
| "ilp32s" | "lp64s" => { | |
| // The soft-float ABI does not require any features and is also not | |
| // incompatible with any features. Rust targets explicitly specify the | |
| // LLVM ABI names, which allows for enabling hard-float support even on | |
| // soft-float targets, and ensures that the ABI behavior is as expected. | |
| NOTHING | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| Arch::S390x => { | |
| // Same as x86, We use our own ABI indicator here; | |
| // LLVM does not have anything native and will switch ABI based | |
| // on the soft-float target feature. | |
| // Every case should require or forbid `soft-float`! | |
| // The "vector" target feature may only be used without soft-float | |
| // because the float and vector registers overlap and the | |
| // standard s390x C ABI may pass vectors via these registers. | |
| match self.rustc_abi { | |
| None => { | |
| // Default hardfloat ABI. | |
| FeatureConstraints { required: &[], incompatible: &["soft-float"] } | |
| } | |
| Some(RustcAbi::Softfloat) => { | |
| // Softfloat ABI, requires corresponding target feature. | |
| // llvm will switch to soft-float ABI just based on this feature. | |
| FeatureConstraints { required: &["soft-float"], incompatible: &["vector"] } | |
| } | |
| Some(r) => { | |
| panic!("invalid Rust ABI for s390x: {r:?}"); | |
| } | |
| } | |
| } | |
| Arch::Avr => { | |
| // SRAM is minimum requirement for C/C++ in both avr-gcc and Clang, | |
| // and backends of them only support assembly for devices have no SRAM. | |
| // See the discussion in https://github.com/rust-lang/rust/pull/146900 for more. | |
| FeatureConstraints { required: &["sram"], incompatible: &[] } | |
| } | |
| _ => NOTHING, | |
| } | |
| } | |
| } |