Skip to content

Commit 581e0ac

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 27f3361 commit 581e0ac

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

tests/codegen/i128-x86-callconv.rs

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

0 commit comments

Comments
 (0)