]>
Commit | Line | Data |
---|---|---|
60c5eb7d | 1 | use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; |
5099ac24 | 2 | use crate::abi::{HasDataLayout, TyAbiInterface}; |
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 | ||
60c5eb7d | 11 | pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) |
dfeec247 | 12 | where |
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 | } |