about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-01-15 15:15:52 +0100
committerFolkert de Vries <folkert@folkertdev.nl>2025-01-16 13:25:40 +0100
commit702134a9300dd36b8c49a044a06d4bc8e454cf87 (patch)
tree57ec67d60d09fd3ff327bdc870524f6b37a6ea75
parent93ba568ab98f1492a96945ef646eeb898128b2ef (diff)
downloadrust-702134a9300dd36b8c49a044a06d4bc8e454cf87.tar.gz
rust-702134a9300dd36b8c49a044a06d4bc8e454cf87.zip
use indirect return for `i128` and `f128` on wasm32
-rw-r--r--compiler/rustc_target/src/callconv/wasm.rs12
-rw-r--r--tests/codegen/f128-wasm32-callconv.rs49
-rw-r--r--tests/codegen/i128-wasm32-callconv.rs49
3 files changed, 110 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs
index 3c4cd76a754..d01b59cbb03 100644
--- a/compiler/rustc_target/src/callconv/wasm.rs
+++ b/compiler/rustc_target/src/callconv/wasm.rs
@@ -1,3 +1,5 @@
+use rustc_abi::{BackendRepr, Float, Integer, Primitive};
+
 use crate::abi::call::{ArgAbi, FnAbi};
 use crate::abi::{HasDataLayout, TyAbiInterface};
 
@@ -27,6 +29,16 @@ where
     if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) {
         ret.make_indirect();
     }
+
+    // `long double`, `__int128_t` and `__uint128_t` use an indirect return
+    if let BackendRepr::Scalar(scalar) = ret.layout.backend_repr {
+        match scalar.primitive() {
+            Primitive::Int(Integer::I128, _) | Primitive::Float(Float::F128) => {
+                ret.make_indirect();
+            }
+            _ => {}
+        }
+    }
 }
 
 fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
diff --git a/tests/codegen/f128-wasm32-callconv.rs b/tests/codegen/f128-wasm32-callconv.rs
new file mode 100644
index 00000000000..8b1b5e7fb01
--- /dev/null
+++ b/tests/codegen/f128-wasm32-callconv.rs
@@ -0,0 +1,49 @@
+//! Verify that Rust implements the expected calling convention for `f128`
+
+//@ add-core-stubs
+//@ compile-flags: -O --target wasm32-wasip1
+//@ needs-llvm-components: webassembly
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items, f128)]
+
+extern crate minicore;
+
+extern "C" {
+    fn extern_call(arg0: f128);
+    fn extern_ret() -> f128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: f128) {
+    // CHECK-LABEL: @pass(
+    // an f128 is passed via registers
+    // CHECK-SAME: fp128 noundef %arg1
+    // CHECK: call void @extern_call
+    unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: f128) -> f128 {
+    // CHECK-LABEL: @ret(
+    // but an f128 is returned via the stack
+    // CHECK-SAME: sret
+    // CHECK: store fp128 %arg1
+    // CHECK-NEXT: ret void
+    arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut f128) {
+    // CHECK-LABEL: @forward
+    // CHECK-SAME: ptr{{.*}} %dst)
+    // without optimizatons, an intermediate alloca is used
+    // CHECK: call void @extern_ret
+    // CHECK: store fp128
+    // CHECK: ret void
+    unsafe { *dst = extern_ret() };
+}
diff --git a/tests/codegen/i128-wasm32-callconv.rs b/tests/codegen/i128-wasm32-callconv.rs
new file mode 100644
index 00000000000..c6d25fbe8be
--- /dev/null
+++ b/tests/codegen/i128-wasm32-callconv.rs
@@ -0,0 +1,49 @@
+//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
+
+//@ add-core-stubs
+//@ compile-flags: -O --target wasm32-wasip1
+//@ needs-llvm-components: webassembly
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+
+extern "C" {
+    fn extern_call(arg0: i128);
+    fn extern_ret() -> i128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: i128) {
+    // CHECK-LABEL: @pass(
+    // an i128 is passed via registers
+    // CHECK-SAME: i128 noundef %arg1
+    // CHECK: call void @extern_call
+    unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
+    // CHECK-LABEL: @ret(
+    // but an i128 is returned via the stack
+    // CHECK-SAME: sret
+    // CHECK: store i128 %arg1
+    // CHECK-NEXT: ret void
+    arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut i128) {
+    // CHECK-LABEL: @forward
+    // CHECK-SAME: ptr{{.*}} %dst)
+    // without optimizatons, an intermediate alloca is used
+    // CHECK: call void @extern_ret
+    // CHECK: store i128
+    // CHECK: ret void
+    unsafe { *dst = extern_ret() };
+}