rustc_target/callconv/
mips64.rs1use arrayvec::ArrayVec;
2use rustc_abi::{
3 BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
4};
5
6use crate::callconv::{ArgAbi, ArgAttribute, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
7
8fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
9 if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr
11 && let Primitive::Int(i, signed) = scalar.primitive()
12 && !signed
13 && i.size().bits() == 32
14 && let PassMode::Direct(ref mut attrs) = arg.mode
15 {
16 attrs.ext(ArgExtension::Sext);
17 return;
18 }
19
20 arg.extend_integer_width_to(bits);
21}
22
23fn float_reg<'a, Ty, C>(cx: &C, ret: &ArgAbi<'a, Ty>, i: usize) -> Option<Reg>
24where
25 Ty: TyAbiInterface<'a, C> + Copy,
26 C: HasDataLayout,
27{
28 match ret.layout.field(cx, i).backend_repr {
29 BackendRepr::Scalar(scalar) => match scalar.primitive() {
30 Primitive::Float(float) => {
31 match float {
32 Float::F16 => None,
34 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"),
35 Float::F32 => Some(Reg::f32()),
36 Float::F64 => Some(Reg::f64()),
37 Float::F128 => Some(Reg::f128()),
38 }
39 }
40 _ => None,
41 },
42 _ => None,
43 }
44}
45
46fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, offset: &mut Size)
47where
48 Ty: TyAbiInterface<'a, C> + Copy,
49 C: HasDataLayout,
50{
51 if !ret.layout.is_aggregate() {
52 extend_integer_width_mips(ret, 64);
53 return;
54 }
55
56 let size = ret.layout.size;
57 let bits = size.bits();
58 if bits <= 128 {
59 if let FieldsShape::Arbitrary { .. } = ret.layout.fields {
64 if ret.layout.fields.count() == 1 {
65 if let Some(reg) = float_reg(cx, ret, 0) {
66 ret.cast_to_with_attrs(reg, ArgAttribute::InReg.into());
70 return;
71 }
72 } else if ret.layout.fields.count() == 2
73 && let Some(reg0) = float_reg(cx, ret, 0)
74 && let Some(reg1) = float_reg(cx, ret, 1)
75 {
76 ret.cast_to_with_attrs(CastTarget::pair(reg0, reg1), ArgAttribute::InReg.into());
77 return;
78 }
79 }
80
81 ret.cast_to(Uniform::new(Reg::i64(), size));
83 } else {
84 ret.make_indirect();
85 *offset += cx.data_layout().pointer_size();
86 }
87}
88
89fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
90where
91 Ty: TyAbiInterface<'a, C> + Copy,
92 C: HasDataLayout,
93{
94 let dl = cx.data_layout();
95 let size = arg.layout.size;
96 let mut prefix = ArrayVec::new();
97
98 let align = Ord::clamp(arg.layout.align.abi, dl.i64_align, dl.i128_align);
100 let pad_i32 = u8::from(!offset.is_aligned(align));
101
102 if !arg.layout.is_aggregate() {
103 extend_integer_width_mips(arg, 64);
104 } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
105 arg.make_indirect();
106 } else {
107 match arg.layout.fields {
108 FieldsShape::Primitive => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
109 FieldsShape::Array { .. } => {
110 arg.make_indirect();
112 }
113 FieldsShape::Union(_) => {
114 }
116 FieldsShape::Arbitrary { .. } => {
117 let mut last_offset = Size::ZERO;
120
121 'outer: for i in 0..arg.layout.fields.count() {
122 let field = arg.layout.field(cx, i);
123 let offset = arg.layout.fields.offset(i);
124
125 if let BackendRepr::Scalar(scalar) = field.backend_repr {
127 if scalar.primitive() == Primitive::Float(Float::F64) {
128 if offset.is_aligned(dl.f64_align) {
129 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));
131 for _ in 0..((offset - last_offset).bits() / 64) {
132 if prefix.try_push(Reg::i64()).is_err() {
133 break 'outer;
134 }
135 }
136
137 if prefix.try_push(Reg::f64()).is_err() {
138 break;
139 }
140 last_offset = offset + Reg::f64().size;
141 }
142 }
143 }
144 }
145 }
146 };
147
148 let rest_size = size - Size::from_bytes(8) * prefix.len() as u64;
150 arg.cast_to_and_pad_i32(
151 CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)),
152 pad_i32,
153 );
154 }
155 *offset = offset.align_to(align) + size.align_to(align);
156}
157
158pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
159where
160 Ty: TyAbiInterface<'a, C> + Copy,
161 C: HasDataLayout,
162{
163 let mut offset = Size::ZERO;
166
167 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
168 classify_ret(cx, &mut fn_abi.ret, &mut offset);
169 }
170
171 for arg in fn_abi.args.iter_mut() {
172 if arg.is_ignore() || !arg.layout.is_sized() {
173 continue;
174 }
175 classify_arg(cx, arg, &mut offset);
176 }
177}