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, RustcAbi};
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::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::SimdVector { .. } => {
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                    if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {
28                        // Use the native `i128` LLVM type for the softfloat ABI -- in other words, adjust nothing.
29                    } else {
30                        // `i128` is returned in xmm0 by Clang and GCC
31                        // FIXME(#134288): This may change for the `-msvc` targets in the future.
32                        let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
33                        a.cast_to(reg);
34                    }
35                } else if a.layout.size.bytes() > 8
36                    && !matches!(scalar.primitive(), Primitive::Float(Float::F128))
37                {
38                    // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
39                    // with what LLVM expects.
40                    a.make_indirect();
41                } else {
42                    a.extend_integer_width_to(32);
43                }
44            }
45        }
46    };
47
48    if !fn_abi.ret.is_ignore() {
49        fixup(&mut fn_abi.ret, true);
50    }
51
52    for arg in fn_abi.args.iter_mut() {
53        if arg.is_ignore() && arg.layout.is_zst() {
54            // Windows ABIs do not talk about ZST since such types do not exist in MSVC.
55            // In that sense we can do whatever we want here, and maybe we should throw an error
56            // (but of course that would be a massive breaking change now).
57            // We try to match clang and gcc (which allow ZST is their windows-gnu targets), so we
58            // pass ZST via pointer indirection.
59            arg.make_indirect_from_ignore();
60            continue;
61        }
62        fixup(arg, false);
63    }
64    // FIXME: We should likely also do something about ZST return types, similar to above.
65    // However, that's non-trivial due to `()`.
66    // See <https://github.com/rust-lang/unsafe-code-guidelines/issues/552>.
67}