Rollup merge of #137363 - workingjubilee:untangle-x86-abi-impl, r=jieyouxu
compiler: factor Windows x86-32 ABI impl into its own file While it shares more than zero code with the SysV x86-32 ABI impl, there is no particular reason to organize wildly different ABIs using if-else in the same function.
This commit is contained in:
commit
3b595aa13f
3 changed files with 89 additions and 23 deletions
|
@ -31,6 +31,7 @@ mod sparc64;
|
|||
mod wasm;
|
||||
mod x86;
|
||||
mod x86_64;
|
||||
mod x86_win32;
|
||||
mod x86_win64;
|
||||
mod xtensa;
|
||||
|
||||
|
@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
};
|
||||
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
|
||||
let opts = x86::X86Options { flavor, regparm, reg_struct_return };
|
||||
x86::compute_abi_info(cx, self, opts);
|
||||
if spec.is_like_msvc {
|
||||
x86_win32::compute_abi_info(cx, self, opts);
|
||||
} else {
|
||||
x86::compute_abi_info(cx, self, opts);
|
||||
}
|
||||
}
|
||||
"x86_64" => match abi {
|
||||
ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
|
||||
|
|
|
@ -36,7 +36,7 @@ where
|
|||
if t.abi_return_struct_as_int || opts.reg_struct_return {
|
||||
// According to Clang, everyone but MSVC returns single-element
|
||||
// float aggregates directly in a floating-point register.
|
||||
if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {
|
||||
if fn_abi.ret.layout.is_single_fp_element(cx) {
|
||||
match fn_abi.ret.layout.size.bytes() {
|
||||
4 => fn_abi.ret.cast_to(Reg::f32()),
|
||||
8 => fn_abi.ret.cast_to(Reg::f64()),
|
||||
|
@ -64,31 +64,11 @@ where
|
|||
continue;
|
||||
}
|
||||
|
||||
// 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(max_repr_align) = arg.layout.max_repr_align
|
||||
&& max_repr_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 >= max_repr_align,
|
||||
"abi alignment {:?} less than requested alignment {max_repr_align:?}",
|
||||
arg.layout.align.abi,
|
||||
);
|
||||
arg.make_indirect();
|
||||
} else if arg.layout.is_aggregate() {
|
||||
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:
|
||||
|
|
81
compiler/rustc_target/src/callconv/x86_win32.rs
Normal file
81
compiler/rustc_target/src/callconv/x86_win32.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface};
|
||||
|
||||
use crate::callconv::FnAbi;
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(
|
||||
cx: &C,
|
||||
fn_abi: &mut FnAbi<'a, Ty>,
|
||||
opts: super::x86::X86Options,
|
||||
) where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() {
|
||||
// Returning a structure. Most often, this will use
|
||||
// a hidden first argument. On some platforms, though,
|
||||
// small structs are returned as integers.
|
||||
//
|
||||
// Some links:
|
||||
// https://www.angelcode.com/dev/callconv/callconv.html
|
||||
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
|
||||
let t = cx.target_spec();
|
||||
// MSVC does not special-case 1-element float aggregates, unlike others.
|
||||
// GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed:
|
||||
// - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
|
||||
// - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667
|
||||
if t.abi_return_struct_as_int || opts.reg_struct_return {
|
||||
match fn_abi.ret.layout.size.bytes() {
|
||||
1 => fn_abi.ret.cast_to(Reg::i8()),
|
||||
2 => fn_abi.ret.cast_to(Reg::i16()),
|
||||
4 => fn_abi.ret.cast_to(Reg::i32()),
|
||||
8 => fn_abi.ret.cast_to(Reg::i64()),
|
||||
_ => fn_abi.ret.make_indirect(),
|
||||
}
|
||||
} else {
|
||||
fn_abi.ret.make_indirect();
|
||||
}
|
||||
} else {
|
||||
fn_abi.ret.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
for arg in fn_abi.args.iter_mut() {
|
||||
if arg.is_ignore() || !arg.layout.is_sized() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
|
||||
// See https://reviews.llvm.org/D72114 for Clang behavior
|
||||
|
||||
let align_4 = Align::from_bytes(4).unwrap();
|
||||
|
||||
if arg.layout.is_adt()
|
||||
&& let Some(max_repr_align) = arg.layout.max_repr_align
|
||||
&& max_repr_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 >= max_repr_align,
|
||||
"abi alignment {:?} less than requested alignment {max_repr_align:?}",
|
||||
arg.layout.align.abi,
|
||||
);
|
||||
arg.make_indirect();
|
||||
} else if arg.layout.is_aggregate() {
|
||||
// Alignment of the `byval` argument.
|
||||
// The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`.
|
||||
let byval_align = align_4;
|
||||
arg.pass_by_stack_offset(Some(byval_align));
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
super::x86::fill_inregs(cx, fn_abi, opts, false);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue