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::X87F80 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`x87_f80` unsupported on mips64")));
}unreachable!("`x87_f80` unsupported on mips64"),
40 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"),
41 }
42 }
43 _ => None,
44 },
45 _ => None,
46 }
47}
48
49fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, offset: &mut Size)
50where
51 Ty: TyAbiInterface<'a, C> + Copy,
52 C: HasDataLayout,
53{
54 if !ret.layout.is_aggregate() {
55 extend_integer_width_mips(ret, 64);
56 return;
57 }
58
59 let size = ret.layout.size;
60 let bits = size.bits();
61 if bits <= 128 {
62 if let Some(component) = ret.layout.complex_number(cx) {
64 match component {
65 Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => {
66 ret.cast_to(Reg { kind: RegKind::Integer, size });
68 }
69 _ => {
70 let reg = Reg { kind: component.reg_kind(), size: component.size() };
72 ret.cast_to(CastTarget::pair(reg, reg));
73 }
74 }
75 return;
76 }
77
78 if let FieldsShape::Arbitrary { .. } = ret.layout.fields {
83 if ret.layout.fields.count() == 1 {
84 if let Some(reg) = float_reg(cx, ret, 0) {
85 ret.cast_to_with_attrs(reg, ArgAttribute::InReg.into());
89 return;
90 }
91 } else if ret.layout.fields.count() == 2
92 && let Some(reg0) = float_reg(cx, ret, 0)
93 && let Some(reg1) = float_reg(cx, ret, 1)
94 {
95 ret.cast_to_with_attrs(CastTarget::pair(reg0, reg1), ArgAttribute::InReg.into());
96 return;
97 }
98 }
99
100 ret.cast_to(Uniform::new(Reg::i64(), size));
102 } else {
103 ret.make_indirect();
104 *offset += cx.data_layout().pointer_size();
105 }
106}
107
108fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
109where
110 Ty: TyAbiInterface<'a, C> + Copy,
111 C: HasDataLayout,
112{
113 let dl = cx.data_layout();
114 let size = arg.layout.size;
115 let mut prefix = ArrayVec::new();
116
117 let align = Ord::clamp(arg.layout.align, dl.i64_align, dl.i128_align);
119 let pad_i32 = u8::from(!offset.is_aligned(align));
120
121 if !arg.layout.is_aggregate() {
122 extend_integer_width_mips(arg, 64);
123
124 if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
131 let kind = RegKind::from_primitive(scalar.primitive());
132 arg.cast_to_and_pad_i32(CastTarget::from(Reg { kind, size }), pad_i32);
133 }
134 } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
135 arg.make_indirect();
136 } else if let Some(component) = arg.layout.complex_number(cx)
137 && !#[allow(non_exhaustive_omitted_patterns)] match component {
Numeric::Float(Float::F16) => true,
_ => false,
}matches!(component, Numeric::Float(Float::F16))
138 {
139 let slot = dl.pointer_size();
140 let curr_offset = offset.align_to(align);
141
142 const NUM_ARG_SLOTS: u64 = 8;
143
144 match component {
145 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"),
146 Numeric::Float(Float::F16 | Float::X87F80 | Float::PpcF128) => {
147 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("not supported on mips64")));
}unreachable!("not supported on mips64")
148 }
149 Numeric::Float(Float::F32 | Float::F64) => {
150 if curr_offset.bytes() / slot.bytes() + 2 <= NUM_ARG_SLOTS {
152 *offset = curr_offset + slot * 2;
158 let unit = Reg { kind: RegKind::Float, size: component.size() };
159 let cast_target = CastTarget::from(Uniform::new(unit, size));
160 arg.cast_to(cast_target);
161 return;
162 }
163
164 arg.cast_to_and_pad_i32(Uniform::new(Reg::i64(), size), pad_i32);
166 }
167 Numeric::Float(Float::F128) => {
168 let reg = Reg { kind: RegKind::Float, size: arg.layout.field(cx, 0).size };
170 arg.cast_to_and_pad_i32(CastTarget::pair(reg, reg), pad_i32);
171 }
172 Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => {
173 let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size });
175 arg.cast_to(cast_target.with_attrs(ArgAttribute::InReg.into()));
177 }
178 Numeric::Int(Integer::I64 | Integer::I128, _) => {
179 let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size });
181 arg.cast_to(cast_target);
182 }
183 }
184 } else {
185 match arg.layout.fields {
186 FieldsShape::Primitive => ::core::panicking::unreachable_default_msg()unreachable!(),
187 FieldsShape::Array { .. } => {
188 arg.make_indirect();
190 }
191 FieldsShape::Union(_) => {
192 }
194 FieldsShape::Arbitrary { .. } => {
195 let mut last_offset = Size::ZERO;
198
199 'outer: for i in 0..arg.layout.fields.count() {
200 let field = arg.layout.field(cx, i);
201 let offset = arg.layout.fields.offset(i);
202
203 if let BackendRepr::Scalar(scalar) = field.backend_repr {
205 if scalar.primitive() == Primitive::Float(Float::F64) {
206 if offset.is_aligned(dl.f64_align) {
207 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));
209 for _ in 0..((offset - last_offset).bits() / 64) {
210 if prefix.try_push(Reg::i64()).is_err() {
211 break 'outer;
212 }
213 }
214
215 if prefix.try_push(Reg::f64()).is_err() {
216 break;
217 }
218 last_offset = offset + Reg::f64().size;
219 }
220 }
221 }
222 }
223 }
224 };
225
226 let rest_size = size - Size::from_bytes(8) * prefix.len() as u64;
228 arg.cast_to_and_pad_i32(
229 CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)),
230 pad_i32,
231 );
232 }
233 *offset = offset.align_to(align) + size.align_to(align);
234}
235
236pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
237where
238 Ty: TyAbiInterface<'a, C> + Copy,
239 C: HasDataLayout,
240{
241 let mut offset = Size::ZERO;
244
245 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
246 classify_ret(cx, &mut fn_abi.ret, &mut offset);
247 }
248
249 for arg in fn_abi.args.iter_mut() {
250 if arg.is_ignore() || !arg.layout.is_sized() {
251 continue;
252 }
253 classify_arg(cx, arg, &mut offset);
254 }
255}