rustc_target/callconv/x86_win32.rs
1use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface};
2
3use crate::callconv::FnAbi;
4use crate::spec::HasTargetSpec;
5
6pub(crate) fn compute_abi_info<'a, Ty, C>(
7 cx: &C,
8 fn_abi: &mut FnAbi<'a, Ty>,
9 opts: super::x86::X86Options,
10) where
11 Ty: TyAbiInterface<'a, C> + Copy,
12 C: HasDataLayout + HasTargetSpec,
13{
14 if !fn_abi.ret.is_ignore() {
15 if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() {
16 // Returning a structure. Most often, this will use
17 // a hidden first argument. On some platforms, though,
18 // small structs are returned as integers.
19 //
20 // Some links:
21 // https://www.angelcode.com/dev/callconv/callconv.html
22 // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
23 let t = cx.target_spec();
24 // MSVC does not special-case 1-element float aggregates, unlike others.
25 // GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed:
26 // - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
27 // - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667
28 if t.abi_return_struct_as_int || opts.reg_struct_return {
29 match fn_abi.ret.layout.size.bytes() {
30 1 => fn_abi.ret.cast_to(Reg::i8()),
31 2 => fn_abi.ret.cast_to(Reg::i16()),
32 4 => fn_abi.ret.cast_to(Reg::i32()),
33 8 => fn_abi.ret.cast_to(Reg::i64()),
34 _ => fn_abi.ret.make_indirect(),
35 }
36 } else {
37 fn_abi.ret.make_indirect();
38 }
39 } else {
40 fn_abi.ret.extend_integer_width_to(32);
41 }
42 }
43
44 for arg in fn_abi.args.iter_mut() {
45 if arg.is_ignore() || !arg.layout.is_sized() {
46 continue;
47 }
48
49 // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
50 // See https://reviews.llvm.org/D72114 for Clang behavior
51
52 let align_4 = Align::from_bytes(4).unwrap();
53
54 if arg.layout.is_adt()
55 && let Some(max_repr_align) = arg.layout.max_repr_align
56 && max_repr_align > align_4
57 {
58 // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
59 // Summarized here:
60 // - Arguments with _requested_ alignment > 4 are passed indirectly.
61 // - For backwards compatibility, arguments with natural alignment > 4 are still passed
62 // on stack (via `byval`). For example, this includes `double`, `int64_t`,
63 // and structs containing them, provided they lack an explicit alignment attribute.
64 assert!(
65 arg.layout.align.abi >= max_repr_align,
66 "abi alignment {:?} less than requested alignment {max_repr_align:?}",
67 arg.layout.align.abi,
68 );
69 arg.make_indirect();
70 } else if arg.layout.is_aggregate() {
71 // Alignment of the `byval` argument.
72 // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`.
73 let byval_align = align_4;
74 arg.pass_by_stack_offset(Some(byval_align));
75 } else {
76 arg.extend_integer_width_to(32);
77 }
78 }
79
80 super::x86::fill_inregs(cx, fn_abi, opts, false);
81}