Skip to content

Commit 847247b

Browse files
committed
Introduce a test for the i128 calling convention on Windows
Currently we both pass and return `i128` indirectly on Windows for MSVC and MinGW, but this will be adjusted. Introduce a test verifying the current state.
1 parent 3cd9311 commit 847247b

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

tests/codegen/i128-x86-callconv.rs

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
2+
3+
//@ revisions: MSVC MINGW
4+
//@ add-core-stubs
5+
//@ [MSVC] needs-llvm-components: x86
6+
//@ [MINGW] needs-llvm-components: x86
7+
//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc
8+
//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu
9+
//@ [MSVC] filecheck-flags: --check-prefix=WIN
10+
//@ [MINGW] filecheck-flags: --check-prefix=WIN
11+
12+
#![crate_type = "lib"]
13+
#![no_std]
14+
#![no_core]
15+
#![feature(no_core, lang_items)]
16+
17+
extern crate minicore;
18+
19+
extern "C" {
20+
fn extern_call(arg0: i128);
21+
fn extern_ret() -> i128;
22+
}
23+
24+
#[no_mangle]
25+
pub extern "C" fn pass(_arg0: u32, arg1: i128) {
26+
// CHECK-LABEL: @pass(
27+
// i128 is passed indirectly on Windows. It should load the pointer to the stack and pass
28+
// a pointer to that allocation.
29+
// WIN-SAME: %_arg0, ptr{{.*}} %arg1)
30+
// WIN: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16
31+
// WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
32+
// WIN: store i128 [[LOADED]], ptr [[PASS]]
33+
// WIN: call void @extern_call
34+
unsafe { extern_call(arg1) };
35+
}
36+
37+
// Check that we produce the correct return ABI
38+
#[no_mangle]
39+
pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
40+
// CHECK-LABEL: @ret(
41+
// i128 is returned on the stack on Windows.
42+
// FIXME: this ABI does not agree with Clang or MinGW GCC
43+
// WIN-SAME: ptr{{.*}} sret([16 x i8]){{.*}} [[RET:%_[0-9]+]], i32{{.*}} %_arg0, ptr{{.*}} %arg1)
44+
// WIN: [[LOADED:%[0-9]+]] = load i128, ptr %arg1
45+
// WIN: store i128 [[LOADED]], ptr [[RET]]
46+
// WIN: ret void
47+
arg1
48+
}
49+
50+
// Check that we consume the correct return ABI
51+
#[no_mangle]
52+
pub extern "C" fn forward(dst: *mut i128) {
53+
// CHECK-LABEL: @forward
54+
// WIN-SAME: ptr{{.*}} %dst)
55+
// WIN: [[RETURNED:%[_0-9]+]] = alloca [16 x i8], align 16
56+
// WIN: call void @extern_ret({{.*}} [[RETURNED]])
57+
// WIN: [[TMP:%[_0-9]+]] = load i128, ptr [[RETURNED]]
58+
// WIN: store i128 [[TMP]], ptr %dst
59+
// WIN: ret void
60+
unsafe { *dst = extern_ret() };
61+
}
62+
63+
#[repr(C)]
64+
struct RetAggregate {
65+
a: i32,
66+
b: i128,
67+
}
68+
69+
#[no_mangle]
70+
pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate {
71+
// CHECK-LABEL: @ret_aggregate(
72+
// Aggregates should also be returned indirectly
73+
// WIN-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1)
74+
// WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
75+
// WIN: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]]
76+
// WIN: store i128 [[LOADED]], ptr [[GEP]]
77+
// WIN: ret void
78+
RetAggregate { a: 1, b: arg1 }
79+
}

0 commit comments

Comments
 (0)