]>
Commit | Line | Data |
---|---|---|
60c5eb7d | 1 | use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; |
ba9703b0 | 2 | use crate::abi::{self, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods}; |
9fa01778 | 3 | use crate::spec::HasTargetSpec; |
ea8adc8c | 4 | |
32a655c1 SL |
5 | #[derive(PartialEq)] |
6 | pub enum Flavor { | |
7 | General, | |
dfeec247 | 8 | Fastcall, |
32a655c1 SL |
9 | } |
10 | ||
ba9703b0 | 11 | fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool |
dfeec247 | 12 | where |
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 | 29 | pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) |
dfeec247 | 30 | where |
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 | } |