about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2024-07-26 00:05:20 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2024-08-07 00:41:48 -0400
commit74653b61a67ae7db9f77ea1e09e65e40686c9058 (patch)
treec589eeb5a45e37481ce4a98efd90b0b09654ebe3
parent6696447f784a888446d13bb400a8d507a68331c9 (diff)
downloadrust-74653b61a67ae7db9f77ea1e09e65e40686c9058.tar.gz
rust-74653b61a67ae7db9f77ea1e09e65e40686c9058.zip
Add implied target features to target_feature attribute
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs40
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_target/src/target_features.rs58
-rw-r--r--tests/ui/target-feature/implied-features.rs24
5 files changed, 113 insertions, 31 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index af8a9be1ccb..dc21b92a95f 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<Str
         }
     }
 
-    // This is a workaround for a LLVM bug that doesn't implicitly enable
-    // `simd128` when `relaxed-simd` is.
-    // See <https://github.com/llvm/llvm-project/pull/99803>, 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 127244a34f8..1bf842b53a3 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::<FxHashMap<_, _>>();
+
+            // implied target features have their own implied target features, so we traverse the
+            // map until there are no more features to add
+            let mut features = 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 c22c2e985ab..b6a29432650 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<Symbol> {
+        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 4e2617c4679..5b79495831a 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 00000000000..c6d9ba78c21
--- /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() {}