Skip to content

Commit d3bd26f

Browse files
committed
Auto merge of #155429 - folkertdev:c-variadic-i128, r=<try>
Support `u128`/`i128` c-variadic arguments try-job: dist-various-1 try-job: dist-various-2 try-job: aarch64-apple try-job: x86_64-mingw-1
2 parents 27dbdb5 + 5e8c8b5 commit d3bd26f

4 files changed

Lines changed: 64 additions & 9 deletions

File tree

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size};
1+
use rustc_abi::{Align, BackendRepr, Endian, Float, HasDataLayout, Integer, Primitive, Size};
22
use rustc_codegen_ssa::MemFlags;
33
use rustc_codegen_ssa::common::IntPredicate;
44
use rustc_codegen_ssa::mir::operand::OperandRef;
@@ -33,7 +33,7 @@ fn round_pointer_up_to_alignment<'ll>(
3333
bx.call_intrinsic(
3434
"llvm.ptrmask",
3535
&[ptr_ty, bx.type_i32()],
36-
&[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)],
36+
&[ptr, bx.const_i32(-(align.bytes() as i32))],
3737
)
3838
}
3939

@@ -75,6 +75,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
7575
}
7676
}
7777

78+
/// Some backends apply special alignment rules to c-variadic arguments.
79+
fn get_param_type_alignment<'ll, 'tcx>(
80+
bx: &mut Builder<'_, 'll, 'tcx>,
81+
layout: TyAndLayout<'tcx>,
82+
) -> Align {
83+
let BackendRepr::Scalar(scalar) = layout.backend_repr else {
84+
bug!("unexpected backend repr {:?}", layout.backend_repr);
85+
};
86+
87+
match bx.cx.tcx.sess.target.arch {
88+
Arch::PowerPC64 => match scalar.primitive() {
89+
Primitive::Int(integer, _) => match integer {
90+
Integer::I8 | Integer::I16 => unreachable!(),
91+
Integer::I32 | Integer::I64 => { /* fall through */ }
92+
Integer::I128 => return Align::EIGHT,
93+
},
94+
Primitive::Float(float) => match float {
95+
Float::F16 | Float::F32 => unreachable!(),
96+
Float::F64 => { /* fall through */ }
97+
Float::F128 => return Align::from_bytes(16).unwrap(),
98+
},
99+
Primitive::Pointer(_) => { /* fall through */ }
100+
},
101+
_ => { /* fall through */ }
102+
}
103+
104+
layout.align.abi
105+
}
106+
78107
enum PassMode {
79108
Direct,
80109
Indirect,
@@ -115,23 +144,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
115144
(
116145
bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx),
117146
bx.cx.data_layout().pointer_size(),
118-
bx.cx.data_layout().pointer_align(),
147+
bx.cx.data_layout().pointer_align().abi,
119148
)
120149
} else {
121-
(layout.llvm_type(bx.cx), layout.size, layout.align)
150+
(layout.llvm_type(bx.cx), layout.size, get_param_type_alignment(bx, layout))
122151
};
123152
let (addr, addr_align) = emit_direct_ptr_va_arg(
124153
bx,
125154
list,
126155
size,
127-
align.abi,
156+
align,
128157
slot_size,
129158
allow_higher_align,
130159
force_right_adjust,
131160
);
132161
if indirect {
133162
let tmp_ret = bx.load(llty, addr, addr_align);
134-
bx.load(layout.llvm_type(bx.cx), tmp_ret, align.abi)
163+
bx.load(layout.llvm_type(bx.cx), tmp_ret, align)
135164
} else {
136165
bx.load(llty, addr, addr_align)
137166
}
@@ -765,9 +794,16 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
765794
// byte boundary if alignment needed by type exceeds 8 byte boundary.
766795
// It isn't stated explicitly in the standard, but in practice we use
767796
// alignment greater than 16 where necessary.
768-
if layout.layout.align.bytes() > 8 {
769-
unreachable!("all instances of VaArgSafe have an alignment <= 8");
770-
}
797+
let overflow_arg_area_v = if layout.layout.align.bytes() > 8 {
798+
round_pointer_up_to_alignment(
799+
bx,
800+
overflow_arg_area_v,
801+
layout.layout.align.abi,
802+
bx.type_ptr(),
803+
)
804+
} else {
805+
overflow_arg_area_v
806+
};
771807

