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}