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