about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-01-17 22:34:26 +0100
committerFolkert de Vries <folkert@folkertdev.nl>2025-01-20 16:57:09 +0100
commitbcf478b7a6915a8ce14009934f2893ddcce8052c (patch)
tree38566a85b80106a50ba7b7fa714e6c5e1d8e2bf8
parent8dec09f3c5bf8e1f12c6ba6eb6040d710353ca63 (diff)
downloadrust-bcf478b7a6915a8ce14009934f2893ddcce8052c.tar.gz
rust-bcf478b7a6915a8ce14009934f2893ddcce8052c.zip
work around the `wasm32-unknown-unknown` ABI being broken
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs47
-rw-r--r--tests/assembly/wasm32-naked-fn.rs17
2 files changed, 48 insertions, 16 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index 35e0ea54525..dc406809874 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -1,12 +1,14 @@
 use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
 use rustc_attr_parsing::InstructionSetAttr;
+use rustc_hir::def_id::DefId;
 use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
 use rustc_middle::mir::{Body, InlineAsmOperand};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{Instance, Ty, TyCtxt};
-use rustc_middle::{bug, ty};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_span::sym;
 use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::WasmCAbi;
 
 use crate::common;
 use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
@@ -285,7 +287,12 @@ fn prefix_and_suffix<'tcx>(
                 writeln!(begin, "{}", arch_prefix).unwrap();
             }
             writeln!(begin, "{asm_name}:").unwrap();
-            writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap();
+            writeln!(
+                begin,
+                ".functype {asm_name} {}",
+                wasm_functype(tcx, fn_abi, instance.def_id())
+            )
+            .unwrap();
 
             writeln!(end).unwrap();
             // .size is ignored for function symbols, so we can skip it
@@ -299,7 +306,7 @@ fn prefix_and_suffix<'tcx>(
 /// The webassembly type signature for the given function.
 ///
 /// Used by the `.functype` directive on wasm targets.
-fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
     let mut signature = String::with_capacity(64);
 
     let ptr_type = match tcx.data_layout.pointer_size.bits() {
@@ -308,8 +315,18 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str
         other => bug!("wasm pointer size cannot be {other} bits"),
     };
 
-    let hidden_return =
-        matches!(fn_abi.ret.mode, PassMode::Indirect { .. } | PassMode::Pair { .. });
+    // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
+    // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
+    // basically the commit introducing this comment should be reverted
+    if let PassMode::Pair { .. } = fn_abi.ret.mode {
+        let _ = WasmCAbi::Legacy;
+        span_bug!(
+            tcx.def_span(def_id),
+            "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
+        );
+    }
+
+    let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
 
     signature.push('(');
 
@@ -322,7 +339,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str
 
     let mut it = fn_abi.args.iter().peekable();
     while let Some(arg_abi) = it.next() {
-        wasm_type(&mut signature, arg_abi, ptr_type);
+        wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
         if it.peek().is_some() {
             signature.push_str(", ");
         }
@@ -331,7 +348,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str
     signature.push_str(") -> (");
 
     if !hidden_return {
-        wasm_type(&mut signature, &fn_abi.ret, ptr_type);
+        wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
     }
 
     signature.push(')');
@@ -339,13 +356,27 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Str
     signature
 }
 
-fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) {
+fn wasm_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    signature: &mut String,
+    arg_abi: &ArgAbi<'_, Ty<'tcx>>,
+    ptr_type: &'static str,
+    def_id: DefId,
+) {
     match arg_abi.mode {
         PassMode::Ignore => { /* do nothing */ }
         PassMode::Direct(_) => {
             let direct_type = match arg_abi.layout.backend_repr {
                 BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
                 BackendRepr::Vector { .. } => "v128",
+                BackendRepr::Memory { .. } => {
+                    // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
+                    let _ = WasmCAbi::Legacy;
+                    span_bug!(
+                        tcx.def_span(def_id),
+                        "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
+                    );
+                }
                 other => unreachable!("unexpected BackendRepr: {:?}", other),
             };
 
diff --git a/tests/assembly/wasm32-naked-fn.rs b/tests/assembly/wasm32-naked-fn.rs
index 8e98b084729..4911a6bd08f 100644
--- a/tests/assembly/wasm32-naked-fn.rs
+++ b/tests/assembly/wasm32-naked-fn.rs
@@ -1,10 +1,10 @@
-//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1
+// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed
+// see https://github.com/rust-lang/rust/issues/115666
+//@ revisions: wasm64-unknown wasm32-wasip1
 //@ add-core-stubs
 //@ assembly-output: emit-asm
-//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown
 //@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
 //@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
-//@ [wasm32-unknown] needs-llvm-components: webassembly
 //@ [wasm64-unknown] needs-llvm-components: webassembly
 //@ [wasm32-wasip1] needs-llvm-components: webassembly
 
@@ -97,7 +97,7 @@ unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
 }
 
 // CHECK-LABEL: fn_i128_i128:
-// wasm32-unknown,wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
+// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
 // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
 #[allow(improper_ctypes_definitions)]
 #[no_mangle]
@@ -114,7 +114,7 @@ unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
 }
 
 // CHECK-LABEL: fn_f128_f128:
-// wasm32-unknown,wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
+// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
 // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
 #[no_mangle]
 #[naked]
@@ -137,18 +137,19 @@ struct Compound {
 
 // CHECK-LABEL: fn_compound_compound:
 // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
-// wasm32-unknown: .functype fn_compound_compound (i32, i32, i64) -> ()
 // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
 #[no_mangle]
 #[naked]
 unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound {
-    // this is the wasm32-unknown-unknown assembly
+    // this is the wasm32-wasip1 assembly
     naked_asm!(
         "local.get       0",
-        "local.get       2",
+        "local.get       1",
+        "i64.load        8",
         "i64.store       8",
         "local.get       0",
         "local.get       1",
+        "i32.load16_u    0",
         "i32.store16     0",
     )
 }