Skip to content

Commit a07eb0a

Browse files
implement vector-containing aggregate alignment for x86 darwin
1 parent be1d4e3 commit a07eb0a

File tree

2 files changed

+109
-31
lines changed

2 files changed

+109
-31
lines changed

compiler/rustc_target/src/abi/call/x86.rs

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
2-
use crate::abi::{Align, HasDataLayout, TyAbiInterface};
2+
use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout};
33
use crate::spec::HasTargetSpec;
44

55
#[derive(PartialEq)]
@@ -53,38 +53,58 @@ where
5353
if arg.is_ignore() {
5454
continue;
5555
}
56-
if !arg.layout.is_aggregate() {
57-
arg.extend_integer_width_to(32);
58-
continue;
59-
}
6056

61-
// We need to compute the alignment of the `byval` argument. The rules can be found in
62-
// `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized here,
63-
// they are:
64-
//
65-
// 1. If the natural alignment of the type is less than or equal to 4, the alignment is 4.
66-
//
67-
// 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment.
68-
// (This doesn't matter here because we ensure we have an aggregate with the check above.)
69-
//
70-
// 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector type
71-
// is 16.
72-
//
73-
// 4. If none of these conditions are true, the alignment is 4.
74-
let t = cx.target_spec();
75-
let align_4 = Align::from_bytes(4).unwrap();
76-
let align_16 = Align::from_bytes(16).unwrap();
77-
let byval_align = if arg.layout.align.abi < align_4 {
78-
align_4
79-
} else if t.is_like_osx && arg.layout.align.abi >= align_16 {
80-
// FIXME(pcwalton): This is dubious--we should actually be looking inside the type to
81-
// determine if it contains SIMD vector values--but I think it's fine?
82-
align_16
83-
} else {
84-
align_4
85-
};
57+
if arg.layout.is_aggregate() {
58+
// We need to compute the alignment of the `byval` argument. The rules can be found in
59+
// `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
60+
// here, they are:
61+
//
62+
// 1. If the natural alignment of the type is <= 4, the alignment is 4.
63+
//
64+
// 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment.
65+
// This doesn't matter here because we only pass aggregates via `byval`, not vectors.
66+
//
67+
// 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector
68+
// type is 16.
69+
//
70+
// 4. If none of these conditions are true, the alignment is 4.
71+
72+
fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
73+
where
74+
Ty: TyAbiInterface<'a, C> + Copy,
75+
{
76+
match layout.abi {
77+
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false,
78+
Abi::Vector { .. } => true,
79+
Abi::Aggregate { .. } => {
80+
for i in 0..layout.fields.count() {
81+
if contains_vector(cx, layout.field(cx, i)) {
82+
return true;
83+
}
84+
}
85+
false
86+
}
87+
}
88+
}
8689

87-
arg.make_indirect_byval(Some(byval_align));
90+
let t = cx.target_spec();
91+
let align_4 = Align::from_bytes(4).unwrap();
92+
let align_16 = Align::from_bytes(16).unwrap();
93+
let byval_align = if arg.layout.align.abi < align_4 {
94+
// (1.)
95+
align_4
96+
} else if t.is_like_osx && contains_vector(cx, arg.layout) {
97+
// (3.)
98+
align_16
99+
} else {
100+
// (4.)
101+
align_4
102+
};
103+
104+
arg.make_indirect_byval(Some(byval_align));
105+
} else {
106+
arg.extend_integer_width_to(32);
107+
}
88108
}
89109

90110
if flavor == Flavor::FastcallOrVectorcall {

tests/codegen/align-byval-vector.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// revisions:x86-linux x86-darwin
2+
3+
//[x86-linux] compile-flags: --target i686-unknown-linux-gnu
4+
//[x86-linux] needs-llvm-components: x86
5+
//[x86-darwin] compile-flags: --target i686-apple-darwin
6+
//[x86-darwin] needs-llvm-components: x86
7+
8+
// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin.
9+
10+
#![feature(no_core, lang_items, repr_simd, simd_ffi)]
11+
#![crate_type = "lib"]
12+
#![no_std]
13+
#![no_core]
14+
#![allow(non_camel_case_types)]
15+
16+
#[lang = "sized"]
17+
trait Sized {}
18+
#[lang = "freeze"]
19+
trait Freeze {}
20+
#[lang = "copy"]
21+
trait Copy {}
22+
23+
#[repr(simd)]
24+
pub struct i32x4(i32, i32, i32, i32);
25+
26+
#[repr(C)]
27+
pub struct Foo {
28+
a: i32x4,
29+
b: i8,
30+
}
31+
32+
// This tests that we recursively check for vector types, not just at the top level.
33+
#[repr(C)]
34+
pub struct DoubleFoo {
35+
one: Foo,
36+
two: Foo,
37+
}
38+
39+
extern "C" {
40+
// x86-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}})
41+
// x86-darwin: declare void @f({{.*}}byval(%Foo) align 16{{.*}})
42+
fn f(foo: Foo);
43+
44+
// x86-linux: declare void @g({{.*}}byval(%DoubleFoo) align 4{{.*}})
45+
// x86-darwin: declare void @g({{.*}}byval(%DoubleFoo) align 16{{.*}})
46+
fn g(foo: DoubleFoo);
47+
}
48+
49+
pub fn main() {
50+
unsafe { f(Foo { a: i32x4(1, 2, 3, 4), b: 0 }) }
51+
52+
unsafe {
53+
g(DoubleFoo {
54+
one: Foo { a: i32x4(1, 2, 3, 4), b: 0 },
55+
two: Foo { a: i32x4(1, 2, 3, 4), b: 0 },
56+
})
57+
}
58+
}

0 commit comments

Comments
 (0)