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:
parent
a18bd8acfc
commit
9d8ce72901
3 changed files with 89 additions and 23 deletions
|
@ -31,6 +31,7 @@ mod sparc64;
|
||||||
mod wasm;
|
mod wasm;
|
||||||
mod x86;
|
mod x86;
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
|
mod x86_win32;
|
||||||
mod x86_win64;
|
mod x86_win64;
|
||||||
mod xtensa;
|
mod xtensa;
|
||||||
|
|
||||||
|
@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||||
};
|
};
|
||||||
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
|
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
|
||||||
let opts = x86::X86Options { flavor, regparm, 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 {
|
"x86_64" => match abi {
|
||||||
ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
|
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 {
|
if t.abi_return_struct_as_int || opts.reg_struct_return {
|
||||||
// According to Clang, everyone but MSVC returns single-element
|
// According to Clang, everyone but MSVC returns single-element
|
||||||
// float aggregates directly in a floating-point register.
|
// 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() {
|
match fn_abi.ret.layout.size.bytes() {
|
||||||
4 => fn_abi.ret.cast_to(Reg::f32()),
|
4 => fn_abi.ret.cast_to(Reg::f32()),
|
||||||
8 => fn_abi.ret.cast_to(Reg::f64()),
|
8 => fn_abi.ret.cast_to(Reg::f64()),
|
||||||
|
@ -64,31 +64,11 @@ where
|
||||||
continue;
|
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 t = cx.target_spec();
|
||||||
let align_4 = Align::from_bytes(4).unwrap();
|
let align_4 = Align::from_bytes(4).unwrap();
|
||||||
let align_16 = Align::from_bytes(16).unwrap();
|
let align_16 = Align::from_bytes(16).unwrap();
|
||||||
|
|
||||||
if t.is_like_msvc
|
if arg.layout.is_aggregate() {
|
||||||
&& 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() {
|
|
||||||
// We need to compute the alignment of the `byval` argument. The rules can be found in
|
// 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
|
// `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
|
||||||
// here, they are:
|
// 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