Skip to content

Commit ed317e4

Browse files
i686-windows: pass arguments with requested alignment > 4 indirectly
1 parent 7089321 commit ed317e4

File tree

5 files changed

+48
-5
lines changed

5 files changed

+48
-5
lines changed

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,15 @@ where
11041104
fn is_unit(this: TyAndLayout<'tcx>) -> bool {
11051105
matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
11061106
}
1107+
1108+
fn repr_options(this: TyAndLayout<'tcx>) -> ReprOptions {
1109+
match *this.ty.kind() {
1110+
ty::Adt(def, ..) => def.repr(),
1111+
_ => {
1112+
bug!("TyAndLayout::repr_options({:?}): not applicable", this)
1113+
}
1114+
}
1115+
}
11071116
}
11081117

11091118
/// Calculates whether a function's ABI can unwind or not.

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

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,31 @@ where
5454
continue;
5555
}
5656

57-
if arg.layout.is_aggregate() {
57+
// FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
58+
// See https://reviews.llvm.org/D72114 for Clang behavior
59+
60+
let t = cx.target_spec();
61+
let align_4 = Align::from_bytes(4).unwrap();
62+
let align_16 = Align::from_bytes(16).unwrap();
63+
64+
if t.is_like_msvc
65+
&& arg.layout.is_adt()
66+
&& let Some(requested_align) = arg.layout.repr_options().align
67+
&& requested_align > align_4
68+
{
69+
// MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
70+
// Summarized here:
71+
// - Arguments with _requested_ alignment > 4 are passed indirectly.
72+
// - For backwards compatibility, arguments with natural alignment > 4 are still passed
73+
// on stack (via `byval`). For example, this includes `double`, `int64_t`,
74+
// and structs containing them, provided they lack an explicit alignment attribute.
75+
assert!(arg.layout.align.abi >= requested_align,
76+
"abi alignment {:?} less than requested alignment {:?}",
77+
arg.layout.align.abi,
78+
requested_align
79+
);
80+
arg.make_indirect();
81+
} else if arg.layout.is_aggregate() {
5882
// We need to compute the alignment of the `byval` argument. The rules can be found in
5983
// `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
6084
// here, they are:
@@ -87,9 +111,6 @@ where
87111
}
88112
}
89113

90-
let t = cx.target_spec();
91-
let align_4 = Align::from_bytes(4).unwrap();
92-
let align_16 = Align::from_bytes(16).unwrap();
93114
let byval_align = if arg.layout.align.abi < align_4 {
94115
// (1.)
95116
align_4

compiler/rustc_target/src/abi/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized {
5555
fn is_never(this: TyAndLayout<'a, Self>) -> bool;
5656
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
5757
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
58+
fn repr_options(this: TyAndLayout<'a, Self>) -> ReprOptions;
5859
}
5960

6061
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
125126
Ty::is_unit(self)
126127
}
127128

129+
pub fn repr_options<C>(self) -> ReprOptions
130+
where
131+
Ty: TyAbiInterface<'a, C>,
132+
{
133+
Ty::repr_options(self)
134+
}
135+
128136
pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
129137
where
130138
Ty: TyAbiInterface<'a, C>,

compiler/rustc_target/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(associated_type_bounds)]
1313
#![feature(exhaustive_patterns)]
1414
#![feature(iter_intersperse)]
15+
#![feature(let_chains)]
1516
#![feature(min_specialization)]
1617
#![feature(never_type)]
1718
#![feature(rustc_attrs)]

tests/run-make/extern-fn-struct-passing-abi/test.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ extern "C" {
8989

9090
fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
9191

92-
fn byval_rect_with_many_huge64(a: Huge64, b: Huge64, c: Huge64, d: Huge64, e: Huge64, f: Huge64, g: Rect);
92+
fn byval_rect_with_many_huge64(
93+
a: Huge64, b: Huge64, c: Huge64,
94+
d: Huge64, e: Huge64, f: Huge64,
95+
g: Rect,
96+
);
9397

9498
fn split_rect(a: i32, b: i32, s: Rect);
9599

0 commit comments

Comments
 (0)