From 74653b61a67ae7db9f77ea1e09e65e40686c9058 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 26 Jul 2024 00:05:20 -0400 Subject: [PATCH] Add implied target features to target_feature attribute --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 16 ----- .../rustc_codegen_ssa/src/target_features.rs | 40 ++++++++++--- compiler/rustc_middle/src/query/mod.rs | 6 ++ compiler/rustc_target/src/target_features.rs | 58 +++++++++++++++++-- tests/ui/target-feature/implied-features.rs | 24 ++++++++ 5 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 tests/ui/target-feature/implied-features.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index af8a9be1ccbfd..dc21b92a95f76 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -646,22 +646,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec, which didn't make - // it into a released version of LLVM yet. - // - // This doesn't use the "implicit target feature" system because it is only - // used for function attributes in other targets, which fixes this bug as - // well on the function attribute level. - if sess.target.families.contains(&"wasm".into()) { - if features.iter().any(|f| f == "+relaxed-simd") - && !features.iter().any(|f| f == "+simd128") - { - features.push("+simd128".into()); - } - } - if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { sess.dcx().emit_err(TargetFeatureDisableOrEnable { features: f, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 127244a34f8f0..1bf842b53a3c5 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,7 +1,7 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; @@ -30,6 +30,7 @@ pub fn from_target_feature( .emit(); }; let rust_features = tcx.features(); + let mut added_target_features = Vec::new(); for item in list { // Only `enable = ...` is accepted in the meta-item list. if !item.has_name(sym::enable) { @@ -44,7 +45,7 @@ pub fn from_target_feature( }; // We allow comma separation to enable multiple features. - target_features.extend(value.as_str().split(',').filter_map(|feature| { + added_target_features.extend(value.as_str().split(',').filter_map(|feature| { let Some(feature_gate) = supported_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); @@ -98,13 +99,12 @@ pub fn from_target_feature( })); } - for (feature, requires) in tcx.sess.target.implicit_target_features() { - if target_features.iter().any(|f| f.as_str() == *feature) - && !target_features.iter().any(|f| f.as_str() == *requires) - { - target_features.push(Symbol::intern(requires)); - } + // Add implied features + for feature in added_target_features.iter() { + target_features + .extend(tcx.implied_target_features(*feature).clone().into_sorted_stable_ord()); } + target_features.extend(added_target_features) } /// Computes the set of target features used in a function for the purposes of @@ -162,6 +162,28 @@ pub(crate) fn provide(providers: &mut Providers) { .collect() } }, + implied_target_features: |tcx, feature| { + let implied_features = tcx + .sess + .target + .implied_target_features() + .iter() + .map(|(f, i)| (Symbol::intern(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 = UnordSet::new(); + let mut new_features = vec![feature]; + while let Some(new_feature) = new_features.pop() { + if features.insert(new_feature) { + if let Some(implied_features) = implied_features.get(&new_feature) { + new_features.extend(implied_features.iter().copied().map(Symbol::intern)) + } + } + } + features + }, asm_target_features, ..*providers } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c22c2e985abba..b6a2943265034 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2183,6 +2183,12 @@ rustc_queries! { desc { "looking up supported target features" } } + query implied_target_features(feature: Symbol) -> &'tcx UnordSet { + arena_cache + eval_always + desc { "looking up implied target features" } + } + query features_query(_: ()) -> &'tcx rustc_feature::Features { feedable desc { "looking up enabled feature gates" } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 4e2617c467949..5b79495831a34 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -339,8 +339,6 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-end ]; -const WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")]; - const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))]; const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[ @@ -411,6 +409,54 @@ const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-end ]; +const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("aes", &["sse2"]), + ("avx", &["sse4.2"]), + ("avx2", &["avx"]), + ("f16c", &["avx"]), + ("fma", &["avx"]), + ("pclmulqdq", &["sse2"]), + ("sha", &["sse2"]), + ("sse2", &["sse"]), + ("sse3", &["sse2"]), + ("sse4.1", &["ssse3"]), + ("sse4.2", &["sse4.1"]), + ("ssse3", &["sse3"]), + // tidy-alphabetical-end +]; + +const AARCH64_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("aes", &["neon"]), + ("f32mm", &["sve"]), + ("f64mm", &["sve"]), + ("fcma", &["neon"]), + ("fhm", &["fp16"]), + ("fp16", &["neon"]), + ("jsconv", &["neon"]), + ("rcpc2", &["rcpc"]), + ("sha2", &["neon"]), + ("sha3", &["sha2"]), + ("sm4", &["neon"]), + ("sve", &["fp16"]), + ("sve2", &["sve"]), + ("sve2-aes", &["sve2", "aes"]), + ("sve2-bitperm", &["sve2"]), + ("sve2-sha3", &["sve2", "sha3"]), + ("sve2-sm4", &["sve2", "sm4"]), + // tidy-alphabetical-end +]; + +const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("zb", &["zba", "zbc", "zbs"]), + ("zk", &["zkn", "zkr", "zks", "zkt", "zbkb", "zbkc", "zkbx"]), + ("zkn", &["zknd", "zkne", "zknh", "zbkb", "zbkc", "zkbx"]), + ("zks", &["zksed", "zksh", "zbkb", "zbkc", "zkbx"]), + // tidy-alphabetical-end +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -458,11 +504,11 @@ impl super::spec::Target { } } - /// Returns a list of target features. Each items first target feature - /// implicitly enables the second one. - pub fn implicit_target_features(&self) -> &'static [(&'static str, &'static str)] { + pub fn implied_target_features(&self) -> &'static [(&'static str, &'static [&'static str])] { match &*self.arch { - "wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES, + "aarch4" => AARCH64_IMPLIED_FEATURES, + "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES, + "x86" | "x86_64" => X86_IMPLIED_FEATURES, _ => &[], } } diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs new file mode 100644 index 0000000000000..c6d9ba78c21e6 --- /dev/null +++ b/tests/ui/target-feature/implied-features.rs @@ -0,0 +1,24 @@ +//@ only-x86_64 +//@ run-pass +#![feature(target_feature_11)] +#![allow(dead_code)] + +#[target_feature(enable = "ssse3")] +fn call_ssse3() {} + +#[target_feature(enable = "avx")] +fn call_avx() {} + +#[target_feature(enable = "avx2")] +fn test_avx2() { + call_ssse3(); + call_avx(); +} + +#[target_feature(enable = "fma")] +fn test_fma() { + call_ssse3(); + call_avx(); +} + +fn main() {}