diff --git a/Cargo.lock b/Cargo.lock
index 7cd07e38472..28b922cf913 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -678,9 +678,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.49"
+version = "0.1.52"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2"
+checksum = "b6591c2442ee984e2b264638a8b5e7ae44fd47b32d28e3a08e2e9c3cdb0c2fb0"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -1028,9 +1028,9 @@ dependencies = [
 
 [[package]]
 name = "dlmalloc"
-version = "0.2.1"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254"
+checksum = "a6fe28e0bf9357092740362502f5cc7955d8dc125ebda71dec72336c2e15c62e"
 dependencies = [
  "compiler_builtins",
  "libc",
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index f128f769580..02096f4abfa 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -320,7 +320,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
                 InlineAsmArch::S390x => {}
                 InlineAsmArch::SpirV => {}
-                InlineAsmArch::Wasm32 => {}
+                InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
                 InlineAsmArch::Bpf => {}
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 6c74163fb49..ff88302bf7a 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -769,7 +769,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // we like. To ensure that LLVM picks the right instruction we choose
         // the raw wasm intrinsic functions which avoid LLVM inserting all the
         // other control flow automatically.
-        if self.sess().target.arch == "wasm32" {
+        if self.sess().target.is_like_wasm {
             let src_ty = self.cx.val_ty(val);
             if self.cx.type_kind(src_ty) != TypeKind::Vector {
                 let float_width = self.cx.float_width(src_ty);
@@ -791,7 +791,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
     fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         // see `fptoui` above for why wasm is different here
-        if self.sess().target.arch == "wasm32" {
+        if self.sess().target.is_like_wasm {
             let src_ty = self.cx.val_ty(val);
             if self.cx.type_kind(src_ty) != TypeKind::Vector {
                 let float_width = self.cx.float_width(src_ty);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 1afa6f02836..b154ced42f0 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -490,7 +490,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
 
             // Wasm statics with custom link sections get special treatment as they
             // go into custom sections of the wasm executable.
-            if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+            if self.tcx.sess.target.is_like_wasm {
                 if let Some(section) = attrs.link_section {
                     let section = llvm::LLVMMDStringInContext(
                         self.llcx,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c3e7e7169a9..3393c9baa28 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -75,7 +75,9 @@ unsafe fn configure_llvm(sess: &Session) {
         if sess.print_llvm_passes() {
             add("-debug-pass=Structure", false);
         }
-        if !sess.opts.debugging_opts.no_generate_arange_section {
+        if sess.target.generate_arange_section
+            && !sess.opts.debugging_opts.no_generate_arange_section
+        {
             add("-generate-arange-section", false);
         }
 
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 99699c50df5..bff13246521 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -189,6 +189,7 @@ pub enum InlineAsmArch {
     S390x,
     SpirV,
     Wasm32,
+    Wasm64,
     Bpf,
 }
 
@@ -212,6 +213,7 @@ impl FromStr for InlineAsmArch {
             "s390x" => Ok(Self::S390x),
             "spirv" => Ok(Self::SpirV),
             "wasm32" => Ok(Self::Wasm32),
+            "wasm64" => Ok(Self::Wasm64),
             "bpf" => Ok(Self::Bpf),
             _ => Err(()),
         }
@@ -318,7 +320,7 @@ impl InlineAsmReg {
             InlineAsmArch::SpirV => {
                 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
-            InlineAsmArch::Wasm32 => {
+            InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
                 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
             InlineAsmArch::Bpf => {
@@ -529,7 +531,9 @@ impl InlineAsmRegClass {
             }
             InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
-            InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
+                Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
+            }
             InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
         })
     }
@@ -725,7 +729,7 @@ pub fn allocatable_registers(
             spirv::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
-        InlineAsmArch::Wasm32 => {
+        InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
             let mut map = wasm::regclass_map();
             wasm::fill_reg_map(arch, has_feature, target, &mut map);
             map
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 69b90bf10fe..0771f998535 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1357,6 +1357,9 @@ pub struct TargetOptions {
 
     /// Minimum number of bits in #[repr(C)] enum. Defaults to 32.
     pub c_enum_min_bits: u64,
+
+    /// Whether or not the DWARF `.debug_aranges` section should be generated.
+    pub generate_arange_section: bool,
 }
 
 impl Default for TargetOptions {
@@ -1462,6 +1465,7 @@ impl Default for TargetOptions {
             supported_sanitizers: SanitizerSet::empty(),
             default_adjusted_cabi: None,
             c_enum_min_bits: 32,
+            generate_arange_section: true,
         }
     }
 }
@@ -2047,6 +2051,7 @@ impl Target {
         key!(supported_sanitizers, SanitizerSet)?;
         key!(default_adjusted_cabi, Option<Abi>)?;
         key!(c_enum_min_bits, u64);
+        key!(generate_arange_section, bool);
 
         if base.is_builtin {
             // This can cause unfortunate ICEs later down the line.
@@ -2286,6 +2291,7 @@ impl ToJson for Target {
         target_option_val!(split_debuginfo);
         target_option_val!(supported_sanitizers);
         target_option_val!(c_enum_min_bits);
+        target_option_val!(generate_arange_section);
 
         if let Some(abi) = self.default_adjusted_cabi {
             d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 86b1a755233..69a404ec564 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -37,7 +37,7 @@ pub fn target() -> Target {
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
-        families: vec!["unix".to_string()],
+        families: vec!["unix".to_string(), "wasm".to_string()],
         ..options
     };
     Target {
diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
index fb6526c0e72..6b7dfbb87d2 100644
--- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
@@ -23,11 +23,15 @@ pub fn target() -> Target {
     // For now this target just never has an entry symbol no matter the output
     // type, so unconditionally pass this.
     clang_args.push("-Wl,--no-entry".to_string());
-    options
-        .pre_link_args
-        .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm))
-        .unwrap()
-        .push("--no-entry".to_string());
+
+    let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap();
+    lld_args.push("--no-entry".to_string());
+    lld_args.push("-mwasm64".to_string());
+
+    // Any engine that implements wasm64 will surely implement the rest of these
+    // features since they were all merged into the official spec by the time
+    // wasm64 was designed.
+    options.features = "+bulk-memory,+mutable-globals,+sign-ext,+nontrapping-fptoint".to_string();
 
     Target {
         llvm_target: "wasm64-unknown-unknown".to_string(),
diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs
index 4c954a1e567..24e9c625169 100644
--- a/compiler/rustc_target/src/spec/wasm_base.rs
+++ b/compiler/rustc_target/src/spec/wasm_base.rs
@@ -128,6 +128,12 @@ pub fn options() -> TargetOptions {
         // gdb scripts don't work on wasm blobs
         emit_debug_gdb_scripts: false,
 
+        // There's more discussion of this at
+        // https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is
+        // that this isn't useful for wasm and has tricky issues with
+        // representation, so this is disabled.
+        generate_arange_section: false,
+
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index d19e99606bc..e7fba3a70ff 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -536,8 +536,8 @@ fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
 }
 
 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
-    // Only restricted on wasm32 target for now
-    if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+    // Only restricted on wasm target for now
+    if !tcx.sess.target.is_like_wasm {
         return;
     }
 
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs
index b208ddd4b27..9c4cf89b6bc 100644
--- a/library/core/src/ffi.rs
+++ b/library/core/src/ffi.rs
@@ -62,7 +62,7 @@ impl fmt::Debug for c_void {
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
-    target_arch = "wasm32",
+    target_family = "wasm",
     target_arch = "asmjs",
     windows
 ))]
@@ -85,7 +85,7 @@ pub struct VaListImpl<'f> {
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
-    target_arch = "wasm32",
+    target_family = "wasm",
     target_arch = "asmjs",
     windows
 ))]
@@ -185,7 +185,7 @@ pub struct VaList<'a, 'f: 'a> {
             not(target_arch = "x86_64")
         ),
         all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
-        target_arch = "wasm32",
+        target_family = "wasm",
         target_arch = "asmjs",
         windows
     ))]
@@ -194,7 +194,7 @@ pub struct VaList<'a, 'f: 'a> {
     #[cfg(all(
         any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
         any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
-        not(target_arch = "wasm32"),
+        not(target_family = "wasm"),
         not(target_arch = "asmjs"),
         not(windows)
     ))]
@@ -206,7 +206,7 @@ pub struct VaList<'a, 'f: 'a> {
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
-    target_arch = "wasm32",
+    target_family = "wasm",
     target_arch = "asmjs",
     windows
 ))]
@@ -227,7 +227,7 @@ impl<'f> VaListImpl<'f> {
 #[cfg(all(
     any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
     any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
-    not(target_arch = "wasm32"),
+    not(target_family = "wasm"),
     not(target_arch = "asmjs"),
     not(windows)
 ))]
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index ac75ce7f221..dec5e0b2123 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -117,7 +117,7 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe
 pub mod personalities {
     #[rustc_std_internal_symbol]
     #[cfg(not(any(
-        all(target_arch = "wasm32", not(target_os = "emscripten"),),
+        all(target_family = "wasm", not(target_os = "emscripten")),
         all(target_os = "windows", target_env = "gnu", target_arch = "x86_64",),
     )))]
     pub extern "C" fn rust_eh_personality() {}
