Skip to content

Commit bcd0683

Browse files
committed
Auto merge of #135534 - folkertdev:fix-wasm-i128-f128, r=tgross35
use indirect return for `i128` and `f128` on wasm32 fixes #135532 Based on https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md we now use an indirect return for `i128`, `u128` and `f128`. That is what LLVM ended up doing anyway. r? `@bjorn3`
2 parents 73c0ae6 + 702134a commit bcd0683

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

compiler/rustc_target/src/callconv/wasm.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use rustc_abi::{BackendRepr, Float, Integer, Primitive};
2+
13
use crate::abi::call::{ArgAbi, FnAbi};
24
use crate::abi::{HasDataLayout, TyAbiInterface};
35

@@ -27,6 +29,16 @@ where
2729
if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) {
2830
ret.make_indirect();
2931
}
32+
33+
// `long double`, `__int128_t` and `__uint128_t` use an indirect return
34+
if let BackendRepr::Scalar(scalar) = ret.layout.backend_repr {
35+
match scalar.primitive() {
36+
Primitive::Int(Integer::I128, _) | Primitive::Float(Float::F128) => {
37+
ret.make_indirect();
38+
}
39+
_ => {}
40+
}
41+
}
3042
}
3143

3244
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)

tests/codegen/f128-wasm32-callconv.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! Verify that Rust implements the expected calling convention for `f128`
2+
3+
//@ add-core-stubs
4+
//@ compile-flags: -O --target wasm32-wasip1
5+
//@ needs-llvm-components: webassembly
6+
7+
#![crate_type = "lib"]
8+
#![no_std]
9+
#![no_core]
10+
#![feature(no_core, lang_items, f128)]
11+
12+
extern crate minicore;
13+
14+
extern "C" {
15+
fn extern_call(arg0: f128);
16+
fn extern_ret() -> f128;
17+
}
18+
19+
#[no_mangle]
20+
pub extern "C" fn pass(_arg0: u32, arg1: f128) {
21+
// CHECK-LABEL: @pass(
22+
// an f128 is passed via registers
23+
// CHECK-SAME: fp128 noundef %arg1
24+
// CHECK: call void @extern_call
25+
unsafe { extern_call(arg1) };
26+
}
27+
28+
// Check that we produce the correct return ABI
29+
#[no_mangle]
30+
pub extern "C" fn ret(_arg0: u32, arg1: f128) -> f128 {
31+
// CHECK-LABEL: @ret(
32+
// but an f128 is returned via the stack
33+
// CHECK-SAME: sret
34+
// CHECK: store fp128 %arg1
35+
// CHECK-NEXT: ret void
36+
arg1
37+
}
38+
39+
// Check that we consume the correct return ABI
40+
#[no_mangle]
41+
pub extern "C" fn forward(dst: *mut f128) {
42+
// CHECK-LABEL: @forward
43+
// CHECK-SAME: ptr{{.*}} %dst)
44+
// without optimizatons, an intermediate alloca is used
45+
// CHECK: call void @extern_ret
46+
// CHECK: store fp128
47+
// CHECK: ret void
48+
unsafe { *dst = extern_ret() };
49+
}

tests/codegen/i128-wasm32-callconv.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
2+
3+
//@ add-core-stubs
4+
//@ compile-flags: -O --target wasm32-wasip1
5+
//@ needs-llvm-components: webassembly
6+
7+
#![crate_type = "lib"]
8+
#![no_std]
9+
#![no_core]
10+
#![feature(no_core, lang_items)]
11+
12+
extern crate minicore;
13+
14+
extern "C" {
15+
fn extern_call(arg0: i128);
16+
fn extern_ret() -> i128;
17+
}
18+
19+
#[no_mangle]
20+
pub extern "C" fn pass(_arg0: u32, arg1: i128) {
21+
// CHECK-LABEL: @pass(
22+
// an i128 is passed via registers
23+
// CHECK-SAME: i128 noundef %arg1
24+
// CHECK: call void @extern_call
25+
unsafe { extern_call(arg1) };
26+
}
27+
28+
// Check that we produce the correct return ABI
29+
#[no_mangle]
30+
pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
31+
// CHECK-LABEL: @ret(
32+
// but an i128 is returned via the stack
33+
// CHECK-SAME: sret
34+
// CHECK: store i128 %arg1
35+
// CHECK-NEXT: ret void
36+
arg1
37+
}
38+
39+
// Check that we consume the correct return ABI
40+
#[no_mangle]
41+
pub extern "C" fn forward(dst: *mut i128) {
42+
// CHECK-LABEL: @forward
43+
// CHECK-SAME: ptr{{.*}} %dst)
44+
// without optimizatons, an intermediate alloca is used
45+
// CHECK: call void @extern_ret
46+
// CHECK: store i128
47+
// CHECK: ret void
48+
unsafe { *dst = extern_ret() };
49+
}

0 commit comments

Comments
 (0)