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, 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::F32) => Some(Reg::f32()),
31 Primitive::Float(Float::F64) => Some(Reg::f64()),
32 _ => None,
33 },
34 _ => None,
35 }
36}
37
38fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, offset: &mut Size)
39where
40 Ty: TyAbiInterface<'a, C> + Copy,
41 C: HasDataLayout,
42{
43 if !ret.layout.is_aggregate() {
44 extend_integer_width_mips(ret, 64);
45 return;
46 }
47
48 let size = ret.layout.size;
49 let bits = size.bits();
50 if bits <= 128 {
51 if let FieldsShape::Arbitrary { .. } = ret.layout.fields {
56 if ret.layout.fields.count() == 1 {
57 if let Some(reg) = float_reg(cx, ret, 0) {
58 ret.cast_to(reg);
59 return;
60 }
61 } else if ret.layout.fields.count() == 2
62 && let Some(reg0) = float_reg(cx, ret, 0)
63 && let Some(reg1) = float_reg(cx, ret, 1)
64 {
65 ret.cast_to(CastTarget::pair(reg0, reg1));
66 return;
67 }
68 }
69
70 ret.cast_to(Uniform::new(Reg::i64(), size));
72 } else {
73 ret.make_indirect();
74 *offset += cx.data_layout().pointer_size();
75 }
76}
77
78fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size)
79where
80 Ty: TyAbiInterface<'a, C> + Copy,
81 C: HasDataLayout,
82{
83 let dl = cx.data_layout();
84 let size = arg.layout.size;
85 let mut prefix = ArrayVec::new();
86
87 let align = Ord::clamp(arg.layout.align.abi, dl.i64_align, dl.i128_align);
89 let pad_i32 = !offset.is_aligned(align);
90
91 if !arg.layout.is_aggregate() {
92 extend_integer_width_mips(arg, 64);
93 } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
94 arg.make_indirect();
95 } else {
96 match arg.layout.fields {
97 FieldsShape::Primitive => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
98 FieldsShape::Array { .. } => {
99 arg.make_indirect();
101 }
102 FieldsShape::Union(_) => {
103 }
105 FieldsShape::Arbitrary { .. } => {
106 let mut last_offset = Size::ZERO;
109
110 'outer: for i in 0..arg.layout.fields.count() {
111 let field = arg.layout.field(cx, i);
112 let offset = arg.layout.fields.offset(i);
113
114 if let BackendRepr::Scalar(scalar) = field.backend_repr {
116 if scalar.primitive() == Primitive::Float(Float::F64) {
117 if offset.is_aligned(dl.f64_align) {
118 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));
120 for _ in 0..((offset - last_offset).bits() / 64) {
121 if prefix.try_push(Reg::i64()).is_err() {
122 break 'outer;
123 }
124 }
125
126 if prefix.try_push(Reg::f64()).is_err() {
127 break;
128 }
129 last_offset = offset + Reg::f64().size;
130 }
131 }
132 }
133 }
134 }
135 };
136
137 let rest_size = size - Size::from_bytes(8) * prefix.len() as u64;
139 arg.cast_to_and_pad_i32(
140 CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)),
141 pad_i32,
142 );
143 }
144 *offset = offset.align_to(align) + size.align_to(align);
145}
146
147pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
148where
149 Ty: TyAbiInterface<'a, C> + Copy,
150 C: HasDataLayout,
151{
152 let mut offset = Size::ZERO;
155
156 if !fn_abi.ret.is_ignore() && fn_abi.ret.layout.is_sized() {
157 classify_ret(cx, &mut fn_abi.ret, &mut offset);
158 }
159
160 for arg in fn_abi.args.iter_mut() {
161 if arg.is_ignore() || !arg.layout.is_sized() {
162 continue;
163 }
164 classify_arg(cx, arg, &mut offset);
165 }
166}