diff --git a/library/panic_unwind/src/dummy.rs b/library/panic_unwind/src/dummy.rs
index 4667ede2baa..a4bcd216c60 100644
--- a/library/panic_unwind/src/dummy.rs
+++ b/library/panic_unwind/src/dummy.rs
@@ -1,6 +1,6 @@
-//! Unwinding for *wasm32* target.
+//! Unwinding for unsupported target.
 //!
-//! Right now we don't support this, so this is just stubs.
+//! Stubs that simply abort for targets that don't support unwinding otherwise.
 
 use alloc::boxed::Box;
 use core::any::Any;
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index b5d0ca2572c..e5753ccae2d 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -56,7 +56,7 @@ cfg_if::cfg_if! {
         mod real_imp;
     } else {
         // Targets that don't support unwinding.
-        // - arch=wasm32
+        // - family=wasm
         // - os=none ("bare metal" targets)
         // - os=uefi
         // - os=espidf
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 248ecdf4bef..8f43e902a87 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.44" }
+compiler_builtins = { version = "0.1.52" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
@@ -35,8 +35,8 @@ features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
 [dev-dependencies]
 rand = "0.7"
 
-[target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
-dlmalloc = { version = "0.2.1", features = ['rustc-dep-of-std'] }
+[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 
 [target.x86_64-fortanix-unknown-sgx.dependencies]
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
diff --git a/library/std/build.rs b/library/std/build.rs
index cc7184d57f1..43168e77296 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -25,6 +25,7 @@ fn main() {
         || target.contains("haiku")
         || target.contains("vxworks")
         || target.contains("wasm32")
+        || target.contains("wasm64")
         || target.contains("asmjs")
         || target.contains("espidf")
         || target.contains("solid")
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 576667c0173..9665d1fa892 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -24,7 +24,8 @@ pub const MIN_ALIGN: usize = 8;
     target_arch = "mips64",
     target_arch = "s390x",
     target_arch = "sparc64",
-    target_arch = "riscv64"
+    target_arch = "riscv64",
+    target_arch = "wasm64",
 )))]
 pub const MIN_ALIGN: usize = 16;
 
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 8b8be6ebc2f..167c918c94c 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -40,7 +40,7 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "wasi")] {
         mod wasi;
         pub use self::wasi::*;
-    } else if #[cfg(target_arch = "wasm32")] {
+    } else if #[cfg(target_family = "wasm")] {
         mod wasm;
         pub use self::wasm::*;
     } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index ef0ca3dd478..3223e894102 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -1,8 +1,8 @@
