Skip to main content

rustc_target/callconv/
x86_win32.rs

1use rustc_abi::{Align, Float, HasDataLayout, Primitive, Reg, RegKind, 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 let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) {
29                // `_Complex _Float16` is returned as `<2 x half>`.
30                let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
31                fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size });
32            } else if t.abi_return_struct_as_int || opts.reg_struct_return {
33                match fn_abi.ret.layout.size.bytes() {
34                    1 => fn_abi.ret.cast_to(Reg::i8()),
35                    2 => fn_abi.ret.cast_to(Reg::i16()),
36                    4 => fn_abi.ret.cast_to(Reg::i32()),
37                    8 => fn_abi.ret.cast_to(Reg::i64()),
38                    _ => fn_abi.ret.make_indirect(),
39                }
40            } else {
41                fn_abi.ret.make_indirect();
42            }
43        } else {
44            fn_abi.ret.extend_integer_width_to(32);
45        }
46    }
47
48    for arg in fn_abi.args.iter_mut() {
49        if arg.is_ignore() || !arg.layout.is_sized() {
50            continue;
51        }
52
53        if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
54            arg.make_indirect();
55            continue;
56        }
57
58        // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
59        // See https://reviews.llvm.org/D72114 for Clang behavior
60
61        let align_4 = Align::from_bytes(4).unwrap();
62
63        if arg.layout.is_adt()
64            && let Some(max_repr_align) = arg.layout.max_repr_align
65            && max_repr_align > align_4
66        {
67            // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
68            // Summarized here:
69            // - Arguments with _requested_ alignment > 4 are passed indirectly.
70            // - For backwards compatibility, arguments with natural alignment > 4 are still passed
71            //   on stack (via `byval`). For example, this includes `double`, `int64_t`,
72            //   and structs containing them, provided they lack an explicit alignment attribute.
73            if !(arg.layout.align.abi >= max_repr_align) {
    {
        ::core::panicking::panic_fmt(format_args!("abi alignment {0:?} less than requested alignment {1:?}",
                arg.layout.align.abi, max_repr_align));
    }
};assert!(
74                arg.layout.align.abi >= max_repr_align,
75                "abi alignment {:?} less than requested alignment {max_repr_align:?}",
76                arg.layout.align.abi,
77            );
78            arg.make_indirect();
79        } else if arg.layout.is_aggregate() {
80            // Alignment of the `byval` argument.
81            // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`.
82            let byval_align = align_4;
83            arg.pass_by_stack_offset(Some(byval_align));
84        } else {
85            arg.extend_integer_width_to(32);
86        }
87    }
88
89    super::x86::fill_inregs(cx, fn_abi, opts, false);
90}