about summary refs log tree commit diff
path: root/compiler/rustc_target/src/callconv/x86_win64.rs
blob: 4d99a9f9ba064b4714149a577a32e3ed1b60e66a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};

use crate::callconv::{ArgAbi, FnAbi, Reg};
use crate::spec::{HasTargetSpec, RustcAbi};

// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing

pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
    let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
        match a.layout.backend_repr {
            BackendRepr::Memory { sized: false } => {}
            BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
                match a.layout.size.bits() {
                    8 => a.cast_to(Reg::i8()),
                    16 => a.cast_to(Reg::i16()),
                    32 => a.cast_to(Reg::i32()),
                    64 => a.cast_to(Reg::i64()),
                    _ => a.make_indirect(),
                }
            }
            BackendRepr::Vector { .. } => {
                // FIXME(eddyb) there should be a size cap here
                // (probably what clang calls "illegal vectors").
            }
            BackendRepr::Scalar(scalar) => {
                if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
                    if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {
                        // Use the native `i128` LLVM type for the softfloat ABI -- in other words, adjust nothing.
                    } else {
                        // `i128` is returned in xmm0 by Clang and GCC
                        // FIXME(#134288): This may change for the `-msvc` targets in the future.
                        let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
                        a.cast_to(reg);
                    }
                } else if a.layout.size.bytes() > 8
                    && !matches!(scalar.primitive(), Primitive::Float(Float::F128))
                {
                    // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
                    // with what LLVM expects.
                    a.make_indirect();
                } else {
                    a.extend_integer_width_to(32);
                }
            }
        }
    };

    if !fn_abi.ret.is_ignore() {
        fixup(&mut fn_abi.ret, true);
    }

    for arg in fn_abi.args.iter_mut() {
        if arg.is_ignore() && arg.layout.is_zst() {
            // Windows ABIs do not talk about ZST since such types do not exist in MSVC.
            // In that sense we can do whatever we want here, and maybe we should throw an error
            // (but of course that would be a massive breaking change now).
            // We try to match clang and gcc (which allow ZST is their windows-gnu targets), so we
            // pass ZST via pointer indirection.
            arg.make_indirect_from_ignore();
            continue;
        }
        fixup(arg, false);
    }
    // FIXME: We should likely also do something about ZST return types, similar to above.
    // However, that's non-trivial due to `()`.
    // See <https://github.com/rust-lang/unsafe-code-guidelines/issues/552>.
}