-//! This is an implementation of a global allocator on the wasm32 platform when
+//! This is an implementation of a global allocator on wasm targets when
 //! emscripten is not in use. In that situation there's no actual runtime for us
 //! to lean on for allocation, so instead we provide our own!
 //!
-//! The wasm32 instruction set has two instructions for getting the current
+//! The wasm instruction set has two instructions for getting the current
 //! amount of memory and growing the amount of memory. These instructions are the
 //! foundation on which we're able to build an allocator, so we do so! Note that
 //! the instructions are also pretty "global" and this is the "global" allocator
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 5a5913ebd79..804727fbc54 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -40,7 +40,7 @@ cfg_if::cfg_if! {
     if #[cfg(any(target_os = "l4re",
                  target_os = "hermit",
                  feature = "restricted-std",
-                 all(target_arch = "wasm32", not(target_os = "emscripten")),
+                 all(target_family = "wasm", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
         pub use crate::sys::net;
     } else {
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index c53290ec0c7..f6898d283fc 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -172,7 +172,7 @@ macro_rules! __thread_local_inner {
             //
             // FIXME(#84224) this should come after the `target_thread_local`
             // block.
-            #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+            #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
             {
                 static mut VAL: $t = $init;
                 Some(&VAL)
@@ -181,7 +181,7 @@ macro_rules! __thread_local_inner {
             // If the platform has support for `#[thread_local]`, use it.
             #[cfg(all(
                 target_thread_local,
-                not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                not(all(target_family = "wasm", not(target_feature = "atomics"))),
             ))]
             {
                 // If a dtor isn't needed we can do something "very raw" and
@@ -238,7 +238,7 @@ macro_rules! __thread_local_inner {
             // same implementation as below for os thread locals.
             #[cfg(all(
                 not(target_thread_local),
-                not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                not(all(target_family = "wasm", not(target_feature = "atomics"))),
             ))]
             {
                 #[inline]
@@ -285,21 +285,21 @@ macro_rules! __thread_local_inner {
             // The issue of "should enable on Windows sometimes" is #84933
             #[cfg_attr(not(windows), inline)]
             unsafe fn __getit() -> $crate::option::Option<&'static $t> {
-                #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+                #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
                 static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
                     $crate::thread::__StaticLocalKeyInner::new();
 
                 #[thread_local]
                 #[cfg(all(
                     target_thread_local,
-                    not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                    not(all(target_family = "wasm", not(target_feature = "atomics"))),
                 ))]
                 static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
                     $crate::thread::__FastLocalKeyInner::new();
 
                 #[cfg(all(
                     not(target_thread_local),
