From 2bf27e09beb4cd1c5f01369e7086e36b3de04f5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Dec 2024 18:32:22 +0100 Subject: [PATCH 1/7] explicitly model that certain ABIs require/forbid certain target features --- compiler/rustc_codegen_llvm/messages.ftl | 4 +- compiler/rustc_codegen_llvm/src/errors.rs | 7 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 220 ++++++++++-------- compiler/rustc_codegen_ssa/messages.ftl | 2 +- .../rustc_codegen_ssa/src/target_features.rs | 52 ++--- .../src/middle/codegen_fn_attrs.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 30 ++- compiler/rustc_target/src/target_features.rs | 208 ++++++++--------- tests/codegen/tied-features-strength.rs | 7 +- .../feature-hierarchy.aarch64-sve2.stderr | 2 +- ...dden-hardfloat-target-feature-attribute.rs | 10 +- ...-hardfloat-target-feature-attribute.stderr | 6 +- ...at-target-feature-flag-disable-neon.stderr | 2 +- ...rdfloat-target-feature-flag-disable.stderr | 8 +- .../forbidden-target-feature-attribute.rs | 2 +- .../forbidden-target-feature-attribute.stderr | 2 +- ...rbidden-target-feature-flag-disable.stderr | 2 +- .../forbidden-target-feature-flag.stderr | 2 +- 18 files changed, 299 insertions(+), 268 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 63c64269eb805..224454489073c 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -8,7 +8,7 @@ codegen_llvm_dynamic_linking_with_lto = codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture codegen_llvm_forbidden_ctarget_feature = - target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason} + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 @@ -22,8 +22,6 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two = codegen_llvm_invalid_minimum_alignment_too_large = invalid minimum global alignment: {$align} is too large -codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`" - codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}" codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 3cdb5b971d908..843d0d6c39fe4 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -37,6 +37,7 @@ pub(crate) struct UnstableCTargetFeature<'a> { #[note(codegen_llvm_forbidden_ctarget_feature_issue)] pub(crate) struct ForbiddenCTargetFeature<'a> { pub feature: &'a str, + pub enabled: &'a str, pub reason: &'a str, } @@ -205,12 +206,6 @@ pub(crate) struct MismatchedDataLayout<'a> { pub llvm_layout: &'a str, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_invalid_target_feature_prefix)] -pub(crate) struct InvalidTargetFeaturePrefix<'a> { - pub feature: &'a str, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_fixed_x18_invalid_arch)] pub(crate) struct FixedX18InvalidArch<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 628c0b1c29c44..0486ae84b82db 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -21,8 +21,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU use crate::back::write::create_informational_target_machine; use crate::errors::{ - FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature, - UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, + UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; @@ -348,7 +348,16 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec { if enabled { // Also add all transitively implied features. - features.extend(sess.target.implied_target_features(std::iter::once(feature))); + + // We don't care about the order in `features` since the only thing we use it for is the + // `features.contains` below. + #[allow(rustc::potential_query_instability)] + features.extend( + sess.target + .implied_target_features(std::iter::once(feature.as_str())) + .iter() + .map(|s| Symbol::intern(s)), + ); } else { // Remove transitively reverse-implied features. @@ -356,7 +365,11 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec // `features.contains` below. #[allow(rustc::potential_query_instability)] features.retain(|f| { - if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) { + if sess + .target + .implied_target_features(std::iter::once(f.as_str())) + .contains(&feature.as_str()) + { // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to // remove `f`. (This is the standard logical contraposition principle.) false @@ -638,7 +651,7 @@ pub(crate) fn global_llvm_features( sess.target .features .split(',') - .filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some()) + .filter(|v| !v.is_empty()) // Drop +v8plus feature introduced in LLVM 20. .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0)) .map(String::from), @@ -651,89 +664,126 @@ pub(crate) fn global_llvm_features( // -Ctarget-features if !only_base_features { let known_features = sess.target.rust_target_features(); + // Will only be filled when `diagnostics` is set! let mut featsmap = FxHashMap::default(); - // insert implied features + // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones + // are disabled. + let (abi_enable, abi_disable) = sess.target.abi_required_features(); + let abi_enable_set = FxHashSet::from_iter(abi_enable.iter().copied()); + let abi_disable_set = FxHashSet::from_iter(abi_disable.iter().copied()); + + // Compute implied features let mut all_rust_features = vec![]; for feature in sess.opts.cg.target_feature.split(',') { - match feature.strip_prefix('+') { - Some(feature) => all_rust_features.extend( - UnordSet::from( - sess.target - .implied_target_features(std::iter::once(Symbol::intern(feature))), - ) - .to_sorted_stable_ord() - .iter() - .map(|s| format!("+{}", s.as_str())), - ), - _ => all_rust_features.push(feature.to_string()), + if let Some(feature) = feature.strip_prefix('+') { + all_rust_features.extend( + UnordSet::from(sess.target.implied_target_features(std::iter::once(feature))) + .to_sorted_stable_ord() + .iter() + .map(|&&s| (true, s)), + ) + } else if let Some(feature) = feature.strip_prefix('-') { + // FIXME: Why do we not remove implied features on "-" here? + // We do the equivalent above in `target_features_cfg`. + // See . + all_rust_features.push((false, feature)); + } else if !feature.is_empty() { + if diagnostics { + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); + } } } + // Remove features that are meant for rustc, not LLVM. + all_rust_features.retain(|(_, feature)| { + // Retain if it is not a rustc feature + !RUSTC_SPECIFIC_FEATURES.contains(feature) + }); - let feats = all_rust_features - .iter() - .filter_map(|s| { - let enable_disable = match s.chars().next() { - None => return None, - Some(c @ ('+' | '-')) => c, - Some(_) => { - if diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); - } - return None; - } - }; - - // Get the backend feature name, if any. - // This excludes rustc-specific features, which do not get passed to LLVM. - let feature = backend_feature_name(sess, s)?; - // Warn against use of LLVM specific feature names and unstable features on the CLI. - if diagnostics { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = - known_features.iter().find_map(|&(rust_feature, _, _)| { - let llvm_features = to_llvm_features(sess, rust_feature)?; - if llvm_features.contains(feature) - && !llvm_features.contains(rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::None, + // Check feature validity. + if diagnostics { + for &(enable, feature) in &all_rust_features { + let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); + match feature_state { + None => { + let rust_feature = + known_features.iter().find_map(|&(rust_feature, _, _)| { + let llvm_features = to_llvm_features(sess, rust_feature)?; + if llvm_features.contains(feature) + && !llvm_features.contains(rust_feature) + { + Some(rust_feature) + } else { + None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some((_, stability, _)) => { - if let Err(reason) = - stability.toggle_allowed(&sess.target, enable_disable == '+') - { - sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + UnknownCTargetFeature { + feature, + rust_feature: PossibleFeature::Some { rust_feature }, } + } else { + UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } + }; + sess.dcx().emit_warn(unknown_feature); + } + Some((_, stability, _)) => { + if let Err(reason) = stability.toggle_allowed(&sess.target, enable) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if stability.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); } } + } - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable_disable == '+'); + // Ensure that the features we enable/disable are compatible with the ABI. + if enable { + if abi_disable_set.contains(feature) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: "enabled", + reason: "this feature is incompatible with the target ABI", + }); + } + } else { + if abi_enable_set.contains(feature) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: "disabled", + reason: "this feature is required by the target ABI", + }); + } } + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable); + } + } + + // To be sure the ABI-relevant features are all in the right state, we explicitly + // (un)set them here. This means if the target spec sets those features wrong, + // we will silently correct them rather than silently producing wrong code. + // (The target sanity check tries to catch this, but we can't know which features are + // enabled in LLVM by default so we can't be fully sure about that check.) + for feature in abi_enable { + all_rust_features.push((true, feature)); + } + for feature in abi_disable { + all_rust_features.push((false, feature)); + } + + // Translate this into LLVM features. + let feats = all_rust_features + .iter() + .filter_map(|&(enable, feature)| { + let enable_disable = if enable { '+' } else { '-' }; // We run through `to_llvm_features` when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two @@ -746,9 +796,9 @@ pub(crate) fn global_llvm_features( enable_disable, llvm_feature.llvm_feature_name )) .chain(llvm_feature.dependency.into_iter().filter_map( - move |feat| match (enable_disable, feat) { - ('-' | '+', TargetFeatureFoldStrength::Both(f)) - | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => { + move |feat| match (enable, feat) { + (_, TargetFeatureFoldStrength::Both(f)) + | (true, TargetFeatureFoldStrength::EnableOnly(f)) => { Some(format!("{enable_disable}{f}")) } _ => None, @@ -780,22 +830,6 @@ pub(crate) fn global_llvm_features( features } -/// Returns a feature name for the given `+feature` or `-feature` string. -/// -/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].) -fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { - // features must start with a `+` or `-`. - let feature = s - .strip_prefix(&['+', '-'][..]) - .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); - // Rustc-specific feature requests like `+crt-static` or `-crt-static` - // are not passed down to LLVM. - if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) { - return None; - } - Some(feature) -} - pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> { let name = sess.opts.unstable_opts.tune_cpu.as_ref()?; Some(handle_native(name)) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 56188714b44fd..484f467068a14 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -67,7 +67,7 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error} codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` codegen_ssa_forbidden_target_feature_attr = - target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason} + target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason} codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 7e80d014ea282..af9ff311061b3 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -32,7 +32,7 @@ pub(crate) fn from_target_feature_attr( .emit(); }; let rust_features = tcx.features(); - let mut added_target_features = Vec::new(); + let (_abi_enable, abi_disable) = tcx.sess.target.abi_required_features(); for item in list { // Only `enable = ...` is accepted in the meta-item list. if !item.has_name(sym::enable) { @@ -47,7 +47,7 @@ pub(crate) fn from_target_feature_attr( }; // We allow comma separation to enable multiple features. - added_target_features.extend(value.as_str().split(',').filter_map(|feature| { + for feature in value.as_str().split(',') { let Some(stability) = rust_target_features.get(feature) else { let msg = format!("the feature named `{feature}` is not valid for this target"); let mut err = tcx.dcx().struct_span_err(item.span(), msg); @@ -59,7 +59,7 @@ pub(crate) fn from_target_feature_attr( } } err.emit(); - return None; + continue; }; // Only allow target features whose feature gates have been enabled @@ -80,31 +80,25 @@ pub(crate) fn from_target_feature_attr( format!("the target feature `{feature}` is currently unstable"), ) .emit(); + } else { + // Add this and the implied features. + let feature_sym = Symbol::intern(feature); + for &name in tcx.implied_target_features(feature_sym) { + // But ensure the ABI does not forbid enabling this. + // Here we do assume that LLVM doesn't add even more implied features + // we don't know about, at least no features that would have ABI effects! + if abi_disable.contains(&name.as_str()) { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: item.span(), + feature: name.as_str(), + reason: "this feature is incompatible with the target ABI", + }); + } + target_features.push(TargetFeature { name, implied: name != feature_sym }) + } } - Some(Symbol::intern(feature)) - })); - } - - // Add explicit features - target_features.extend( - added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }), - ); - - // Add implied features - let mut implied_target_features = UnordSet::new(); - for feature in added_target_features.iter() { - implied_target_features.extend(tcx.implied_target_features(*feature).clone()); - } - for feature in added_target_features.iter() { - implied_target_features.remove(feature); + } } - target_features.extend( - implied_target_features - .into_sorted_stable_ord() - .iter() - .copied() - .map(|name| TargetFeature { name, implied: true }), - ) } /// Computes the set of target features used in a function for the purposes of @@ -163,9 +157,13 @@ pub(crate) fn provide(providers: &mut Providers) { .collect() } }, - implied_target_features: |tcx, feature| { + implied_target_features: |tcx, feature: Symbol| { + let feature = feature.as_str(); UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature))) .into_sorted_stable_ord() + .into_iter() + .map(|s| Symbol::intern(s)) + .collect() }, asm_target_features, ..*providers diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 241767fe249b1..16d868300db3b 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -28,6 +28,7 @@ pub struct CodegenFnAttrs { pub link_ordinal: Option, /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). + /// Implied target features have already been applied. pub target_features: Vec, /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found. pub linkage: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 02962d55a60ed..28011f632b34b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2651,10 +2651,6 @@ impl TargetOptions { pub(crate) fn has_feature(&self, search_feature: &str) -> bool { self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature)) } - - pub(crate) fn has_neg_feature(&self, search_feature: &str) -> bool { - self.features.split(',').any(|f| f.strip_prefix('-').is_some_and(|f| f == search_feature)) - } } impl Default for TargetOptions { @@ -3201,7 +3197,8 @@ impl Target { check_matches!( &*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e", - "invalid RISC-V ABI name" + "invalid RISC-V ABI name: {}", + self.llvm_abiname, ); } "riscv64" => { @@ -3209,7 +3206,8 @@ impl Target { check_matches!( &*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64e", - "invalid RISC-V ABI name" + "invalid RISC-V ABI name: {}", + self.llvm_abiname, ); } "arm" => { @@ -3243,6 +3241,26 @@ impl Target { )); } } + // Check that we don't mis-set any of the ABI-relevant features. + let (abi_enable, abi_disable) = self.abi_required_features(); + for feat in abi_enable { + // The feature might be enabled by default so we can't *require* it to show up. + // But it must not be *disabled*. + if features_disabled.contains(feat) { + return Err(format!( + "target feature `{feat}` is required by the ABI but gets disabled in target spec" + )); + } + } + for feat in abi_disable { + // The feature might be disable by default so we can't *require* it to show up. + // But it must not be *enabled*. + if features_enabled.contains(feat) { + return Err(format!( + "target feature `{feat}` is incompatible with the ABI but gets enabled in target spec" + )); + } + } } Ok(()) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5372437b0d2ab..dd9c3921fc27e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -213,22 +213,7 @@ const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ ("dotprod", unstable(sym::arm_target_feature), &["neon"]), ("dsp", unstable(sym::arm_target_feature), &[]), ("fp-armv8", unstable(sym::arm_target_feature), &["vfp4"]), - ( - "fpregs", - Stability::Unstable { - nightly_feature: sym::arm_target_feature, - allow_toggle: |target: &Target, _enable| { - // Only allow toggling this if the target has `soft-float` set. With `soft-float`, - // `fpregs` isn't needed so changing it cannot affect the ABI. - if target.has_feature("soft-float") { - Ok(()) - } else { - Err("unsound on hard-float targets because it changes float ABI") - } - }, - }, - &[], - ), + ("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"]), @@ -326,28 +311,7 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ // FEAT_MTE & FEAT_MTE2 ("mte", STABLE, &[]), // FEAT_AdvSimd & FEAT_FP - ( - "neon", - Stability::Stable { - allow_toggle: |target, enable| { - if target.abi == "softfloat" { - // `neon` has no ABI implications for softfloat targets, we can allow this. - Ok(()) - } else if enable - && !target.has_neg_feature("fp-armv8") - && !target.has_neg_feature("neon") - { - // neon is enabled by default, and has not been disabled, so enabling it again - // is redundant and we can permit it. Forbidding this would be a breaking change - // since this feature is stable. - Ok(()) - } else { - Err("unsound on hard-float targets because it changes float ABI") - } - }, - }, - &[], - ), + ("neon", STABLE, &[]), // FEAT_PAUTH (address authentication) ("paca", STABLE, &[]), // FEAT_PAUTH (generic authentication) @@ -532,22 +496,7 @@ const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ ("tbm", unstable(sym::tbm_target_feature), &[]), ("vaes", unstable(sym::avx512_target_feature), &["avx2", "aes"]), ("vpclmulqdq", unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]), - ( - "x87", - Stability::Unstable { - nightly_feature: sym::x87_target_feature, - allow_toggle: |target: &Target, _enable| { - // Only allow toggling this if the target has `soft-float` set. With `soft-float`, - // `fpregs` isn't needed so changing it cannot affect the ABI. - if target.has_feature("soft-float") { - Ok(()) - } else { - Err("unsound on hard-float targets because it changes float ABI") - } - }, - }, - &[], - ), + ("x87", unstable(sym::x87_target_feature), &[]), ("xop", unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]), ("xsave", STABLE, &[]), ("xsavec", STABLE, &["xsave"]), @@ -590,55 +539,8 @@ const RISCV_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", STABLE, &["zaamo", "zalrsc"]), ("c", STABLE, &[]), - ( - "d", - Stability::Unstable { - nightly_feature: sym::riscv_target_feature, - allow_toggle: |target, enable| match &*target.llvm_abiname { - "ilp32d" | "lp64d" if !enable => { - // The ABI requires the `d` feature, so it cannot be disabled. - Err("feature is required by ABI") - } - "ilp32e" if enable => { - // ilp32e is incompatible with features that need aligned load/stores > 32 bits, - // like `d`. - Err("feature is incompatible with ABI") - } - _ => Ok(()), - }, - }, - &["f"], - ), - ( - "e", - Stability::Unstable { - // Given that this is a negative feature, consider this before stabilizing: - // does it really make sense to enable this feature in an individual - // function with `#[target_feature]`? - nightly_feature: sym::riscv_target_feature, - allow_toggle: |target, enable| { - match &*target.llvm_abiname { - _ if !enable => { - // Disabling this feature means we can use more registers (x16-x31). - // The "e" ABIs treat them 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. - // On other ABIs, the feature is already disabled anyway. - Ok(()) - } - "ilp32e" | "lp64e" => { - // Embedded ABIs should already have the feature anyway, it's fine to enable - // it again from an ABI perspective. - Ok(()) - } - _ => { - // *Not* an embedded ABI. Enabling `e` is invalid. - Err("feature is incompatible with ABI") - } - } - }, - }, - &[], - ), + ("d", unstable(sym::riscv_target_feature), &["f"]), + ("e", unstable(sym::riscv_target_feature), &[]), ( "f", Stability::Unstable { @@ -904,27 +806,107 @@ impl Target { } } - pub fn implied_target_features( + pub fn implied_target_features<'a>( &self, - base_features: impl Iterator, - ) -> FxHashSet { - let implied_features = self - .rust_target_features() - .iter() - .map(|(f, _, i)| (Symbol::intern(f), i)) - .collect::>(); + base_features: impl Iterator, + ) -> FxHashSet<&'a str> { + let implied_features = + self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::>(); // 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 = base_features.collect::>(); + let mut new_features = base_features.collect::>(); 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().map(Symbol::intern)) + 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. + /// + /// 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) -> (&'static [&'static str], &'static [&'static str]) { + const NOTHING: (&'static [&'static str], &'static [&'static str]) = (&[], &[]); + // 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 { + "x86" | "x86_64" => { + // We support 2 ABIs, hardfloat (default) and softfloat. + if self.has_feature("soft-float") { + NOTHING + } else { + // Hardfloat ABI. x87 must be enabled. + (&["x87"], &[]) + } + } + "arm" => { + // We support 2 ABIs, hardfloat (default) and softfloat. + if self.has_feature("soft-float") { + NOTHING + } else { + // Hardfloat ABI. x87 must be enabled. + (&["fpregs"], &[]) + } + } + "aarch64" | "arm64ec" => { + match &*self.abi { + "softfloat" => { + // This is not fully correct, LLVM actually doesn't let us enforce the softfloat + // ABI properly... see . + // FIXME: should be forbid "neon" here? But that would be a breaking change. + NOTHING + } + _ => { + // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. + // These are Rust feature names and we use "neon" to control both of them. + (&["neon"], &[]) + } + } + } + "riscv32" | "riscv64" => { + match &*self.llvm_abiname { + "ilp32d" | "lp64d" => { + // Requires d (which implies f), incompatible with e. + (&["d"], &["e"]) + } + "ilp32f" | "lp64f" => { + // Requires f, incompatible with e. + (&["f"], &["e"]) + } + "ilp32" | "lp64" => { + // Requires nothing, incompatible with e. + (&[], &["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. + (&[], &["d"]) + } + "lp64e" => { + // As above, `e` is not required. + NOTHING + } + _ => unreachable!(), + } + } + _ => NOTHING, + } + } } diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 1b2b63c3d1ac4..4d96a7cde7812 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -1,5 +1,5 @@ // ignore-tidy-linelength -//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON +//@ revisions: ENABLE_SVE DISABLE_SVE ENABLE_NEON //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 @@ -11,9 +11,10 @@ // ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" } //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 -// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?))*}}" } +// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" } -//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 +// The DISABLE_NEON is disabled since neon is a required target feature for this targt, it cannot be disabled. +// it would have: compile-flags: -C target-feature=-neon -Copt-level=0 // DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" } //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 diff --git a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr b/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr index d5d7d7aa627ba..b6c3ccdedfb00 100644 --- a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr +++ b/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr @@ -1,4 +1,4 @@ -warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI +warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs index b3171d52c510f..dab01179c0b36 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs @@ -1,11 +1,11 @@ -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -#![feature(no_core, lang_items)] +//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib +//@ needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature)] #![no_core] #[lang = "sized"] pub trait Sized {} -#[target_feature(enable = "x87")] -//~^ERROR: cannot be toggled with +#[target_feature(enable = "d")] +//~^ERROR: cannot be enabled with pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr index 3ebbe69d8aeca..9df56d86729c1 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr @@ -1,8 +1,8 @@ -error: target feature `x87` cannot be toggled with `#[target_feature]`: unsound on hard-float targets because it changes float ABI +error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18 | -LL | #[target_feature(enable = "x87")] - | ^^^^^^^^^^^^^^ +LL | #[target_feature(enable = "d")] + | ^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr index d5d7d7aa627ba..b6c3ccdedfb00 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr @@ -1,4 +1,4 @@ -warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI +warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr index 604ad2f991ae9..6191681286a36 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr @@ -1,7 +1,11 @@ -warning: target feature `x87` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI +warning: unstable feature specified for `-Ctarget-feature`: `x87` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: target feature `x87` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 -warning: 1 warning emitted +warning: 2 warnings emitted diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-target-feature-attribute.rs index f13cdd17da639..2ba5f2215c7b2 100644 --- a/tests/ui/target-feature/forbidden-target-feature-attribute.rs +++ b/tests/ui/target-feature/forbidden-target-feature-attribute.rs @@ -7,5 +7,5 @@ pub trait Sized {} #[target_feature(enable = "soft-float")] -//~^ERROR: cannot be toggled with +//~^ERROR: cannot be enabled with pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr index 27ac4aaf9605c..f3d54cc19d3e9 100644 --- a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr @@ -1,4 +1,4 @@ -error: target feature `soft-float` cannot be toggled with `#[target_feature]`: unsound because it changes float ABI +error: target feature `soft-float` cannot be enabled with `#[target_feature]`: unsound because it changes float ABI --> $DIR/forbidden-target-feature-attribute.rs:9:18 | LL | #[target_feature(enable = "soft-float")] diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr index 508e1fe0cf476..797cd4be5c27f 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr @@ -1,4 +1,4 @@ -warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI +warning: target feature `soft-float` cannot be disabled with `-Ctarget-feature`: unsound because it changes float ABI | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 diff --git a/tests/ui/target-feature/forbidden-target-feature-flag.stderr b/tests/ui/target-feature/forbidden-target-feature-flag.stderr index 508e1fe0cf476..075666fbf6682 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-flag.stderr @@ -1,4 +1,4 @@ -warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI +warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: unsound because it changes float ABI | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 From cfae43d6380279fb8b6995f9bf29deb490dc2ff4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Dec 2024 18:59:19 +0100 Subject: [PATCH 2/7] clean up target feature system; most of the toggleability is now handled by the ABI target feature check --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- .../rustc_codegen_ssa/src/target_features.rs | 9 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_target/src/target_features.rs | 774 ++++++++---------- 4 files changed, 349 insertions(+), 438 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0486ae84b82db..d4b2260123b0c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -728,7 +728,7 @@ pub(crate) fn global_llvm_features( sess.dcx().emit_warn(unknown_feature); } Some((_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed(&sess.target, enable) { + if let Err(reason) = stability.toggle_allowed() { sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, enabled: if enable { "enabled" } else { "disabled" }, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index af9ff311061b3..61eeae630ed07 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -19,7 +19,7 @@ use crate::errors; pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, attr: &hir::Attribute, - rust_target_features: &UnordMap, + rust_target_features: &UnordMap, target_features: &mut Vec, ) { let Some(list) = attr.meta_item_list() else { return }; @@ -64,7 +64,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed(/*enable*/ true) { + if let Err(reason) = stability.toggle_allowed() { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature, @@ -141,19 +141,18 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - let target = &tcx.sess.target; if tcx.sess.opts.actually_rustdoc { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all rustc_target::target_features::all_rust_features() - .map(|(a, b)| (a.to_string(), b.compute_toggleability(target))) + .map(|(a, b)| (a.to_string(), b)) .collect() } else { tcx.sess .target .rust_target_features() .iter() - .map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target))) + .map(|(a, b, _)| (a.to_string(), *b)) .collect() } }, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7e7b602c560ba..5f6a1a06a6a1a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2355,7 +2355,7 @@ rustc_queries! { } /// Returns the Rust target features for the current target. These are not always the same as LLVM target features! - query rust_target_features(_: CrateNum) -> &'tcx UnordMap { + query rust_target_features(_: CrateNum) -> &'tcx UnordMap { arena_cache eval_always desc { "looking up Rust target features" } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index dd9c3921fc27e..31e2cabed62a5 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -17,60 +17,34 @@ pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"]; /// Stability information for target features. -/// `Toggleability` is the type storing whether (un)stable features can be toggled: -/// this is initially a function since it can depend on `Target`, but for stable hashing -/// it needs to be something hashable to we have to make the type generic. -#[derive(Debug, Clone)] -pub enum Stability { +#[derive(Debug, Copy, Clone)] +pub enum Stability { /// This target feature is stable, it can be used in `#[target_feature]` and /// `#[cfg(target_feature)]`. - Stable { - /// When enabling/disabling the feature via `-Ctarget-feature` or `#[target_feature]`, - /// determine if that is allowed. - allow_toggle: Toggleability, - }, + 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 { + Unstable( /// This must be a *language* feature, or else rustc will ICE when reporting a missing /// feature gate! - nightly_feature: Symbol, - /// See `Stable::allow_toggle` comment above. - allow_toggle: Toggleability, - }, + 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 that change the floating-point ABI. + /// 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::*; -/// Returns `Ok` if the toggle is allowed, `Err` with an explanation of not. -/// The `bool` indicates whether the feature is being enabled (`true`) or disabled. -pub type AllowToggleUncomputed = fn(&Target, bool) -> Result<(), &'static str>; - -/// The computed result of whether a feature can be enabled/disabled on the current target. -#[derive(Debug, Clone)] -pub struct AllowToggleComputed { - enable: Result<(), &'static str>, - disable: Result<(), &'static str>, -} - -/// `Stability` where `allow_toggle` has not been computed yet. -pub type StabilityUncomputed = Stability; -/// `Stability` where `allow_toggle` has already been computed. -pub type StabilityComputed = Stability; - -impl> HashStable for Stability { +impl HashStable 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 { allow_toggle } => { - allow_toggle.hash_stable(hcx, hasher); - } - Stability::Unstable { nightly_feature, allow_toggle } => { + Stability::Stable => {} + Stability::Unstable(nightly_feature) => { nightly_feature.hash_stable(hcx, hasher); - allow_toggle.hash_stable(hcx, hasher); } Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); @@ -79,16 +53,7 @@ impl> HashStable for Stability HashStable for AllowToggleComputed { - #[inline] - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - let AllowToggleComputed { enable, disable } = self; - enable.hash_stable(hcx, hasher); - disable.hash_stable(hcx, hasher); - } -} - -impl Stability { +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`.) @@ -106,59 +71,23 @@ impl Stability { /// - for `cfg(target_feature)`, check `in_cfg` pub fn requires_nightly(&self) -> Option { match *self { - Stability::Unstable { nightly_feature, .. } => Some(nightly_feature), + Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), } } -} - -impl StabilityUncomputed { - pub fn compute_toggleability(&self, target: &Target) -> StabilityComputed { - use Stability::*; - let compute = |f: AllowToggleUncomputed| AllowToggleComputed { - enable: f(target, true), - disable: f(target, false), - }; - match *self { - Stable { allow_toggle } => Stable { allow_toggle: compute(allow_toggle) }, - Unstable { nightly_feature, allow_toggle } => { - Unstable { nightly_feature, allow_toggle: compute(allow_toggle) } - } - Forbidden { reason } => Forbidden { reason }, - } - } - - pub fn toggle_allowed(&self, target: &Target, enable: bool) -> Result<(), &'static str> { - use Stability::*; - match *self { - Stable { allow_toggle } => allow_toggle(target, enable), - Unstable { allow_toggle, .. } => allow_toggle(target, enable), - Forbidden { reason } => Err(reason), - } - } -} -impl StabilityComputed { /// 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, enable: bool) -> Result<(), &'static str> { - let allow_toggle = match self { - Stability::Stable { allow_toggle } => allow_toggle, - Stability::Unstable { allow_toggle, .. } => allow_toggle, - Stability::Forbidden { reason } => return Err(reason), - }; - if enable { allow_toggle.enable } else { allow_toggle.disable } + pub fn toggle_allowed(&self) -> Result<(), &'static str> { + match self { + Stability::Forbidden { reason } => Err(reason), + _ => Ok(()), + } } } -// Constructors for the list below, defaulting to "always allow toggle". -const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target, _enable| Ok(()) }; -const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed { - Stability::Unstable { nightly_feature, allow_toggle: |_target, _enable| Ok(()) } -} - // 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`. @@ -204,182 +133,182 @@ const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed { // Both of these are also applied transitively. type ImpliedFeatures = &'static [&'static str]; -const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("aclass", unstable(sym::arm_target_feature), &[]), - ("aes", unstable(sym::arm_target_feature), &["neon"]), - ("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"]), - ("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"]), + ("aclass", Unstable(sym::arm_target_feature), &[]), + ("aes", Unstable(sym::arm_target_feature), &["neon"]), + ("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"]), + ("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"]), ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]), // 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), &[]), + ("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 ]; -const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start // FEAT_AES & FEAT_PMULL - ("aes", STABLE, &["neon"]), + ("aes", Stable, &["neon"]), // FEAT_BF16 - ("bf16", STABLE, &[]), + ("bf16", Stable, &[]), // FEAT_BTI - ("bti", STABLE, &[]), + ("bti", Stable, &[]), // FEAT_CRC - ("crc", STABLE, &[]), + ("crc", Stable, &[]), // FEAT_CSSC - ("cssc", unstable(sym::aarch64_unstable_target_feature), &[]), + ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_DIT - ("dit", STABLE, &[]), + ("dit", Stable, &[]), // FEAT_DotProd - ("dotprod", STABLE, &["neon"]), + ("dotprod", Stable, &["neon"]), // FEAT_DPB - ("dpb", STABLE, &[]), + ("dpb", Stable, &[]), // FEAT_DPB2 - ("dpb2", STABLE, &["dpb"]), + ("dpb2", Stable, &["dpb"]), // FEAT_ECV - ("ecv", unstable(sym::aarch64_unstable_target_feature), &[]), + ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_F32MM - ("f32mm", STABLE, &["sve"]), + ("f32mm", Stable, &["sve"]), // FEAT_F64MM - ("f64mm", STABLE, &["sve"]), + ("f64mm", Stable, &["sve"]), // FEAT_FAMINMAX - ("faminmax", unstable(sym::aarch64_unstable_target_feature), &[]), + ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_FCMA - ("fcma", STABLE, &["neon"]), + ("fcma", Stable, &["neon"]), // FEAT_FHM - ("fhm", STABLE, &["fp16"]), + ("fhm", Stable, &["fp16"]), // FEAT_FLAGM - ("flagm", STABLE, &[]), + ("flagm", Stable, &[]), // FEAT_FLAGM2 - ("flagm2", unstable(sym::aarch64_unstable_target_feature), &[]), + ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), ("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]), // FEAT_FP16 // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 - ("fp16", STABLE, &["neon"]), + ("fp16", Stable, &["neon"]), // FEAT_FP8 - ("fp8", unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), + ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), // FEAT_FP8DOT2 - ("fp8dot2", unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), + ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), // FEAT_FP8DOT4 - ("fp8dot4", unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), + ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), // FEAT_FP8FMA - ("fp8fma", unstable(sym::aarch64_unstable_target_feature), &["fp8"]), + ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), // FEAT_FRINTTS - ("frintts", STABLE, &[]), + ("frintts", Stable, &[]), // FEAT_HBC - ("hbc", unstable(sym::aarch64_unstable_target_feature), &[]), + ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_I8MM - ("i8mm", STABLE, &[]), + ("i8mm", Stable, &[]), // FEAT_JSCVT // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 - ("jsconv", STABLE, &["neon"]), + ("jsconv", Stable, &["neon"]), // FEAT_LOR - ("lor", STABLE, &[]), + ("lor", Stable, &[]), // FEAT_LSE - ("lse", STABLE, &[]), + ("lse", Stable, &[]), // FEAT_LSE128 - ("lse128", unstable(sym::aarch64_unstable_target_feature), &["lse"]), + ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), // FEAT_LSE2 - ("lse2", unstable(sym::aarch64_unstable_target_feature), &[]), + ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_LUT - ("lut", unstable(sym::aarch64_unstable_target_feature), &[]), + ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_MOPS - ("mops", unstable(sym::aarch64_unstable_target_feature), &[]), + ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_MTE & FEAT_MTE2 - ("mte", STABLE, &[]), + ("mte", Stable, &[]), // FEAT_AdvSimd & FEAT_FP - ("neon", STABLE, &[]), + ("neon", Stable, &[]), // FEAT_PAUTH (address authentication) - ("paca", STABLE, &[]), + ("paca", Stable, &[]), // FEAT_PAUTH (generic authentication) - ("pacg", STABLE, &[]), + ("pacg", Stable, &[]), // FEAT_PAN - ("pan", STABLE, &[]), + ("pan", Stable, &[]), // FEAT_PAuth_LR - ("pauth-lr", unstable(sym::aarch64_unstable_target_feature), &[]), + ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_PMUv3 - ("pmuv3", STABLE, &[]), + ("pmuv3", Stable, &[]), // FEAT_RNG - ("rand", STABLE, &[]), + ("rand", Stable, &[]), // FEAT_RAS & FEAT_RASv1p1 - ("ras", STABLE, &[]), + ("ras", Stable, &[]), // FEAT_LRCPC - ("rcpc", STABLE, &[]), + ("rcpc", Stable, &[]), // FEAT_LRCPC2 - ("rcpc2", STABLE, &["rcpc"]), + ("rcpc2", Stable, &["rcpc"]), // FEAT_LRCPC3 - ("rcpc3", unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), + ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), // FEAT_RDM - ("rdm", STABLE, &["neon"]), + ("rdm", Stable, &["neon"]), // This is needed for inline assembly, but shouldn't be stabilized as-is // since it should be enabled globally using -Zfixed-x18, not // #[target_feature]. // Note that cfg(target_feature = "reserve-x18") is currently not set for // targets that reserve x18 by default. - ("reserve-x18", unstable(sym::aarch64_unstable_target_feature), &[]), + ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_SB - ("sb", STABLE, &[]), + ("sb", Stable, &[]), // FEAT_SHA1 & FEAT_SHA256 - ("sha2", STABLE, &["neon"]), + ("sha2", Stable, &["neon"]), // FEAT_SHA512 & FEAT_SHA3 - ("sha3", STABLE, &["sha2"]), + ("sha3", Stable, &["sha2"]), // FEAT_SM3 & FEAT_SM4 - ("sm4", STABLE, &["neon"]), + ("sm4", Stable, &["neon"]), // FEAT_SME - ("sme", unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), // FEAT_SME_B16B16 - ("sme-b16b16", unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), + ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), // FEAT_SME_F16F16 - ("sme-f16f16", unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), // FEAT_SME_F64F64 - ("sme-f64f64", unstable(sym::aarch64_unstable_target_feature), &["sme"]), + ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), // FEAT_SME_F8F16 - ("sme-f8f16", unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), + ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), // FEAT_SME_F8F32 - ("sme-f8f32", unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), // FEAT_SME_FA64 - ("sme-fa64", unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), + ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), // FEAT_SME_I16I64 - ("sme-i16i64", unstable(sym::aarch64_unstable_target_feature), &["sme"]), + ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), // FEAT_SME_LUTv2 - ("sme-lutv2", unstable(sym::aarch64_unstable_target_feature), &[]), + ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_SME2 - ("sme2", unstable(sym::aarch64_unstable_target_feature), &["sme"]), + ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), // FEAT_SME2p1 - ("sme2p1", unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), // FEAT_SPE - ("spe", STABLE, &[]), + ("spe", Stable, &[]), // FEAT_SSBS & FEAT_SSBS2 - ("ssbs", STABLE, &[]), + ("ssbs", Stable, &[]), // FEAT_SSVE_FP8FDOT2 - ("ssve-fp8dot2", unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), + ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), // FEAT_SSVE_FP8FDOT4 - ("ssve-fp8dot4", unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), + ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), // FEAT_SSVE_FP8FMA - ("ssve-fp8fma", unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + ("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 // @@ -387,46 +316,46 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ // 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"]), + ("sve", Stable, &["neon"]), // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) - ("sve-b16b16", unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), // FEAT_SVE2 - ("sve2", STABLE, &["sve"]), + ("sve2", Stable, &["sve"]), // FEAT_SVE_AES & FEAT_SVE_PMULL128 - ("sve2-aes", STABLE, &["sve2", "aes"]), + ("sve2-aes", Stable, &["sve2", "aes"]), // FEAT_SVE2_BitPerm - ("sve2-bitperm", STABLE, &["sve2"]), + ("sve2-bitperm", Stable, &["sve2"]), // FEAT_SVE2_SHA3 - ("sve2-sha3", STABLE, &["sve2", "sha3"]), + ("sve2-sha3", Stable, &["sve2", "sha3"]), // FEAT_SVE2_SM4 - ("sve2-sm4", STABLE, &["sve2", "sm4"]), + ("sve2-sm4", Stable, &["sve2", "sm4"]), // FEAT_SVE2p1 - ("sve2p1", unstable(sym::aarch64_unstable_target_feature), &["sve2"]), + ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]), // FEAT_TME - ("tme", STABLE, &[]), - ("v8.1a", unstable(sym::aarch64_ver_target_feature), &[ + ("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", 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"]), + ("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, &[]), + ("vh", Stable, &[]), // FEAT_WFxT - ("wfxt", unstable(sym::aarch64_unstable_target_feature), &[]), + ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]), // tidy-alphabetical-end ]; @@ -434,275 +363,260 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[ &["paca", "pacg"], // Together these represent `pauth` in LLVM ]; -const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("adx", STABLE, &[]), - ("aes", STABLE, &["sse2"]), - ("amx-bf16", unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-complex", 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-tile", unstable(sym::x86_amx_intrinsics), &[]), - ("avx", STABLE, &["sse4.2"]), - ("avx2", STABLE, &["avx"]), - ("avx512bf16", unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512bitalg", unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512bw", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512cd", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512dq", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512f", unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), - ("avx512fp16", unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]), - ("avx512ifma", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vbmi", unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512vbmi2", unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512vl", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vnni", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vp2intersect", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vpopcntdq", unstable(sym::avx512_target_feature), &["avx512f"]), - ("avxifma", unstable(sym::avx512_target_feature), &["avx2"]), - ("avxneconvert", unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnni", unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnniint16", unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnniint8", unstable(sym::avx512_target_feature), &["avx2"]), - ("bmi1", STABLE, &[]), - ("bmi2", STABLE, &[]), - ("cmpxchg16b", STABLE, &[]), - ("ermsb", unstable(sym::ermsb_target_feature), &[]), - ("f16c", STABLE, &["avx"]), - ("fma", STABLE, &["avx"]), - ("fxsr", STABLE, &[]), - ("gfni", unstable(sym::avx512_target_feature), &["sse2"]), - ("lahfsahf", unstable(sym::lahfsahf_target_feature), &[]), - ("lzcnt", STABLE, &[]), - ("movbe", STABLE, &[]), - ("pclmulqdq", STABLE, &["sse2"]), - ("popcnt", STABLE, &[]), - ("prfchw", unstable(sym::prfchw_target_feature), &[]), - ("rdrand", STABLE, &[]), - ("rdseed", STABLE, &[]), - ("rtm", unstable(sym::rtm_target_feature), &[]), - ("sha", STABLE, &["sse2"]), - ("sha512", unstable(sym::sha512_sm_x86), &["avx2"]), - ("sm3", unstable(sym::sha512_sm_x86), &["avx"]), - ("sm4", unstable(sym::sha512_sm_x86), &["avx2"]), + ("adx", Stable, &[]), + ("aes", Stable, &["sse2"]), + ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-complex", 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-tile", Unstable(sym::x86_amx_intrinsics), &[]), + ("avx", Stable, &["sse4.2"]), + ("avx2", Stable, &["avx"]), + ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]), + ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]), + ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), + ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]), + ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]), + ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]), + ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]), + ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]), + ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]), + ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]), + ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]), + ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]), + ("bmi1", Stable, &[]), + ("bmi2", Stable, &[]), + ("cmpxchg16b", Stable, &[]), + ("ermsb", Unstable(sym::ermsb_target_feature), &[]), + ("f16c", Stable, &["avx"]), + ("fma", Stable, &["avx"]), + ("fxsr", Stable, &[]), + ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]), + ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), + ("lzcnt", Stable, &[]), + ("movbe", Stable, &[]), + ("pclmulqdq", Stable, &["sse2"]), + ("popcnt", Stable, &[]), + ("prfchw", Unstable(sym::prfchw_target_feature), &[]), + ("rdrand", Stable, &[]), + ("rdseed", Stable, &[]), + ("rtm", Unstable(sym::rtm_target_feature), &[]), + ("sha", Stable, &["sse2"]), + ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]), + ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]), + ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]), ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]), - ("sse", STABLE, &[]), - ("sse2", STABLE, &["sse"]), - ("sse3", STABLE, &["sse2"]), - ("sse4.1", STABLE, &["ssse3"]), - ("sse4.2", STABLE, &["sse4.1"]), - ("sse4a", unstable(sym::sse4a_target_feature), &["sse3"]), - ("ssse3", STABLE, &["sse3"]), - ("tbm", unstable(sym::tbm_target_feature), &[]), - ("vaes", unstable(sym::avx512_target_feature), &["avx2", "aes"]), - ("vpclmulqdq", unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]), - ("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"]), + ("sse", Stable, &[]), + ("sse2", Stable, &["sse"]), + ("sse3", Stable, &["sse2"]), + ("sse4.1", Stable, &["ssse3"]), + ("sse4.2", Stable, &["sse4.1"]), + ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]), + ("ssse3", Stable, &["sse3"]), + ("tbm", Unstable(sym::tbm_target_feature), &[]), + ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]), + ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]), + ("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, StabilityUncomputed, ImpliedFeatures)] = &[ +const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("hvx", unstable(sym::hexagon_target_feature), &[]), - ("hvx-length128b", unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvx", Unstable(sym::hexagon_target_feature), &[]), + ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]), // tidy-alphabetical-end ]; -const POWERPC_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("altivec", unstable(sym::powerpc_target_feature), &[]), - ("partword-atomics", unstable(sym::powerpc_target_feature), &[]), - ("power10-vector", unstable(sym::powerpc_target_feature), &["power9-vector"]), - ("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"]), - ("quadword-atomics", unstable(sym::powerpc_target_feature), &[]), - ("vsx", unstable(sym::powerpc_target_feature), &["altivec"]), + ("altivec", Unstable(sym::powerpc_target_feature), &[]), + ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), + ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), + ("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"]), + ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), + ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), // tidy-alphabetical-end ]; -const MIPS_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +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), &[]), + ("fp64", Unstable(sym::mips_target_feature), &[]), + ("msa", Unstable(sym::mips_target_feature), &[]), + ("virt", Unstable(sym::mips_target_feature), &[]), // tidy-alphabetical-end ]; -const RISCV_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("a", STABLE, &["zaamo", "zalrsc"]), - ("c", STABLE, &[]), - ("d", unstable(sym::riscv_target_feature), &["f"]), - ("e", unstable(sym::riscv_target_feature), &[]), - ( - "f", - Stability::Unstable { - nightly_feature: sym::riscv_target_feature, - allow_toggle: |target, enable| { - match &*target.llvm_abiname { - "ilp32f" | "ilp32d" | "lp64f" | "lp64d" if !enable => { - // The ABI requires the `f` feature, so it cannot be disabled. - Err("feature is required by ABI") - } - _ => Ok(()), - } - }, - }, - &[], - ), + ("a", Stable, &["zaamo", "zalrsc"]), + ("c", Stable, &[]), + ("d", Unstable(sym::riscv_target_feature), &["f"]), + ("e", Unstable(sym::riscv_target_feature), &[]), + ("f", Unstable(sym::riscv_target_feature), &[]), ( "forced-atomics", Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" }, &[], ), - ("m", STABLE, &[]), - ("relax", unstable(sym::riscv_target_feature), &[]), - ("unaligned-scalar-mem", unstable(sym::riscv_target_feature), &[]), - ("v", unstable(sym::riscv_target_feature), &[]), - ("zaamo", unstable(sym::riscv_target_feature), &[]), - ("zabha", unstable(sym::riscv_target_feature), &["zaamo"]), - ("zalrsc", unstable(sym::riscv_target_feature), &[]), - ("zba", STABLE, &[]), - ("zbb", STABLE, &[]), - ("zbc", STABLE, &[]), - ("zbkb", STABLE, &[]), - ("zbkc", STABLE, &[]), - ("zbkx", STABLE, &[]), - ("zbs", STABLE, &[]), - ("zdinx", unstable(sym::riscv_target_feature), &["zfinx"]), - ("zfh", unstable(sym::riscv_target_feature), &["zfhmin"]), - ("zfhmin", unstable(sym::riscv_target_feature), &["f"]), - ("zfinx", unstable(sym::riscv_target_feature), &[]), - ("zhinx", unstable(sym::riscv_target_feature), &["zhinxmin"]), - ("zhinxmin", unstable(sym::riscv_target_feature), &["zfinx"]), - ("zk", STABLE, &["zkn", "zkr", "zkt"]), - ("zkn", STABLE, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), - ("zknd", STABLE, &[]), - ("zkne", STABLE, &[]), - ("zknh", STABLE, &[]), - ("zkr", STABLE, &[]), - ("zks", STABLE, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), - ("zksed", STABLE, &[]), - ("zksh", STABLE, &[]), - ("zkt", STABLE, &[]), + ("m", Stable, &[]), + ("relax", Unstable(sym::riscv_target_feature), &[]), + ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), + ("v", Unstable(sym::riscv_target_feature), &[]), + ("zaamo", Unstable(sym::riscv_target_feature), &[]), + ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), + ("zalrsc", Unstable(sym::riscv_target_feature), &[]), + ("zba", Stable, &[]), + ("zbb", Stable, &[]), + ("zbc", Stable, &[]), + ("zbkb", Stable, &[]), + ("zbkc", Stable, &[]), + ("zbkx", Stable, &[]), + ("zbs", Stable, &[]), + ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), + ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), + ("zfinx", Unstable(sym::riscv_target_feature), &[]), + ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), + ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zk", Stable, &["zkn", "zkr", "zkt"]), + ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), + ("zknd", Stable, &[]), + ("zkne", Stable, &[]), + ("zknh", Stable, &[]), + ("zkr", Stable, &[]), + ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), + ("zksed", Stable, &[]), + ("zksh", Stable, &[]), + ("zkt", Stable, &[]), // tidy-alphabetical-end ]; -const WASM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const 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, &[]), - ("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), &[]), + ("atomics", Unstable(sym::wasm_target_feature), &[]), + ("bulk-memory", Stable, &[]), + ("exception-handling", Unstable(sym::wasm_target_feature), &[]), + ("extended-const", Stable, &[]), + ("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, StabilityUncomputed, ImpliedFeatures)] = - &[("alu32", unstable(sym::bpf_target_feature), &[])]; +const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = + &[("alu32", Unstable(sym::bpf_target_feature), &[])]; -const CSKY_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("10e60", unstable(sym::csky_target_feature), &["7e10"]), - ("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"]), - ("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), &[]), + ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), + ("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"]), + ("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), &[]), + ("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 ]; -const LOONGARCH_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("d", unstable(sym::loongarch_target_feature), &["f"]), - ("f", unstable(sym::loongarch_target_feature), &[]), - ("frecipe", unstable(sym::loongarch_target_feature), &[]), - ("lasx", unstable(sym::loongarch_target_feature), &["lsx"]), - ("lbt", unstable(sym::loongarch_target_feature), &[]), - ("lsx", unstable(sym::loongarch_target_feature), &["d"]), - ("lvz", unstable(sym::loongarch_target_feature), &[]), - ("relax", unstable(sym::loongarch_target_feature), &[]), - ("ual", unstable(sym::loongarch_target_feature), &[]), + ("d", Unstable(sym::loongarch_target_feature), &["f"]), + ("f", Unstable(sym::loongarch_target_feature), &[]), + ("frecipe", Unstable(sym::loongarch_target_feature), &[]), + ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]), + ("lbt", Unstable(sym::loongarch_target_feature), &[]), + ("lsx", Unstable(sym::loongarch_target_feature), &["d"]), + ("lvz", Unstable(sym::loongarch_target_feature), &[]), + ("relax", Unstable(sym::loongarch_target_feature), &[]), + ("ual", Unstable(sym::loongarch_target_feature), &[]), // tidy-alphabetical-end ]; -const IBMZ_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("backchain", unstable(sym::s390x_target_feature), &[]), - ("vector", unstable(sym::s390x_target_feature), &[]), + ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("vector", Unstable(sym::s390x_target_feature), &[]), // tidy-alphabetical-end ]; -const SPARC_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +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), &[]), + ("leoncasa", Unstable(sym::sparc_target_feature), &[]), + ("v8plus", Unstable(sym::sparc_target_feature), &[]), + ("v9", Unstable(sym::sparc_target_feature), &[]), // tidy-alphabetical-end ]; -const M68K_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ +const 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"]), + ("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"]), + ("isa-68881", Unstable(sym::m68k_target_feature), &[]), + ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]), // tidy-alphabetical-end ]; @@ -710,7 +624,7 @@ const M68K_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[ /// 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 { +pub fn all_rust_features() -> impl Iterator { std::iter::empty() .chain(ARM_FEATURES.iter()) .chain(AARCH64_FEATURES.iter()) @@ -756,9 +670,7 @@ const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] &[(128, "lsx"), (256, "lasx")]; impl Target { - pub fn rust_target_features( - &self, - ) -> &'static [(&'static str, StabilityUncomputed, ImpliedFeatures)] { + pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] { match &*self.arch { "arm" => ARM_FEATURES, "aarch64" | "arm64ec" => AARCH64_FEATURES, From 0a8cfc2f8f1343fc99f18ca3cad8e2d11f60d7d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Dec 2024 19:08:30 +0100 Subject: [PATCH 3/7] adjust GCC backend --- compiler/rustc_codegen_gcc/src/errors.rs | 1 + compiler/rustc_codegen_gcc/src/gcc_util.rs | 196 ++++++++++++--------- 2 files changed, 116 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 56849cc861098..c896246866b9c 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> { #[diag(codegen_gcc_forbidden_ctarget_feature)] pub(crate) struct ForbiddenCTargetFeature<'a> { pub feature: &'a str, + pub enabled: &'a str, pub reason: &'a str, } diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 058a874501b26..b0fd07827d6c0 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -1,9 +1,11 @@ +use std::iter::FromIterator; + #[cfg(feature = "master")] use gccjit::Context; use rustc_codegen_ssa::codegen_attrs::check_tied_features; use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::bug; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::UnordSet; use rustc_session::Session; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; @@ -37,82 +39,128 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec return None, - Some(c @ ('+' | '-')) => c, - Some(_) => { - if diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); - } - return None; - } - }; - // Get the backend feature name, if any. - // This excludes rustc-specific features, that do not get passed down to GCC. - let feature = backend_feature_name(s)?; - // Warn against use of GCC specific feature names on the CLI. + // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones + // are disabled. + let (abi_enable, abi_disable) = sess.target.abi_required_features(); + let abi_enable_set = FxHashSet::from_iter(abi_enable.iter().copied()); + let abi_disable_set = FxHashSet::from_iter(abi_disable.iter().copied()); + + // Compute implied features + let mut all_rust_features = vec![]; + for feature in sess.opts.cg.target_feature.split(',') { + if let Some(feature) = feature.strip_prefix('+') { + all_rust_features.extend( + UnordSet::from(sess.target.implied_target_features(std::iter::once(feature))) + .to_sorted_stable_ord() + .iter() + .map(|&&s| (true, s)), + ) + } else if let Some(feature) = feature.strip_prefix('-') { + // FIXME: Why do we not remove implied features on "-" here? + // We do the equivalent above in `target_features_cfg`. + // See . + all_rust_features.push((false, feature)); + } else if !feature.is_empty() { if diagnostics { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = - known_features.iter().find_map(|&(rust_feature, _, _)| { - let gcc_features = to_gcc_features(sess, rust_feature); - if gcc_features.contains(&feature) - && !gcc_features.contains(&rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some((_, stability, _)) => { - if let Err(reason) = - stability.toggle_allowed(&sess.target, enable_disable == '+') + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); + } + } + } + // Remove features that are meant for rustc, not LLVM. + all_rust_features.retain(|(_, feature)| { + // Retain if it is not a rustc feature + !RUSTC_SPECIFIC_FEATURES.contains(feature) + }); + + // Check feature validity. + if diagnostics { + for &(enable, feature) in &all_rust_features { + let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); + match feature_state { + None => { + let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { + let gcc_features = to_gcc_features(sess, rust_feature); + if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) { - sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. (It makes little sense - // to hard-error here since we just warn about fully unknown - // features above). - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + Some(rust_feature) + } else { + None } + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + UnknownCTargetFeature { + feature, + rust_feature: PossibleFeature::Some { rust_feature }, + } + } else { + UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } + }; + sess.dcx().emit_warn(unknown_feature); + } + Some((_, stability, _)) => { + if let Err(reason) = stability.toggle_allowed() { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if stability.requires_nightly().is_some() { + // An unstable feature. Warn about using it. (It makes little sense + // to hard-error here since we just warn about fully unknown + // features above). + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); } } + } - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable_disable == '+'); + // Ensure that the features we enable/disable are compatible with the ABI. + if enable { + if abi_disable_set.contains(feature) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: "enabled", + reason: "this feature is incompatible with the target ABI", + }); + } + } else { + if abi_enable_set.contains(feature) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: "disabled", + reason: "this feature is required by the target ABI", + }); + } } - // ... otherwise though we run through `to_gcc_features` when + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable); + } + } + + // To be sure the ABI-relevant features are all in the right state, we explicitly + // (un)set them here. This means if the target spec sets those features wrong, + // we will silently correct them rather than silently producing wrong code. + // (The target sanity check tries to catch this, but we can't know which features are + // enabled in GCC by default so we can't be fully sure about that check.) + for feature in abi_enable { + all_rust_features.push((true, feature)); + } + for feature in abi_disable { + all_rust_features.push((false, feature)); + } + + // Translate this into GCC features. + let feats = all_rust_features + .iter() + .filter_map(|&(enable, feature)| { + let enable_disable = if enable { '+' } else { '-' }; + // We run through `to_gcc_features` when // passing requests down to GCC. This means that all in-language // features also work on the command line instead of having two // different names when the GCC name and the Rust name differ. @@ -146,26 +194,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Option<&str> { - // features must start with a `+` or `-`. - let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| { - bug!("target feature `{}` must begin with a `+` or `-`", s); - }); - // Rustc-specific feature requests like `+crt-static` or `-crt-static` - // are not passed down to GCC. - if RUSTC_SPECIFIC_FEATURES.contains(&feature) { - return None; - } - Some(feature) -} - // To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { + // FIXME: seems like x87 does not exist? + ("x86", "x87") => smallvec![], ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], ("x86", "pclmulqdq") => smallvec!["pclmul"], ("x86", "rdrand") => smallvec!["rdrnd"], From eb527424a5f0206a464d0968387d85636ac9d305 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Dec 2024 19:47:41 +0100 Subject: [PATCH 4/7] x86-64 hardfloat actually requires sse2 --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 18 ++++++++++++------ compiler/rustc_codegen_llvm/src/llvm_util.rs | 19 +++++++++++++------ compiler/rustc_target/src/target_features.rs | 11 ++++++++++- tests/codegen/target-feature-overrides.rs | 4 ++-- ...oat-target-feature-flag-disable-implied.rs | 10 ++++++++++ ...target-feature-flag-disable-implied.stderr | 7 +++++++ 6 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index b0fd07827d6c0..3e579d75d86ca 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -129,12 +129,18 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec { + "x86" => { // We support 2 ABIs, hardfloat (default) and softfloat. if self.has_feature("soft-float") { NOTHING @@ -762,6 +762,15 @@ impl Target { (&["x87"], &[]) } } + "x86_64" => { + // We support 2 ABIs, hardfloat (default) and softfloat. + if self.has_feature("soft-float") { + NOTHING + } else { + // Hardfloat ABI. x87 and SSE2 must be enabled. + (&["x87", "sse2"], &[]) + } + } "arm" => { // We support 2 ABIs, hardfloat (default) and softfloat. if self.has_feature("soft-float") { diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index f38a1ae72de5d..c4f9a8898a1fb 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -40,7 +40,7 @@ pub unsafe fn banana() -> u32 { // CHECK: attributes [[APPLEATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}" +// INCOMPAT-SAME: "target-features"="-avx2,-avx,+x87,+sse2,+avx,{{.*}}" // CHECK: attributes [[BANANAATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx" +// INCOMPAT-SAME: "target-features"="-avx2,-avx,+x87,+sse2" diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs new file mode 100644 index 0000000000000..3d09217327ab9 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-sse +// For now this is just a warning. +//@ build-pass +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr new file mode 100644 index 0000000000000..72b2d03fe2036 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr @@ -0,0 +1,7 @@ +warning: target feature `sse` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: 1 warning emitted + From 912b7291d0f8f477388282a04ccf085d1b3715b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Dec 2024 22:19:55 +0100 Subject: [PATCH 5/7] add ABI target features *before* -Ctarget-features --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 12 ++++++------ compiler/rustc_codegen_llvm/src/llvm_util.rs | 12 ++++++------ compiler/rustc_target/src/target_features.rs | 3 +++ tests/codegen/target-feature-overrides.rs | 8 ++++---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 3e579d75d86ca..e9dfb4e4cf44a 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -154,12 +154,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec u32 { } // CHECK: attributes [[APPLEATTRS]] -// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx,+x87,+sse2,+avx,{{.*}}" +// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}" +// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx,+avx,{{.*}}" // CHECK: attributes [[BANANAATTRS]] -// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx,+x87,+sse2" +// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}" +// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx" From 43ede97ebf7d874c9076723840c945b051b10ee2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Dec 2024 12:20:30 +0100 Subject: [PATCH 6/7] arm: use target.llvm_floatabi over soft-float target feature --- compiler/rustc_target/src/target_features.rs | 29 ++++++++++++++------ tests/codegen/tied-features-strength.rs | 8 +++--- tests/run-make/simd-ffi/rmake.rs | 2 +- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b5e30c4d5c993..142ac0ff3d31f 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_span::{Symbol, sym}; -use crate::spec::Target; +use crate::spec::{FloatAbi, Target}; /// Features that control behaviour of rustc, rather than the codegen. /// These exist globally and are not in the target-specific lists below. @@ -148,7 +148,6 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), ("rclass", Unstable(sym::arm_target_feature), &[]), ("sha2", Unstable(sym::arm_target_feature), &["neon"]), - ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]), // 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]. @@ -204,6 +203,7 @@ const AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("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_FP16 // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 @@ -758,6 +758,7 @@ impl Target { match &*self.arch { "x86" => { // We support 2 ABIs, hardfloat (default) and softfloat. + // x86 has no sane ABI indicator so we have to use the target feature. if self.has_feature("soft-float") { NOTHING } else { @@ -767,6 +768,7 @@ impl Target { } "x86_64" => { // We support 2 ABIs, hardfloat (default) and softfloat. + // x86 has no sane ABI indicator so we have to use the target feature. if self.has_feature("soft-float") { NOTHING } else { @@ -775,20 +777,27 @@ impl Target { } } "arm" => { - // We support 2 ABIs, hardfloat (default) and softfloat. - if self.has_feature("soft-float") { - NOTHING - } else { - // Hardfloat ABI. x87 must be enabled. - (&["fpregs"], &[]) + // 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. + NOTHING + } + FloatAbi::Hard => { + // Must have `fpregs` and must not have `soft-float`. + (&["fpregs"], &["soft-float"]) + } } } "aarch64" | "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. match &*self.abi { "softfloat" => { // This is not fully correct, LLVM actually doesn't let us enforce the softfloat // ABI properly... see . - // FIXME: should be forbid "neon" here? But that would be a breaking change. + // FIXME: should we forbid "neon" here? But that would be a breaking change. NOTHING } _ => { @@ -799,6 +808,8 @@ impl Target { } } "riscv32" | "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. diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 4d96a7cde7812..6daa5cd7d5e26 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -1,5 +1,5 @@ // ignore-tidy-linelength -//@ revisions: ENABLE_SVE DISABLE_SVE ENABLE_NEON +//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 @@ -13,9 +13,9 @@ //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 // DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" } -// The DISABLE_NEON is disabled since neon is a required target feature for this targt, it cannot be disabled. -// it would have: compile-flags: -C target-feature=-neon -Copt-level=0 -// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" } +//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 +// `neon` and `fp-armv8` get enabled as target base features, but then disabled again at the end of the list. +// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}},-neon,-fp-armv8{{(,\+fpmr)?}}" } //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" } diff --git a/tests/run-make/simd-ffi/rmake.rs b/tests/run-make/simd-ffi/rmake.rs index 04990c8bdf437..ef71dfa4c3021 100644 --- a/tests/run-make/simd-ffi/rmake.rs +++ b/tests/run-make/simd-ffi/rmake.rs @@ -56,7 +56,7 @@ fn main() { .target(&target) .emit("llvm-ir,asm") .input("simd.rs") - .arg("-Ctarget-feature=+neon,+sse") + .arg("-Ctarget-feature=-soft-float,+neon,+sse") .arg(&format!("-Cextra-filename=-{target}")) .run(); } From 2e64b5352be9ec8b2a7b956c2be108394b85f4b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jan 2025 10:34:33 +0100 Subject: [PATCH 7/7] add dedicated type for ABI target feature constraints --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 19 +++++++------ compiler/rustc_codegen_llvm/src/llvm_util.rs | 17 ++++++----- .../rustc_codegen_ssa/src/target_features.rs | 4 +-- compiler/rustc_target/src/spec/mod.rs | 8 +++--- compiler/rustc_target/src/target_features.rs | 28 ++++++++++++------- 5 files changed, 45 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index e9dfb4e4cf44a..1994a2a3c5373 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -47,9 +47,9 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec Vec Vec Vec &'static [(&'static str, Stability, ImpliedFeatures)] { match &*self.arch { @@ -749,8 +757,8 @@ impl 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) -> (&'static [&'static str], &'static [&'static str]) { - const NOTHING: (&'static [&'static str], &'static [&'static str]) = (&[], &[]); + 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 @@ -763,7 +771,7 @@ impl Target { NOTHING } else { // Hardfloat ABI. x87 must be enabled. - (&["x87"], &[]) + FeatureConstraints { required: &["x87"], incompatible: &[] } } } "x86_64" => { @@ -773,7 +781,7 @@ impl Target { NOTHING } else { // Hardfloat ABI. x87 and SSE2 must be enabled. - (&["x87", "sse2"], &[]) + FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] } } } "arm" => { @@ -786,7 +794,7 @@ impl Target { } FloatAbi::Hard => { // Must have `fpregs` and must not have `soft-float`. - (&["fpregs"], &["soft-float"]) + FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] } } } } @@ -803,7 +811,7 @@ impl Target { _ => { // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. // These are Rust feature names and we use "neon" to control both of them. - (&["neon"], &[]) + FeatureConstraints { required: &["neon"], incompatible: &[] } } } } @@ -813,15 +821,15 @@ impl Target { match &*self.llvm_abiname { "ilp32d" | "lp64d" => { // Requires d (which implies f), incompatible with e. - (&["d"], &["e"]) + FeatureConstraints { required: &["d"], incompatible: &["e"] } } "ilp32f" | "lp64f" => { // Requires f, incompatible with e. - (&["f"], &["e"]) + FeatureConstraints { required: &["f"], incompatible: &["e"] } } "ilp32" | "lp64" => { // Requires nothing, incompatible with e. - (&[], &["e"]) + FeatureConstraints { required: &[], incompatible: &["e"] } } "ilp32e" => { // ilp32e is documented to be incompatible with features that need aligned @@ -832,7 +840,7 @@ impl Target { // 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. - (&[], &["d"]) + FeatureConstraints { required: &[], incompatible: &["d"] } } "lp64e" => { // As above, `e` is not required.