i686-windows: pass arguments with requested alignment > 4 indirectly

This commit is contained in:
Erik Desjardins 2023-05-20 16:11:09 -04:00
parent 7089321c6d
commit ed317e4a47
5 changed files with 48 additions and 5 deletions

View File

@ -1104,6 +1104,15 @@ where
fn is_unit(this: TyAndLayout<'tcx>) -> bool {
matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
}
fn repr_options(this: TyAndLayout<'tcx>) -> ReprOptions {
match *this.ty.kind() {
ty::Adt(def, ..) => def.repr(),
_ => {
bug!("TyAndLayout::repr_options({:?}): not applicable", this)
}
}
}
}
/// Calculates whether a function's ABI can unwind or not.

View File

@ -54,7 +54,31 @@ where
continue;
}
if arg.layout.is_aggregate() {
// FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
// See https://reviews.llvm.org/D72114 for Clang behavior
let t = cx.target_spec();
let align_4 = Align::from_bytes(4).unwrap();
let align_16 = Align::from_bytes(16).unwrap();
if t.is_like_msvc
&& arg.layout.is_adt()
&& let Some(requested_align) = arg.layout.repr_options().align
&& requested_align > align_4
{
// MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
// Summarized here:
// - Arguments with _requested_ alignment > 4 are passed indirectly.
// - For backwards compatibility, arguments with natural alignment > 4 are still passed
// on stack (via `byval`). For example, this includes `double`, `int64_t`,
// and structs containing them, provided they lack an explicit alignment attribute.
assert!(arg.layout.align.abi >= requested_align,
"abi alignment {:?} less than requested alignment {:?}",
arg.layout.align.abi,
requested_align
);
arg.make_indirect();
} else if arg.layout.is_aggregate() {
// We need to compute the alignment of the `byval` argument. The rules can be found in
// `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
// here, they are:
@ -87,9 +111,6 @@ where
}
}
let t = cx.target_spec();
let align_4 = Align::from_bytes(4).unwrap();
let align_16 = Align::from_bytes(16).unwrap();
let byval_align = if arg.layout.align.abi < align_4 {
// (1.)
align_4

View File

@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized {
fn is_never(this: TyAndLayout<'a, Self>) -> bool;
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
fn repr_options(this: TyAndLayout<'a, Self>) -> ReprOptions;
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_unit(self)
}
pub fn repr_options<C>(self) -> ReprOptions
where
Ty: TyAbiInterface<'a, C>,
{
Ty::repr_options(self)
}
pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
where
Ty: TyAbiInterface<'a, C>,

View File

@ -12,6 +12,7 @@
#![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]

View File

@ -89,7 +89,11 @@ extern "C" {
fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
fn byval_rect_with_many_huge64(a: Huge64, b: Huge64, c: Huge64, d: Huge64, e: Huge64, f: Huge64, g: Rect);
fn byval_rect_with_many_huge64(
a: Huge64, b: Huge64, c: Huge64,
d: Huge64, e: Huge64, f: Huge64,
g: Rect,
);
fn split_rect(a: i32, b: i32, s: Rect);