1use arrayvec::ArrayVec;
2use rustc_abi::{
3 Align, BackendRepr, FieldsShape, Float, HasDataLayout, Integer, Numeric, Primitive, Reg,
4 RegKind, Size, TyAbiInterface, TyAndLayout, Variants,
5};
6
7use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform};
8use crate::spec::{HasTargetSpec, Os};
9
10#[derive(#[automatically_derived]
impl ::core::marker::Copy for DoubleWord { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DoubleWord { }
#[automatically_derived]
impl ::core::clone::Clone for DoubleWord {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<[Word; 2]>;
*self
}
}Clone)]
14enum DoubleWord {
15 F64,
16 F128Start,
17 F128End,
18 Words([Word; 2]),
19}
20
21#[derive(#[automatically_derived]
impl ::core::marker::Copy for Word { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Word { }
#[automatically_derived]
impl ::core::clone::Clone for Word {
#[inline]
fn clone(&self) -> Self { *self }
}Clone)]
22enum Word {
23 F32,
24 Integer,
25}
26
27fn classify<'a, Ty, C>(
28 cx: &C,
29 arg_layout: &TyAndLayout<'a, Ty>,
30 offset: Size,
31 double_words: &mut [DoubleWord; 4],
32) where
33 Ty: TyAbiInterface<'a, C> + Copy,
34 C: HasDataLayout,
35{
36 match arg_layout.backend_repr {
40 BackendRepr::Scalar(scalar) => match scalar.primitive() {
41 Primitive::Float(float) => {
42 if offset.is_aligned(Ord::min(*float.align(cx), Align::EIGHT)) {
43 let index = offset.bytes_usize() / 8;
44 match float {
45 Float::F128 => {
46 double_words[index] = DoubleWord::F128Start;
47 double_words[index + 1] = DoubleWord::F128End;
48 }
49 Float::F64 => {
50 double_words[index] = DoubleWord::F64;
51 }
52 Float::F32 => match &mut double_words[index] {
53 DoubleWord::Words(words) => {
54 words[(offset.bytes_usize() % 8) / 4] = Word::F32;
55 }
56 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
57 },
58 Float::F16 => {
59 }
61 Float::F16B => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`f16b` unsupported on sparc64")));
}unreachable!("`f16b` unsupported on sparc64"),
62 Float::PpcF128 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`ppcf128` unsupported on sparc64")));
}unreachable!("`ppcf128` unsupported on sparc64"),
63 }
64 } else {
65 }
67 }
68 Primitive::Int(_, _) | Primitive::Pointer(_) => { }
69 },
70 BackendRepr::SimdVector { .. } => {}
71 BackendRepr::SimdScalableVector { .. } => {}
72 BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields {
73 FieldsShape::Primitive => {
74 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("aggregates can\'t have `FieldsShape::Primitive`")));
}unreachable!("aggregates can't have `FieldsShape::Primitive`")
75 }
76 FieldsShape::Union(_) => {
77 if !arg_layout.is_zst() {
78 if arg_layout.is_transparent() {
79 let non_1zst_elem = arg_layout.non_1zst_field(cx).expect("not exactly one non-1-ZST field in non-ZST repr(transparent) union").1;
80 classify(cx, &non_1zst_elem, offset, double_words);
81 }
82 }
83 }
84 FieldsShape::Array { .. } => {}
85 FieldsShape::Arbitrary { .. } => match arg_layout.variants {
86 Variants::Multiple { .. } => {}
87 Variants::Single { .. } | Variants::Empty => {
88 for i in arg_layout.fields.index_by_increasing_offset() {
92 classify(
93 cx,
94 &arg_layout.field(cx, i),
95 offset + arg_layout.fields.offset(i),
96 double_words,
97 );
98 }
99 }
100 },
101 },
102 }
103}
104
105fn classify_arg<'a, Ty, C>(
106 cx: &C,
107 arg: &mut ArgAbi<'a, Ty>,
108 in_registers_max: Size,
109 total_double_word_count: &mut usize,
110) where
111 Ty: TyAbiInterface<'a, C> + Copy,
112 C: HasDataLayout,
113{
114 let pad = !total_double_word_count.is_multiple_of(2) && arg.layout.align.abi.bytes() == 16;
122 let double_word_count = arg.layout.size.bytes_usize().div_ceil(8);
124 let start_double_word_count = *total_double_word_count + usize::from(pad);
126
127 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
128 arg.make_indirect();
129 *total_double_word_count += 1;
130 return;
131 }
132
133 if !arg.layout.is_aggregate() {
134 arg.extend_integer_width_to(64);
135 *total_double_word_count = start_double_word_count + double_word_count;
136 return;
137 }
138
139 let total = arg.layout.size;
140 if total > in_registers_max {
141 arg.make_indirect();
142 *total_double_word_count += 1;
143 return;
144 }
145
146 *total_double_word_count = start_double_word_count + double_word_count;
147
148 if let Some(Numeric::Int(Integer::I8 | Integer::I16, _)) = arg.layout.complex_number(cx) {
150 arg.cast_to(Reg { kind: RegKind::Integer, size: total });
151 return;
152 }
153
154 const ARGUMENT_REGISTERS: usize = 8;
155
156 let mut double_words = [DoubleWord::Words([Word::Integer; 2]); ARGUMENT_REGISTERS / 2];
157 classify(cx, &arg.layout, Size::ZERO, &mut double_words);
158
159 let mut regs = ArrayVec::new();
160 let mut attrs = ArgAttribute::empty();
161
162 for (index, double_word) in double_words.into_iter().enumerate() {
163 if arg.layout.size.bytes_usize() <= index * 8 {
164 break;
165 }
166 match double_word {
167 DoubleWord::F128Start if (start_double_word_count + index).is_multiple_of(2) => {
169 regs.push(Reg::f128());
170 }
171 DoubleWord::F128Start => {
172 regs.push(Reg::i64());
178 regs.push(Reg::i64());
179 }
180 DoubleWord::F128End => {} DoubleWord::F64 => regs.push(Reg::f64()),
182 DoubleWord::Words([Word::Integer, Word::Integer]) => regs.push(Reg::i64()),
183 DoubleWord::Words(words) => {
184 attrs |= ArgAttribute::InReg;
185 for word in words {
186 match word {
187 Word::F32 => regs.push(Reg::f32()),
188 Word::Integer => regs.push(Reg::i32()),
189 }
190 }
191 }
192 }
193 }
194
195 let cast_target = match regs.as_slice() {
196 [reg] => CastTarget::from(*reg),
198 _ => CastTarget::prefixed(regs, Uniform::new(Reg::i8(), Size::ZERO)),
199 };
200
201 arg.cast_to_and_pad_i32(cast_target.with_attrs(attrs.into()), u8::from(pad));
202}
203
204pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
205where
206 Ty: TyAbiInterface<'a, C> + Copy,
207 C: HasDataLayout + HasTargetSpec,
208{
209 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
210 classify_arg(cx, &mut fn_abi.ret, Size::from_bytes(32), &mut 0);
212 }
213
214 let passes_zsts = #[allow(non_exhaustive_omitted_patterns)] match cx.target_spec().os {
Os::Linux => true,
_ => false,
}matches!(cx.target_spec().os, Os::Linux);
216
217 let mut double_word_count = 0;
218 for arg in fn_abi.args.iter_mut() {
219 if !arg.layout.is_sized() {
220 continue;
221 }
222 if arg.is_ignore() {
223 if passes_zsts && arg.layout.is_repr_c() {
224 arg.make_indirect_from_ignore();
225 double_word_count += 1;
226 }
227 continue;
228 }
229 classify_arg(cx, arg, Size::from_bytes(16), &mut double_word_count);
231 }
232}