From 90521399b4bfa889916cb62e2394b69f295e22cf Mon Sep 17 00:00:00 2001
From: daxpedda <daxpedda@gmail.com>
Date: Wed, 21 Feb 2024 23:12:19 +0100
Subject: [PATCH 1/2] Stabilize Wasm relaxed SIMD

---
 compiler/rustc_target/src/target_features.rs | 2 +-
 tests/ui/target-feature/wasm-relaxed-simd.rs | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/target-feature/wasm-relaxed-simd.rs

diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index e52f2fc06df06..843e28b17b0b5 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -333,7 +333,7 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     ("mutable-globals", Stable),
     ("nontrapping-fptoint", Stable),
     ("reference-types", Unstable(sym::wasm_target_feature)),
-    ("relaxed-simd", Unstable(sym::wasm_target_feature)),
+    ("relaxed-simd", Stable),
     ("sign-ext", Stable),
     ("simd128", Stable),
     // tidy-alphabetical-end
diff --git a/tests/ui/target-feature/wasm-relaxed-simd.rs b/tests/ui/target-feature/wasm-relaxed-simd.rs
new file mode 100644
index 0000000000000..3c80647fdfe17
--- /dev/null
+++ b/tests/ui/target-feature/wasm-relaxed-simd.rs
@@ -0,0 +1,9 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: -Ctarget-feature=+relaxed-simd,+simd128 --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}

From 80b74d397fffc9deaafd2b44552ba3a9107b4d5b Mon Sep 17 00:00:00 2001
From: daxpedda <daxpedda@gmail.com>
Date: Sat, 13 Jul 2024 00:10:33 +0200
Subject: [PATCH 2/2] Implement a implicit target feature mechanism

---
 compiler/rustc_codegen_llvm/src/llvm_util.rs     | 16 ++++++++++++++++
 .../rustc_codegen_ssa/src/target_features.rs     |  8 ++++++++
 compiler/rustc_target/src/target_features.rs     | 11 +++++++++++
 tests/ui/target-feature/implicit-features-cli.rs |  9 +++++++++
 tests/ui/target-feature/implicit-features.rs     | 10 ++++++++++
 tests/ui/target-feature/wasm-relaxed-simd.rs     |  2 +-
 6 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/target-feature/implicit-features-cli.rs
 create mode 100644 tests/ui/target-feature/implicit-features.rs

diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index dc21b92a95f76..af8a9be1ccbfd 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -646,6 +646,22 @@ 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 b52e6259944d7..127244a34f8f0 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -97,6 +97,14 @@ pub fn from_target_feature(
             Some(Symbol::intern(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));
+        }
+    }
 }
 
 /// Computes the set of target features used in a function for the purposes of
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 843e28b17b0b5..4e2617c467949 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -339,6 +339,8 @@ 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)] = &[
@@ -455,4 +457,13 @@ 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)] {
+        match &*self.arch {
+            "wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES,
+            _ => &[],
+        }
+    }
 }
diff --git a/tests/ui/target-feature/implicit-features-cli.rs b/tests/ui/target-feature/implicit-features-cli.rs
new file mode 100644
index 0000000000000..34e7c3d506659
--- /dev/null
+++ b/tests/ui/target-feature/implicit-features-cli.rs
@@ -0,0 +1,9 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}
diff --git a/tests/ui/target-feature/implicit-features.rs b/tests/ui/target-feature/implicit-features.rs
new file mode 100644
index 0000000000000..b9c48b0822d53
--- /dev/null
+++ b/tests/ui/target-feature/implicit-features.rs
@@ -0,0 +1,10 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+#[target_feature(enable = "relaxed-simd")]
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}
diff --git a/tests/ui/target-feature/wasm-relaxed-simd.rs b/tests/ui/target-feature/wasm-relaxed-simd.rs
index 3c80647fdfe17..34e7c3d506659 100644
--- a/tests/ui/target-feature/wasm-relaxed-simd.rs
+++ b/tests/ui/target-feature/wasm-relaxed-simd.rs
@@ -1,5 +1,5 @@
 //@ only-wasm32-wasip1
-//@ compile-flags: -Ctarget-feature=+relaxed-simd,+simd128 --crate-type=lib
+//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
 //@ build-pass
 
 use std::arch::wasm32::*;