Skip to content

Commit 2c77443

Browse files
committed
Auto merge of #47614 - dotdash:x86_64_sysv_ffi, r=eddyb
Fix oversized loads on x86_64 SysV FFI calls The x86_64 SysV ABI should use exact sizes for small structs passed in registers, i.e. a struct that occupies 3 bytes should use an i24, instead of the i32 it currently uses. Refs #45543
2 parents 0bb8935 + 5f3dc8b commit 2c77443

File tree

4 files changed

+94
-57
lines changed

4 files changed

+94
-57
lines changed

Diff for: src/librustc_trans/cabi_x86_64.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg
134134
None => None,
135135
Some(Class::Int) => {
136136
*i += 1;
137-
Some(match size.bytes() {
138-
1 => Reg::i8(),
139-
2 => Reg::i16(),
140-
3 |
141-
4 => Reg::i32(),
142-
_ => Reg::i64()
137+
Some(if size.bytes() < 8 {
138+
Reg {
139+
kind: RegKind::Integer,
140+
size
141+
}
142+
} else {
143+
Reg::i64()
143144
})
144145
}
145146
Some(Class::Sse) => {

Diff for: src/test/codegen/abi-x86_64_sysv.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// only-x86_64
12+
13+
// compile-flags: -C no-prepopulate-passes
14+
15+
#![crate_type = "lib"]
16+
17+
pub struct S24 {
18+
a: i8,
19+
b: i8,
20+
c: i8,
21+
}
22+
23+
pub struct S48 {
24+
a: i16,
25+
b: i16,
26+
c: i8,
27+
}
28+
29+
// CHECK: i24 @struct_24_bits(i24
30+
#[no_mangle]
31+
pub extern "sysv64" fn struct_24_bits(a: S24) -> S24 {
32+
a
33+
}
34+
35+
// CHECK: i48 @struct_48_bits(i48
36+
#[no_mangle]
37+
pub extern "sysv64" fn struct_48_bits(a: S48) -> S48 {
38+
a
39+
}

Diff for: src/test/codegen/repr-transparent-sysv64.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// only-x86_64
12+
13+
// compile-flags: -C no-prepopulate-passes
14+
15+
#![crate_type="lib"]
16+
#![feature(repr_transparent)]
17+
18+
#[repr(C)]
19+
pub struct Rgb8 { r: u8, g: u8, b: u8 }
20+
21+
#[repr(transparent)]
22+
pub struct Rgb8Wrap(Rgb8);
23+
24+
// CHECK: i24 @test_Rgb8Wrap(i24)
25+
#[no_mangle]
26+
pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} }
27+
28+
#[repr(C)]
29+
pub union FloatBits {
30+
float: f32,
31+
bits: u32,
32+
}
33+
34+
#[repr(transparent)]
35+
pub struct SmallUnion(FloatBits);
36+
37+
// CHECK: i32 @test_SmallUnion(i32)
38+
#[no_mangle]
39+
pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} }

Diff for: src/test/codegen/repr-transparent.rs

+9-51
Original file line numberDiff line numberDiff line change
@@ -123,55 +123,13 @@ pub struct StructWithProjection(<f32 as Mirror>::It);
123123
pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
124124

125125

126-
// The rest of this file tests newtypes around small aggregates on an ABI where small aggregates are
127-
// packed into one register. This is ABI-dependent, so instead we focus on one ABI and supply a
128-
// dummy definition for other ABIs to keep FileCheck happy.
126+
// All that remains to be tested are aggregates. They are tested in separate files called repr-
127+
// transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR
128+
// function signatures vary so much that it's not reasonably possible to cover all of them with a
129+
// single CHECK line.
129130
//
130-
// Bigger aggregates are tested in separate files called repr-transparent-aggregate-*.rs because
131-
// there, the expected LLVM IR function signatures vary so much that it's not reasonably possible to
132-
// cover all of them with a single CHECK line. Instead we group ABIs by the general "shape" of the
133-
// signature and have a separate test file for each bin.
134-
//
135-
// PS: You may be wondering why we don't just compare the return types and argument types for
136-
// equality with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on
137-
// newtypes containing aggregates. This is OK on all ABIs we support, but because LLVM has not
138-
// gotten rid of pointee types yet, the IR function signature will be syntactically different (%Foo*
139-
// vs %FooWrapper*).
140-
141-
#[repr(C)]
142-
pub struct Rgb8 { r: u8, g: u8, b: u8 }
143-
144-
#[repr(transparent)]
145-
pub struct Rgb8Wrap(Rgb8);
146-
147-
// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not
148-
// CHECK: define i32 @test_Rgb8Wrap(i32
149-
#[no_mangle]
150-
#[cfg(all(target_arch="x86_64", target_os="linux"))]
151-
pub extern fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} }
152-
153-
#[cfg(not(all(target_arch="x86_64", target_os="linux")))]
154-
#[no_mangle]
155-
pub extern fn test_Rgb8Wrap(_: u32) -> u32 { loop {} }
156-
157-
// Same as with the small struct above: ABI-dependent, we only test the interesting case
158-
// (ABIs that pack the aggregate into a scalar) and stub it out on other ABIs
159-
160-
#[repr(C)]
161-
pub union FloatBits {
162-
float: f32,
163-
bits: u32,
164-
}
165-
166-
#[repr(transparent)]
167-
pub struct SmallUnion(FloatBits);
168-
169-
// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not
170-
// CHECK: define i32 @test_SmallUnion(i32
171-
#[no_mangle]
172-
#[cfg(all(target_arch="x86_64", target_os="linux"))]
173-
pub extern fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} }
174-
175-
#[cfg(not(all(target_arch="x86_64", target_os="linux")))]
176-
#[no_mangle]
177-
pub extern fn test_SmallUnion(_: u32) -> u32 { loop {} }
131+
// You may be wondering why we don't just compare the return types and argument types for equality
132+
// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes
133+
// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of
134+
// pointee types yet, the IR function signature will be syntactically different (%Foo* vs
135+
// %FooWrapper*).

0 commit comments

Comments
 (0)