]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_target/src/abi/call/x86.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_target / src / abi / call / x86.rs
CommitLineData
60c5eb7d 1use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
5099ac24 2use crate::abi::{HasDataLayout, TyAbiInterface};
9fa01778 3use crate::spec::HasTargetSpec;
ea8adc8c 4
32a655c1
SL
5#[derive(PartialEq)]
6pub enum Flavor {
7 General,
dfeec247 8 Fastcall,
32a655c1
SL
9}
10
60c5eb7d 11pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
dfeec247 12where
94222f64
XL
13 Ty: TyAbiInterface<'a, C> + Copy,
14 C: HasDataLayout + HasTargetSpec,
83c7162d 15{
60c5eb7d
XL
16 if !fn_abi.ret.is_ignore() {
17 if fn_abi.ret.layout.is_aggregate() {
54a0048b
SL
18 // Returning a structure. Most often, this will use
19 // a hidden first argument. On some platforms, though,
20 // small structs are returned as integers.
21 //
22 // Some links:
136023e0 23 // https://www.angelcode.com/dev/callconv/callconv.html
54a0048b 24 // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
83c7162d 25 let t = cx.target_spec();
29967ef6 26 if t.abi_return_struct_as_int {
ea8adc8c
XL
27 // According to Clang, everyone but MSVC returns single-element
28 // float aggregates directly in a floating-point register.
5099ac24 29 if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {
60c5eb7d
XL
30 match fn_abi.ret.layout.size.bytes() {
31 4 => fn_abi.ret.cast_to(Reg::f32()),
32 8 => fn_abi.ret.cast_to(Reg::f64()),
dfeec247 33 _ => fn_abi.ret.make_indirect(),
ea8adc8c
XL
34 }
35 } else {
60c5eb7d
XL
36 match fn_abi.ret.layout.size.bytes() {
37 1 => fn_abi.ret.cast_to(Reg::i8()),
38 2 => fn_abi.ret.cast_to(Reg::i16()),
39 4 => fn_abi.ret.cast_to(Reg::i32()),
40 8 => fn_abi.ret.cast_to(Reg::i64()),
dfeec247 41 _ => fn_abi.ret.make_indirect(),
ea8adc8c 42 }
54a0048b
SL
43 }
44 } else {
60c5eb7d 45 fn_abi.ret.make_indirect();
54a0048b
SL
46 }
47 } else {
60c5eb7d 48 fn_abi.ret.extend_integer_width_to(32);
54a0048b
SL
49 }
50 }
51
60c5eb7d 52 for arg in &mut fn_abi.args {
dfeec247
XL
53 if arg.is_ignore() {
54 continue;
55 }
cc61c64b 56 if arg.layout.is_aggregate() {
ff7c6d11 57 arg.make_indirect_byval();
54a0048b
SL
58 } else {
59 arg.extend_integer_width_to(32);
60 }
61 }
32a655c1
SL
62
63 if flavor == Flavor::Fastcall {
64 // Mark arguments as InReg like clang does it,
65 // so our fastcall is compatible with C/C++ fastcall.
66
67 // Clang reference: lib/CodeGen/TargetInfo.cpp
68 // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
69
70 // IsSoftFloatABI is only set to true on ARM platforms,
71 // which in turn can't be x86?
72
73 let mut free_regs = 2;
74
60c5eb7d 75 for arg in &mut fn_abi.args {
ff7c6d11 76 let attrs = match arg.mode {
fc512014
XL
77 PassMode::Ignore
78 | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
79 continue;
80 }
ff7c6d11 81 PassMode::Direct(ref mut attrs) => attrs,
fc512014
XL
82 PassMode::Pair(..)
83 | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
84 | PassMode::Cast(_) => {
83c7162d 85 unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
ff7c6d11
XL
86 }
87 };
32a655c1 88
cc61c64b 89 // At this point we know this must be a primitive of sorts.
74b04a01 90 let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
ff7c6d11 91 assert_eq!(unit.size, arg.layout.size);
cc61c64b 92 if unit.kind == RegKind::Float {
32a655c1
SL
93 continue;
94 }
95
ff7c6d11 96 let size_in_regs = (arg.layout.size.bits() + 31) / 32;
32a655c1
SL
97
98 if size_in_regs == 0 {
99 continue;
100 }
101
102 if size_in_regs > free_regs {
103 break;
104 }
105
106 free_regs -= size_in_regs;
107
ff7c6d11
XL
108 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
109 attrs.set(ArgAttribute::InReg);
32a655c1
SL
110 }
111
112 if free_regs == 0 {
113 break;
114 }
115 }
116 }
54a0048b 117}