rustc_target/callconv/
x86_win64.rs

1use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
2
3use crate::callconv::{ArgAbi, FnAbi, Reg};
4use crate::spec::HasTargetSpec;
5
6// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
7
8pub(crate) fn compute_abi_info<Ty>(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
9    let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
10        match a.layout.backend_repr {
11            BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
12            BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
13                match a.layout.size.bits() {
14                    8 => a.cast_to(Reg::i8()),
15                    16 => a.cast_to(Reg::i16()),
16                    32 => a.cast_to(Reg::i32()),
17                    64 => a.cast_to(Reg::i64()),
18                    _ => a.make_indirect(),
19                }
20            }
21            BackendRepr::Vector { .. } => {
22                // FIXME(eddyb) there should be a size cap here
23                // (probably what clang calls "illegal vectors").
24            }
25            BackendRepr::Scalar(scalar) => {
26                if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
27                    // `i128` is returned in xmm0 by Clang and GCC
28                    // FIXME(#134288): This may change for the `-msvc` targets in the future.
29                    let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
30                    a.cast_to(reg);
31                } else if a.layout.size.bytes() > 8
32                    && !matches!(scalar.primitive(), Primitive::Float(Float::F128))
33                {
34                    // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
35                    // with what LLVM expects.
36                    a.make_indirect();
37                } else {
38                    a.extend_integer_width_to(32);
39                }
40            }
41        }
42    };
43
44    if !fn_abi.ret.is_ignore() {
45        fixup(&mut fn_abi.ret, true);
46    }
47
48    for arg in fn_abi.args.iter_mut() {
49        if arg.is_ignore() && arg.layout.is_zst() {
50            // Windows ABIs do not talk about ZST since such types do not exist in MSVC.
51            // In that sense we can do whatever we want here, and maybe we should throw an error
52            // (but of course that would be a massive breaking change now).
53            // We try to match clang and gcc (which allow ZST is their windows-gnu targets), so we
54            // pass ZST via pointer indirection.
55            arg.make_indirect_from_ignore();
56            continue;
57        }
58        fixup(arg, false);
59    }
60    // FIXME: We should likely also do something about ZST return types, similar to above.
61    // However, that's non-trivial due to `()`.
62    // See <https://github.com/rust-lang/unsafe-code-guidelines/issues/552>.
63}