]>
Commit | Line | Data |
---|---|---|
cc61c64b | 1 | // FIXME: |
9cc50fc6 SL |
2 | // Alignment of 128 bit types is not currently handled, this will |
3 | // need to be fixed when PowerPC vector support is added. | |
4 | ||
dfeec247 | 5 | use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; |
94222f64 | 6 | use crate::abi::{Endian, HasDataLayout, TyAbiInterface}; |
9fa01778 | 7 | use crate::spec::HasTargetSpec; |
9cc50fc6 | 8 | |
ea8adc8c XL |
9 | #[derive(Debug, Clone, Copy, PartialEq)] |
10 | enum ABI { | |
11 | ELFv1, // original ABI used for powerpc64 (big-endian) | |
a1dfa0c6 | 12 | ELFv2, // newer ABI used for powerpc64le and musl (both endians) |
ea8adc8c | 13 | } |
9fa01778 | 14 | use ABI::*; |
ea8adc8c | 15 | |
dfeec247 XL |
16 | fn is_homogeneous_aggregate<'a, Ty, C>( |
17 | cx: &C, | |
18 | arg: &mut ArgAbi<'a, Ty>, | |
19 | abi: ABI, | |
20 | ) -> Option<Uniform> | |
21 | where | |
94222f64 XL |
22 | Ty: TyAbiInterface<'a, C> + Copy, |
23 | C: HasDataLayout, | |
83c7162d | 24 | { |
74b04a01 | 25 | arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { |
ea8adc8c XL |
26 | // ELFv1 only passes one-member aggregates transparently. |
27 | // ELFv2 passes up to eight uniquely addressable members. | |
ff7c6d11 | 28 | if (abi == ELFv1 && arg.layout.size > unit.size) |
dfeec247 XL |
29 | || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() |
30 | { | |
cc61c64b | 31 | return None; |
9cc50fc6 SL |
32 | } |
33 | ||
cc61c64b XL |
34 | let valid_unit = match unit.kind { |
35 | RegKind::Integer => false, | |
36 | RegKind::Float => true, | |
dfeec247 | 37 | RegKind::Vector => arg.layout.size.bits() == 128, |
cc61c64b | 38 | }; |
9cc50fc6 | 39 | |
60c5eb7d | 40 | valid_unit.then_some(Uniform { unit, total: arg.layout.size }) |
9cc50fc6 SL |
41 | }) |
42 | } | |
43 | ||
60c5eb7d | 44 | fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI) |
dfeec247 | 45 | where |
94222f64 XL |
46 | Ty: TyAbiInterface<'a, C> + Copy, |
47 | C: HasDataLayout, | |
83c7162d | 48 | { |
cc61c64b | 49 | if !ret.layout.is_aggregate() { |
54a0048b SL |
50 | ret.extend_integer_width_to(64); |
51 | return; | |
9cc50fc6 SL |
52 | } |
53 | ||
ea8adc8c XL |
54 | // The ELFv1 ABI doesn't return aggregates in registers |
55 | if abi == ELFv1 { | |
ff7c6d11 | 56 | ret.make_indirect(); |
ea8adc8c | 57 | return; |
9cc50fc6 SL |
58 | } |
59 | ||
2c00a5a8 | 60 | if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) { |
ff7c6d11 | 61 | ret.cast_to(uniform); |
54a0048b | 62 | return; |
9cc50fc6 | 63 | } |
ea8adc8c | 64 | |
ff7c6d11 | 65 | let size = ret.layout.size; |
cc61c64b XL |
66 | let bits = size.bits(); |
67 | if bits <= 128 { | |
a1dfa0c6 XL |
68 | let unit = if cx.data_layout().endian == Endian::Big { |
69 | Reg { kind: RegKind::Integer, size } | |
70 | } else if bits <= 8 { | |
cc61c64b XL |
71 | Reg::i8() |
72 | } else if bits <= 16 { | |
73 | Reg::i16() | |
74 | } else if bits <= 32 { | |
75 | Reg::i32() | |
9cc50fc6 | 76 | } else { |
cc61c64b | 77 | Reg::i64() |
9cc50fc6 | 78 | }; |
cc61c64b | 79 | |
dfeec247 | 80 | ret.cast_to(Uniform { unit, total: size }); |
54a0048b | 81 | return; |
9cc50fc6 SL |
82 | } |
83 | ||
ff7c6d11 | 84 | ret.make_indirect(); |
9cc50fc6 SL |
85 | } |
86 | ||
60c5eb7d | 87 | fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI) |
dfeec247 | 88 | where |
94222f64 XL |
89 | Ty: TyAbiInterface<'a, C> + Copy, |
90 | C: HasDataLayout, | |
83c7162d | 91 | { |
cc61c64b | 92 | if !arg.layout.is_aggregate() { |
54a0048b SL |
93 | arg.extend_integer_width_to(64); |
94 | return; | |
9cc50fc6 | 95 | } |
54a0048b | 96 | |
2c00a5a8 | 97 | if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) { |
ff7c6d11 | 98 | arg.cast_to(uniform); |
54a0048b | 99 | return; |
9cc50fc6 SL |
100 | } |
101 | ||
ff7c6d11 | 102 | let size = arg.layout.size; |
a1dfa0c6 XL |
103 | let (unit, total) = if size.bits() <= 64 { |
104 | // Aggregates smaller than a doubleword should appear in | |
105 | // the least-significant bits of the parameter doubleword. | |
106 | (Reg { kind: RegKind::Integer, size }, size) | |
107 | } else { | |
108 | // Aggregates larger than a doubleword should be padded | |
109 | // at the tail to fill out a whole number of doublewords. | |
110 | let reg_i64 = Reg::i64(); | |
111 | (reg_i64, size.align_to(reg_i64.align(cx))) | |
ea8adc8c XL |
112 | }; |
113 | ||
dfeec247 | 114 | arg.cast_to(Uniform { unit, total }); |
9cc50fc6 SL |
115 | } |
116 | ||
60c5eb7d | 117 | pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) |
dfeec247 | 118 | where |
94222f64 XL |
119 | Ty: TyAbiInterface<'a, C> + Copy, |
120 | C: HasDataLayout + HasTargetSpec, | |
83c7162d | 121 | { |
29967ef6 | 122 | let abi = if cx.target_spec().env == "musl" { |
a1dfa0c6 XL |
123 | ELFv2 |
124 | } else { | |
125 | match cx.data_layout().endian { | |
126 | Endian::Big => ELFv1, | |
dfeec247 | 127 | Endian::Little => ELFv2, |
a1dfa0c6 | 128 | } |
ea8adc8c XL |
129 | }; |
130 | ||
60c5eb7d XL |
131 | if !fn_abi.ret.is_ignore() { |
132 | classify_ret(cx, &mut fn_abi.ret, abi); | |
54a0048b | 133 | } |
9cc50fc6 | 134 | |
f2b60f7d | 135 | for arg in fn_abi.args.iter_mut() { |
dfeec247 XL |
136 | if arg.is_ignore() { |
137 | continue; | |
138 | } | |
60c5eb7d | 139 | classify_arg(cx, arg, abi); |
54a0048b | 140 | } |
9cc50fc6 | 141 | } |