diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 4b324740a1f..3ce594b945a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -188,8 +188,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
         ("x86", "avx512gfni") => smallvec!["gfni"],
         ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
         ("aarch64", "fp") => smallvec!["fp-armv8"],
-        ("aarch64", "fp16") => smallvec!["fullfp16"],
-        ("aarch64", "fhm") => smallvec!["fp16fml"],
         ("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
         ("aarch64", "dpb") => smallvec!["ccpp"],
         ("aarch64", "dpb2") => smallvec!["ccdp"],
@@ -198,6 +196,19 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
         ("aarch64", "pmuv3") => smallvec!["perfmon"],
         ("aarch64", "paca") => smallvec!["pauth"],
         ("aarch64", "pacg") => smallvec!["pauth"],
+        // Rust ties fp and neon together. In LLVM neon implicitly enables fp,
+        // but we manually enable neon when a feature only implicitly enables fp
+        ("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
+        ("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
+        ("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
+        ("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
+        ("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
+        ("aarch64", "sve") => smallvec!["sve", "neon"],
+        ("aarch64", "sve2") => smallvec!["sve2", "neon"],
+        ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
+        ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
+        ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
+        ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
         (_, s) => smallvec![s],
     }
 }
@@ -490,7 +501,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
             return SmallVec::<[_; 2]>::new();
         }
-        // ... otherwise though we run through `to_llvm_feature when
+        // ... otherwise though 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
         // different names when the LLVM name and the Rust name differ.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index df011d6ca5f..f37c6751381 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -44,105 +44,108 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
 
 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     // FEAT_AdvSimd
-    ("neon", Some(sym::aarch64_target_feature)),
+    ("neon", None),
     // FEAT_FP
-    ("fp", Some(sym::aarch64_target_feature)),
+    ("fp", None),
     // FEAT_FP16
-    ("fp16", Some(sym::aarch64_target_feature)),
+    ("fp16", None),
     // FEAT_SVE
-    ("sve", Some(sym::aarch64_target_feature)),
+    ("sve", None),
     // FEAT_CRC
-    ("crc", Some(sym::aarch64_target_feature)),
+    ("crc", None),
     // FEAT_RAS
-    ("ras", Some(sym::aarch64_target_feature)),
+    ("ras", None),
     // FEAT_LSE
-    ("lse", Some(sym::aarch64_target_feature)),
+    ("lse", None),
     // FEAT_RDM
-    ("rdm", Some(sym::aarch64_target_feature)),
+    ("rdm", None),
     // FEAT_RCPC
-    ("rcpc", Some(sym::aarch64_target_feature)),
+    ("rcpc", None),
     // FEAT_RCPC2
-    ("rcpc2", Some(sym::aarch64_target_feature)),
+    ("rcpc2", None),
     // FEAT_DotProd
-    ("dotprod", Some(sym::aarch64_target_feature)),
+    ("dotprod", None),
     // FEAT_TME
-    ("tme", Some(sym::aarch64_target_feature)),
+    ("tme", None),
     // FEAT_FHM
-    ("fhm", Some(sym::aarch64_target_feature)),
+    ("fhm", None),
     // FEAT_DIT
-    ("dit", Some(sym::aarch64_target_feature)),
+    ("dit", None),
     // FEAT_FLAGM
-    ("flagm", Some(sym::aarch64_target_feature)),
+    ("flagm", None),
     // FEAT_SSBS
-    ("ssbs", Some(sym::aarch64_target_feature)),
+    ("ssbs", None),
     // FEAT_SB
-    ("sb", Some(sym::aarch64_target_feature)),
+    ("sb", None),
     // FEAT_PAUTH (address authentication)
-    ("paca", Some(sym::aarch64_target_feature)),
+    ("paca", None),
     // FEAT_PAUTH (generic authentication)
-    ("pacg", Some(sym::aarch64_target_feature)),
+    ("pacg", None),
     // FEAT_DPB
-    ("dpb", Some(sym::aarch64_target_feature)),
+    ("dpb", None),
     // FEAT_DPB2
-    ("dpb2", Some(sym::aarch64_target_feature)),
+    ("dpb2", None),
     // FEAT_SVE2
-    ("sve2", Some(sym::aarch64_target_feature)),
+    ("sve2", None),
     // FEAT_SVE2_AES
-    ("sve2-aes", Some(sym::aarch64_target_feature)),
+    ("sve2-aes", None),
     // FEAT_SVE2_SM4
-    ("sve2-sm4", Some(sym::aarch64_target_feature)),
+    ("sve2-sm4", None),
     // FEAT_SVE2_SHA3
-    ("sve2-sha3", Some(sym::aarch64_target_feature)),
+    ("sve2-sha3", None),
     // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", Some(sym::aarch64_target_feature)),
+    ("sve2-bitperm", None),
     // FEAT_FRINTTS
-    ("frintts", Some(sym::aarch64_target_feature)),
+    ("frintts", None),
     // FEAT_I8MM
-    ("i8mm", Some(sym::aarch64_target_feature)),
+    ("i8mm", None),
     // FEAT_F32MM
-    ("f32mm", Some(sym::aarch64_target_feature)),
+    ("f32mm", None),
     // FEAT_F64MM
-    ("f64mm", Some(sym::aarch64_target_feature)),
+    ("f64mm", None),
     // FEAT_BF16
-    ("bf16", Some(sym::aarch64_target_feature)),
+    ("bf16", None),
     // FEAT_RAND
-    ("rand", Some(sym::aarch64_target_feature)),
+    ("rand", None),
     // FEAT_BTI
-    ("bti", Some(sym::aarch64_target_feature)),
+    ("bti", None),
     // FEAT_MTE
-    ("mte", Some(sym::aarch64_target_feature)),
+    ("mte", None),
     // FEAT_JSCVT
-    ("jsconv", Some(sym::aarch64_target_feature)),
+    ("jsconv", None),
     // FEAT_FCMA
-    ("fcma", Some(sym::aarch64_target_feature)),
+    ("fcma", None),
     // FEAT_AES
-    ("aes", Some(sym::aarch64_target_feature)),
+    ("aes", None),
     // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", Some(sym::aarch64_target_feature)),
+    ("sha2", None),
     // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", Some(sym::aarch64_target_feature)),
+    ("sha3", None),
     // FEAT_SM3 & FEAT_SM4
-    ("sm4", Some(sym::aarch64_target_feature)),
+    ("sm4", None),
     // FEAT_PAN
-    ("pan", Some(sym::aarch64_target_feature)),
+    ("pan", None),
     // FEAT_LOR
-    ("lor", Some(sym::aarch64_target_feature)),
+    ("lor", None),
     // FEAT_VHE
-    ("vh", Some(sym::aarch64_target_feature)),
+    ("vh", None),
     // FEAT_PMUv3
-    ("pmuv3", Some(sym::aarch64_target_feature)),
+    ("pmuv3", None),
     // FEAT_SPE
-    ("spe", Some(sym::aarch64_target_feature)),
-    ("v8.1a", Some(sym::aarch64_target_feature)),
-    ("v8.2a", Some(sym::aarch64_target_feature)),
-    ("v8.3a", Some(sym::aarch64_target_feature)),
-    ("v8.4a", Some(sym::aarch64_target_feature)),
-    ("v8.5a", Some(sym::aarch64_target_feature)),
-    ("v8.6a", Some(sym::aarch64_target_feature)),
-    ("v8.7a", Some(sym::aarch64_target_feature)),
+    ("spe", None),
+    ("v8.1a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.2a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.3a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.4a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.5a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.6a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.7a", Some(sym::aarch64_ver_target_feature)),
 ];
 
-const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[
+    &["fp", "neon"],   // Silicon always has both, so avoid needless complications
+    &["paca", "pacg"], // Together these represent `pauth` in LLVM
+];
 
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("adx", Some(sym::adx_target_feature)),
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index fc2ac75d609..e49f40ff1a1 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -46,6 +46,8 @@ declare_features! (
     // feature-group-start: accepted features
     // -------------------------------------------------------------------------
 
+    /// Allows `#[target_feature(...)]` on aarch64 platforms
+    (accepted, aarch64_target_feature, "1.61.0", Some(44839), None),
     /// Allows the sysV64 ABI to be specified on all platforms
     /// instead of just the platforms on which it is the C ABI.
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ccd296c3da1..d9748b19e13 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -243,7 +243,7 @@ declare_features! (
     // FIXME: Document these and merge with the list below.
 
     // Unstable `#[target_feature]` directives.
-    (active, aarch64_target_feature, "1.27.0", Some(44839), None),
+    (active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
     (active, adx_target_feature, "1.32.0", Some(44839), None),
     (active, arm_target_feature, "1.27.0", Some(44839), None),
     (active, avx512_target_feature, "1.27.0", Some(44839), None),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 967eb3cc22a..4dd1c3fed6b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -278,6 +278,7 @@ symbols! {
         _task_context,
         a32,
         aarch64_target_feature,
+        aarch64_ver_target_feature,
         abi,
         abi_amdgpu_kernel,
         abi_avr_interrupt,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index cabdcdc214b..16e72d0c2c5 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2680,7 +2680,6 @@ fn from_target_feature(
             // Only allow features whose feature gates have been enabled.
             let allowed = match feature_gate.as_ref().copied() {
                 Some(sym::arm_target_feature) => rust_features.arm_target_feature,
-                Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
                 Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
                 Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
                 Some(sym::mips_target_feature) => rust_features.mips_target_feature,
@@ -2696,6 +2695,7 @@ fn from_target_feature(
                 Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
                 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
                 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
+                Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1ab7481b7ba..e1be20c2179 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -206,7 +206,7 @@
 #![feature(asm_const)]
 //
 // Target features:
-#![feature(aarch64_target_feature)]
+#![cfg_attr(bootstrap, feature(aarch64_target_feature))]
 #![feature(adx_target_feature)]
 #![feature(arm_target_feature)]
 #![feature(avx512_target_feature)]
diff --git a/src/test/run-make-fulldeps/simd-ffi/Makefile b/src/test/run-make-fulldeps/simd-ffi/Makefile
index e9c974a0137..38f2fcd18c5 100644
--- a/src/test/run-make-fulldeps/simd-ffi/Makefile
+++ b/src/test/run-make-fulldeps/simd-ffi/Makefile
@@ -41,7 +41,7 @@ define MK_TARGETS
 # now.
 $(1): simd.rs
 	$$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \
-                -C target-feature='+neon,+sse2' -C extra-filename=-$(1)
+                -C target-feature='+fp,+neon,+sse2' -C extra-filename=-$(1)
 endef
 
 $(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx))))
diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs
index 7cdf404242d..2382c98f8f1 100644
--- a/src/test/ui/target-feature/gate.rs
+++ b/src/test/ui/target-feature/gate.rs
@@ -16,7 +16,6 @@
 // gate-test-avx512_target_feature
 // gate-test-tbm_target_feature
 // gate-test-arm_target_feature
-// gate-test-aarch64_target_feature
 // gate-test-hexagon_target_feature
 // gate-test-mips_target_feature
 // gate-test-wasm_target_feature
@@ -28,6 +27,7 @@
 // gate-test-riscv_target_feature
 // gate-test-ermsb_target_feature
 // gate-test-bpf_target_feature
+// gate-test-aarch64_ver_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
diff --git a/src/test/ui/target-feature/tied-features.rs b/src/test/ui/target-feature/tied-features.rs
index 01353e9f70c..048777cb3ba 100644
--- a/src/test/ui/target-feature/tied-features.rs
+++ b/src/test/ui/target-feature/tied-features.rs
@@ -1,7 +1,7 @@
 // build-fail
 // compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
 // needs-llvm-components: aarch64
-#![feature(aarch64_target_feature, target_feature_11)]
+#![cfg_attr(bootstrap, feature(aarch64_target_feature))]
 #![feature(no_core, lang_items)]
 #![no_core]