1use rustc_abi::{
2 Align, BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
3 TyAndLayout, Variants,
4};
5
6use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform};
7use crate::spec::{HasTargetSpec, Os};
8
9#[derive(#[automatically_derived]
impl ::core::marker::Copy for DoubleWord { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DoubleWord {
#[inline]
fn clone(&self) -> DoubleWord {
let _: ::core::clone::AssertParamIsClone<[Word; 2]>;
*self
}
}Clone)]
13enum DoubleWord {
14 F64,
15 F128Start,
16 F128End,
17 Words([Word; 2]),
18}
19
20#[derive(#[automatically_derived]
impl ::core::marker::Copy for Word { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Word {
#[inline]
fn clone(&self) -> Word { *self }
}Clone)]
21enum Word {
22 F32,
23 Integer,
24}
25
26fn classify<'a, Ty, C>(
27 cx: &C,
28 arg_layout: &TyAndLayout<'a, Ty>,
29 offset: Size,
30 double_words: &mut [DoubleWord; 4],
31) where
32 Ty: TyAbiInterface<'a, C> + Copy,
33 C: HasDataLayout,
34{
35 match arg_layout.backend_repr {
39 BackendRepr::Scalar(scalar) => match scalar.primitive() {
40 Primitive::Float(float) => {
41 if offset.is_aligned(Ord::min(*float.align(cx), Align::EIGHT)) {
42 let index = offset.bytes_usize() / 8;
43 match float {
44 Float::F128 => {
45 double_words[index] = DoubleWord::F128Start;
46 double_words[index + 1] = DoubleWord::F128End;
47 }
48 Float::F64 => {
49 double_words[index] = DoubleWord::F64;
50 }
51 Float::F32 => match &mut double_words[index] {
52 DoubleWord::Words(words) => {
53 words[(offset.bytes_usize() % 8) / 4] = Word::F32;
54 }
55 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
56 },
57 Float::F16 => {
58 }
60 }
61 } else {
62 }
64 }
65 Primitive::Int(_, _) | Primitive::Pointer(_) => { }
66 },
67 BackendRepr::SimdVector { .. } => {}
68 BackendRepr::ScalableVector { .. } => {}
69 BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
70 FieldsShape::Primitive => {
71 {
::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`")
72 }
73 FieldsShape::Union(_) => {
74 if !arg_layout.is_zst() {
75 if arg_layout.is_transparent() {
76 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;
77 classify(cx, &non_1zst_elem, offset, double_words);
78 }
79 }
80 }
81 FieldsShape::Array { .. } => {}
82 FieldsShape::Arbitrary { .. } => match arg_layout.variants {
83 Variants::Multiple { .. } => {}
84 Variants::Single { .. } | Variants::Empty => {
85 for i in arg_layout.fields.index_by_increasing_offset() {
89 classify(
90 cx,
91 &arg_layout.field(cx, i),
92 offset + arg_layout.fields.offset(i),
93 double_words,
94 );
95 }
96 }
97 },
98 },
99 }
100}
101
102fn classify_arg<'a, Ty, C>(
103 cx: &C,
104 arg: &mut ArgAbi<'a, Ty>,
105 in_registers_max: Size,
106 total_double_word_count: &mut usize,
107) where
108 Ty: TyAbiInterface<'a, C> + Copy,
109 C: HasDataLayout,
110{
111 let pad = !total_double_word_count.is_multiple_of(2) && arg.layout.align.abi.bytes() == 16;
119 let double_word_count = arg.layout.size.bytes_usize().div_ceil(8);
121 let start_double_word_count = *total_double_word_count + usize::from(pad);
123
124 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
125 arg.make_indirect();
126 *total_double_word_count += 1;
127 return;
128 }
129
130 if !arg.layout.is_aggregate() {
131 arg.extend_integer_width_to(64);
132 *total_double_word_count = start_double_word_count + double_word_count;
133 return;
134 }
135
136 let total = arg.layout.size;
137 if total > in_registers_max {
138 arg.make_indirect();
139 *total_double_word_count += 1;
140 return;
141 }
142
143 *total_double_word_count = start_double_word_count + double_word_count;
144
145 const ARGUMENT_REGISTERS: usize = 8;
146
147 let mut double_words = [DoubleWord::Words([Word::Integer; 2]); ARGUMENT_REGISTERS / 2];
148 classify(cx, &arg.layout, Size::ZERO, &mut double_words);
149
150 let mut regs = [None; ARGUMENT_REGISTERS];
151 let mut i = 0;
152 let mut push = |reg| {
153 regs[i] = Some(reg);
154 i += 1;
155 };
156 let mut attrs = ArgAttribute::empty();
157
158 for (index, double_word) in double_words.into_iter().enumerate() {
159 if arg.layout.size.bytes_usize() <= index * 8 {
160 break;
161 }
162 match double_word {
163 DoubleWord::F128Start if (start_double_word_count + index).is_multiple_of(2) => {
165 push(Reg::f128());
166 }
167 DoubleWord::F128Start => {
168 push(Reg::i64());
174 push(Reg::i64());
175 }
176 DoubleWord::F128End => {} DoubleWord::F64 => push(Reg::f64()),
178 DoubleWord::Words([Word::Integer, Word::Integer]) => push(Reg::i64()),
179 DoubleWord::Words(words) => {
180 attrs |= ArgAttribute::InReg;
181 for word in words {
182 match word {
183 Word::F32 => push(Reg::f32()),
184 Word::Integer => push(Reg::i32()),
185 }
186 }
187 }
188 }
189 }
190
191 let cast_target = match regs {
192 [Some(reg), None, rest @ ..] => {
193 if true {
if !rest.iter().all(|x| x.is_none()) {
::core::panicking::panic("assertion failed: rest.iter().all(|x| x.is_none())")
};
};debug_assert!(rest.iter().all(|x| x.is_none()));
195 CastTarget::from(reg)
196 }
197 _ => CastTarget::prefixed(regs, Uniform::new(Reg::i8(), Size::ZERO)),
198 };
199
200 arg.cast_to_and_pad_i32(cast_target.with_attrs(attrs.into()), pad);
201}
202
203pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
204where
205 Ty: TyAbiInterface<'a, C> + Copy,
206 C: HasDataLayout + HasTargetSpec,
207{
208 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
209 classify_arg(cx, &mut fn_abi.ret, Size::from_bytes(32), &mut 0);
211 }
212
213 let passes_zsts = #[allow(non_exhaustive_omitted_patterns)] match cx.target_spec().os {
Os::Linux => true,
_ => false,
}matches!(cx.target_spec().os, Os::Linux);
215
216 let mut double_word_count = 0;
217 for arg in fn_abi.args.iter_mut() {
218 if !arg.layout.is_sized() {
219 continue;
220 }
221 if arg.is_ignore() {
222 if passes_zsts && arg.layout.is_zst() {
223 arg.make_indirect_from_ignore();
224 double_word_count += 1;
225 }
226 continue;
227 }
228 classify_arg(cx, arg, Size::from_bytes(16), &mut double_word_count);
230 }
231}