1use arrayvec::ArrayVec;
2use rustc_abi::{
3 BackendRepr, FieldsShape, Float, HasDataLayout, Integer, Numeric, Primitive, Reg, RegKind,
4 Size, TyAbiInterface,
5};
6
7use crate::callconv::{ArgAbi, ArgAttribute, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
8
9fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
10 if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr
12 && let Primitive::Int(i, signed) = scalar.primitive()
13 && !signed
14 && i.size().bits() == 32
15 && let PassMode::Direct(ref mut attrs) = arg.mode
16 {
17 attrs.ext(ArgExtension::Sext);
18 return;
19 }
20
21 arg.extend_integer_width_to(bits);
22}
23
24fn float_reg<'a, Ty, C>(cx: &C, ret: &ArgAbi<'a, Ty>, i: usize) -> Option<Reg>
25where
26 Ty: TyAbiInterface<'a, C> + Copy,
27 C: HasDataLayout,
28{
29 match ret.layout.field(cx, i).backend_repr {
30 BackendRepr::Scalar(scalar) => match scalar.primitive() {
31 Primitive::Float(float) => {
32 match float {
33 Float::F16 => None,
35 Float::F32 => Some(Reg::f32()),
36 Float::F64 => Some(Reg::f64()),
37 Float::F128 => Some(Reg::f128()),
38 Float::F16B => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`f16b` unsupported on mips64")));
}unreachable!("`f16b` unsupported on mips64"),
39 Float::PpcF128 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`ppcf128` unsupported on mips64")));
}unreachable!("`ppcf128` unsupported on mips64"),
40 }
41 }
42 _ => None,
43 },
44 _ => None,
45 }
46}
47
48fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, offset: &mut Size)
49where
50 Ty: TyAbiInterface<'a, C> + Copy,
51 C: HasDataLayout,
52{
53 if !ret.layout.is_aggregate() {
54 extend_integer_width_mips(ret, 64);
55 return;
56 }
57
58 let size = ret.layout.size;
59 let bits = size.bits();
60 if bits <= 128 {
61 if let Some(component) = ret.layout.complex_number(cx) {
63 match component {
64 Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => {
65 ret.cast_to(Reg { kind: RegKind::Integer, size });
67 }
68 _ => {
69 let reg = Reg { kind: component.reg_kind(), size: component.size() };
71 ret.cast_to(CastTarget::pair(reg, reg));
72 }
73 }
74 return;
75 }
76
77 if let FieldsShape::Arbitrary { .. } = ret.layout.fields {
82 if ret.layout.fields.count() == 1 {
83 if let Some(reg) = float_reg(cx, ret, 0) {
84 ret.cast_to_with_attrs(reg, ArgAttribute::InReg.into());
88 return;
89 }
90 } else if ret.layout.fields.count() == 2
91 && let Some(reg0) = float_reg(cx, ret, 0)
92 && let Some(reg1) = float_reg(cx, ret, 1)
93 {
94 ret.cast_to_with_attrs(CastTarget::pair(reg0, reg1), ArgAttribute::InReg.into());
95 return;
96 }
97 }
98
99 ret.cast_to(Uniform::new(Reg::i64(), size));
101 } else {
102 ret.make_indirect();
103 *offset += cx.data_layout().pointer_size();
104 }
105}
106
107fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
108where
109 Ty: TyAbiInterface<'a, C> + Copy,
110 C: HasDataLayout,
111{
112 let dl = cx.data_layout();
113 let size = arg.layout.size;
114 let mut prefix = ArrayVec::new();
115
116 let align = Ord::clamp(arg.layout.align.abi, dl.i64_align, dl.i128_align);
118 let pad_i32 = u8::from(!offset.is_aligned(align));
119
120 if !arg.layout.is_aggregate() {
121 extend_integer_width_mips(arg, 64);
122
123 if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
130 let kind = RegKind::from_primitive(scalar.primitive());
131 arg.cast_to_and_pad_i32(CastTarget::from(Reg { kind, size }), pad_i32);
132 }
133 } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
134 arg.make_indirect();
135 } else if let Some(component) = arg.layout.complex_number(cx)
136 && !#[allow(non_exhaustive_omitted_patterns)] match component {
Numeric::Float(Float::F16) => true,
_ => false,
}matches!(component, Numeric::Float(Float::F16))
137 {
138 let slot = dl.pointer_size();
139 let curr_offset = offset.align_to(align);
140
141 const NUM_ARG_SLOTS: u64 = 8;
142
143 match component {
144 Numeric::Float(Float::F16B) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Complex<f16b> is not C-compatible")));
}unreachable!("Complex<f16b> is not C-compatible"),
145 Numeric::Float(Float::F16) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("not supported on mips64")));
}unreachable!("not supported on mips64"),
146 Numeric::Float(Float::PpcF128) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("not supported on mips64")));
}unreachable!("not supported on mips64"),
147 Numeric::Float(Float::F32 | Float::F64) => {
148 if curr_offset.bytes() / slot.bytes() + 2 <= NUM_ARG_SLOTS {
150 *offset = curr_offset + slot * 2;
156 let unit = Reg { kind: RegKind::Float, size: component.size() };
157 let cast_target = CastTarget::from(Uniform::new(unit, size));
158 arg.cast_to(cast_target);
159 return;
160 }
161
162 arg.cast_to_and_pad_i32(Uniform::new(Reg::i64(), size), pad_i32);
164 }
165 Numeric::Float(Float::F128) => {
166 let reg = Reg { kind: RegKind::Float, size: arg.layout.field(cx, 0).size };
168 arg.cast_to_and_pad_i32(CastTarget::pair(reg, reg), pad_i32);
169 }
170 Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => {
171 let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size });
173 arg.cast_to(cast_target.with_attrs(ArgAttribute::InReg.into()));
175 }
176 Numeric::Int(Integer::I64 | Integer::I128, _) => {
177 let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size });
179 arg.cast_to(cast_target);
180 }
181 }
182 } else {
183 match arg.layout.fields {
184 FieldsShape::Primitive => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
185 FieldsShape::Array { .. } => {
186 arg.make_indirect();
188 }
189 FieldsShape::Union(_) => {
190 }
192 FieldsShape::Arbitrary { .. } => {
193 let mut last_offset = Size::ZERO;
196
197 'outer: for i in 0..arg.layout.fields.count() {
198 let field = arg.layout.field(cx, i);
199 let offset = arg.layout.fields.offset(i);
200
201 if let BackendRepr::Scalar(scalar) = field.backend_repr {
203 if scalar.primitive() == Primitive::Float(Float::F64) {
204 if offset.is_aligned(dl.f64_align) {
205 if !last_offset.is_aligned(dl.f64_align) {
::core::panicking::panic("assertion failed: last_offset.is_aligned(dl.f64_align)")
};assert!(last_offset.is_aligned(dl.f64_align));
207 for _ in 0..((offset - last_offset).bits() / 64) {
208 if prefix.try_push(Reg::i64()).is_err() {
209 break 'outer;
210 }
211 }
212
213 if prefix.try_push(Reg::f64()).is_err() {
214 break;
215 }
216 last_offset = offset + Reg::f64().size;
217 }
218 }
219 }
220 }
221 }
222 };
223
224 let rest_size = size - Size::from_bytes(8) * prefix.len() as u64;
226 arg.cast_to_and_pad_i32(
227 CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)),
228 pad_i32,
229 );
230 }
231 *offset = offset.align_to(align) + size.align_to(align);
232}
233
234pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
235where
236 Ty: TyAbiInterface<'a, C> + Copy,
237 C: HasDataLayout,
238{
239 let mut offset = Size::ZERO;
242
243 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
244 classify_ret(cx, &mut fn_abi.ret, &mut offset);
245 }
246
247 for arg in fn_abi.args.iter_mut() {
248 if arg.is_ignore() || !arg.layout.is_sized() {
249 continue;
250 }
251 classify_arg(cx, arg, &mut offset);
252 }
253}