772808
// AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
773809
let mem_addr = overflow_arg_area_v;
@@ -1075,6 +1111,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10751111
PassMode::Direct,
10761112
SlotSize::Bytes8,
10771113
AllowHigherAlign::Yes,
1114+
// ForceRightAdjust only takes effect on big-endian architectures.
10781115
ForceRightAdjust::Yes,
10791116
),
10801117
Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => {

library/core/src/ffi/va_list.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,11 +269,13 @@ mod sealed {
269269
impl Sealed for i16 {}
270270
impl Sealed for i32 {}
271271
impl Sealed for i64 {}
272+
impl Sealed for i128 {}
272273
impl Sealed for isize {}
273274

274275
impl Sealed for u16 {}
275276
impl Sealed for u32 {}
276277
impl Sealed for u64 {}
278+
impl Sealed for u128 {}
277279
impl Sealed for usize {}
278280

279281
impl Sealed for f32 {}
@@ -334,10 +336,12 @@ crate::cfg_select! {
334336

335337
unsafe impl VaArgSafe for i32 {}
336338
unsafe impl VaArgSafe for i64 {}
339+
unsafe impl VaArgSafe for i128 {}
337340
unsafe impl VaArgSafe for isize {}
338341

339342
unsafe impl VaArgSafe for u32 {}
340343
unsafe impl VaArgSafe for u64 {}
344+
unsafe impl VaArgSafe for u128 {}
341345
unsafe impl VaArgSafe for usize {}
342346

343347
unsafe impl VaArgSafe for f64 {}

tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
5757
if compare_c_str(ap.arg::<*const c_char>(), c"Correct") { 0 } else { 0xff }
5858
}
5959

60+
#[unsafe(no_mangle)]
61+
pub unsafe extern "C" fn check_list_i128(mut ap: VaList) -> usize {
62+
continue_if!(ap.arg::<i128>() == -42);
63+
// use a 32-bit value here to test the alignment logic.
64+
continue_if!(ap.arg::<c_int>() == 0xAAAA_AAAAu32.cast_signed());
65+
continue_if!(ap.arg::<u128>() == u128::MAX);
66+
0
67+
}
68+
6069
#[unsafe(no_mangle)]
6170
pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
6271
continue_if!(ap.arg::<c_int>() == 42);

tests/run-make/c-link-to-rust-va-list-fn/test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extern size_t check_list_0(va_list ap);
88
extern size_t check_list_1(va_list ap);
99
extern size_t check_list_2(va_list ap);
1010
extern size_t check_list_copy_0(va_list ap);
11+
extern size_t check_list_i128(va_list ap);
1112
extern size_t check_varargs_0(int fixed, ...);
1213
extern size_t check_varargs_1(int fixed, ...);
1314
extern size_t check_varargs_2(int fixed, ...);
@@ -38,6 +39,10 @@ int main(int argc, char* argv[]) {
3839

3940
assert(test_rust(check_list_copy_0, 6.28, 16, 'A', "Skip Me!", "Correct") == 0);
4041

42+
#if defined(__SIZEOF_INT128__)
43+
assert(test_rust(check_list_i128, (__int128)-42, 0xAAAAAAAA, (unsigned __int128)-1) == 0);
44+
#endif
45+
4146
assert(check_varargs_0(0, 42, "Hello, World!") == 0);
4247

4348
assert(check_varargs_1(0, 3.14, 12l, 'A', 0x1LL) == 0);

0 commit comments

Comments
 (0)