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