-                    not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                    not(all(target_family = "wasm", not(target_feature = "atomics"))),
                 ))]
                 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
                     $crate::thread::__OsLocalKeyInner::new();
@@ -479,10 +479,10 @@ mod lazy {
     }
 }
 
-/// On some platforms like wasm32 there's no threads, so no need to generate
+/// On some targets like wasm there's no threads, so no need to generate
 /// thread locals and we can instead just use plain statics!
 #[doc(hidden)]
-#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
 pub mod statik {
     use super::lazy::LazyKeyInner;
     use crate::fmt;
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 2a155ce3117..39b53b51bfa 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -200,7 +200,7 @@ pub use self::local::fast::Key as __FastLocalKeyInner;
 #[doc(hidden)]
 pub use self::local::os::Key as __OsLocalKeyInner;
 #[unstable(feature = "libstd_thread_internals", issue = "none")]
-#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
+#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
 #[doc(hidden)]
 pub use self::local::statik::Key as __StaticLocalKeyInner;
 
diff --git a/library/stdarch b/library/stdarch
index 5fdbc476afc..815d55c610d 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit 5fdbc476afc81a789806697fc4a2d9d19b8c9993
+Subproject commit 815d55c610dab39e92e7c83bf5fd4b7a020b4d46
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 11c5ab48ed3..9c261e8cc8e 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -284,7 +284,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
     // Prevent the usage of `Instant` in some cases:
     // - It's currently not supported for wasm targets.
     // - We disable it for miri because it's not available when isolation is enabled.
-    let is_instant_supported = !cfg!(target_arch = "wasm32") && !cfg!(miri);
+    let is_instant_supported = !cfg!(target_family = "wasm") && !cfg!(miri);
 
     let start_time = is_instant_supported.then(Instant::now);
     run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 99d951d8016..2516f3452b1 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -470,7 +470,7 @@ pub fn run_test(
 
     // Emscripten can catch panics but other wasm targets cannot
     let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No
-        && cfg!(target_arch = "wasm32")
+        && cfg!(target_family = "wasm")
         && !cfg!(target_os = "emscripten");
 
     if force_ignore || desc.ignore || ignore_because_no_process_support {
@@ -519,7 +519,7 @@ pub fn run_test(
         // If the platform is single-threaded we're just going to run
         // the test synchronously, regardless of the concurrency
         // level.
-        let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
+        let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm");
         if concurrency == Concurrent::Yes && supports_threads {
             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
             let mut runtest = Arc::new(Mutex::new(Some(runtest)));
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 22bf6b8a9d4..cb1b0ebf8db 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1276,7 +1276,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         builder.ensure(native::TestHelpers { target: compiler.host });
 
         // As well as the target, except for plain wasm32, which can't build it
-        if !target.contains("wasm32") || target.contains("emscripten") {
+        if !target.contains("wasm") || target.contains("emscripten") {
             builder.ensure(native::TestHelpers { target });
         }
 
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index c251425d1b7..69a0304d41d 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -16,6 +16,7 @@
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
+    - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
 - [Target Tier Policy](target-tier-policy.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 6b0c336b3c7..4da3491c586 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -276,7 +276,7 @@ target | std | host | notes
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7a Linux with NEON, MUSL
-`wasm64-unknown-unknown` | * |  | WebAssembly
+[`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 `x86_64-apple-tvos` | * | | x86 64-bit tvOS
 `x86_64-pc-windows-msvc` | ✓ |  | 64-bit Windows XP support
diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
new file mode 100644
index 00000000000..021b904debd
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
@@ -0,0 +1,101 @@
+# `wasm64-unknown-unknown`
+
+**Tier: 3**
+
+WebAssembly target which uses 64-bit memories, relying on the [memory64]
+WebAssembly proposal.
+
+[memory64]: https://github.com/webassembly/memory64
+
+## Target maintainers
+
+- Alex Crichton, https://github.com/alexcrichton
+
+## Requirements
+
+This target is cross-compiled. The target supports `std` in the same manner as
+the `wasm32-unknown-unknown` target which is to say that it comes with the
+standard library but many I/O functions such as `std::fs` and `std::net` will
+simply return error. Additionally I/O operations like `println!` don't actually
+do anything and the prints aren't routed anywhere. This is the same as the
+`wasm32-unknown-unknown` target. This target comes by default with an allocator,
+currently [dlmalloc] which is [ported to rust][dlmalloc-rs].
+
+[dlmalloc]: http://gee.cs.oswego.edu/dl/html/malloc.html
+[dlmalloc-rs]: https://github.com/alexcrichton/dlmalloc-rs
+
+The difference of this target with `wasm32-unknown-unknown` is that it's
+compiled for 64-bit memories instead of 32-bit memories. This means that `usize`
+is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum
+memory size is now the full 64-bit address space instead of the 4GB as limited
+by the 32-bit address space for `wasm32-unknown-unknown`.
+
+This target is not a stable target. The [memory64] WebAssembly proposal is stil
+in-progress and not standardized. This means that there are not many engines
+which implement the `memory64` feature and if they do they're likely behind a
+flag, for example:
+
+* Nodejs - `--experimental-wasm-memory64`
+* Wasmtime - `--wasm-features memory64`
+
+Also note that at this time the `wasm64-unknown-unknown` target assumes the
+presence of other merged wasm proposals such as (with their LLVM feature flags):
+
+* [Bulk memory] - `+bulk-memory`
+* Mutable imported globals - `+mutable-globals`
+* [Sign-extending operations] - `+sign-ext`
+* [Non-trapping fp-to-int operations] - `+nontrapping-fptoint`
+
+[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md
+[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md
+[Non-trapping fp-to-int operations]: https://github.com/WebAssembly/spec/blob/main/proposals/nontrapping-float-to-int-conversion/Overview.md
+
+The `wasm64-unknown-unknown` target intends to match the default Clang targets
+for its `"C"` ABI, which is likely to be the same as Clang's
+`wasm32-unknown-unknown` largely.
+
+> **Note**: due to the relatively early-days nature of this target when working
+> with this target you may encounter LLVM bugs. If an assertion hit or a bug is
+> found it's recommended to open an issue either with rust-lang/rust or ideally
+> with LLVM itself.
+
+This target does not support `panic=unwind` at this time.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`, and the target also requires `lld` to be built to work.
+
+```toml
+[build]
+target = ["wasm64-unknown-unknown"]
+
+[rust]
+lld = true
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `std` by using
+`build-std` or similar.
+
+Note that the following `cfg` directives are set for `wasm64-unknown-unknown`:
+
+* `cfg(target_arch = "wasm64")`
+* `cfg(target_family = "wasm")`
+
+## Testing
+
+Currently testing is not well supported for `wasm64-unknown-unknown` and the
+Rust project doesn't run any tests for this target. Testing support sort of
+works but without `println!` it's not the most exciting tests to run.
+
+## Cross-compilation toolchains and C code
+
+Compiling Rust code with C code for `wasm64-unknown-unknown` is theoretically
+possible, but there are no known toolchains to do this at this time. At the time
+of this writing there is no known "libc" for wasm that works with
+`wasm64-unknown-unknown`, which means that mixing C & Rust with this target
+effectively cannot be done.
diff --git a/src/test/ui/cfg/cfg-target-family.rs b/src/test/ui/cfg/cfg-target-family.rs
index 90a59fab8e2..5182cdc8940 100644
--- a/src/test/ui/cfg/cfg-target-family.rs
+++ b/src/test/ui/cfg/cfg-target-family.rs
@@ -4,13 +4,10 @@
 // pretty-expanded FIXME #23616
 
 #[cfg(target_family = "windows")]
-pub fn main() {
-}
+pub fn main() {}
 
 #[cfg(target_family = "unix")]
-pub fn main() {
-}
+pub fn main() {}
 
-#[cfg(target_family="wasm")]
-pub fn main() {
-}
+#[cfg(all(target_family = "wasm", not(target_os = "emscripten")))]
+pub fn main() {}