1use rustc_abi::{
2 AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
3};
4
5use crate::callconv::{ArgAbi, ArgAttribute, FnAbi, PassMode, TyAbiInterface};
6use crate::spec::{HasTargetSpec, RustcAbi};
7
8fn is_single_fp_element<'a, Ty, C>(mut layout: TyAndLayout<'a, Ty>, cx: &C) -> bool
10where
11 Ty: TyAbiInterface<'a, C> + Copy,
12 C: HasDataLayout,
13{
14 let outer_size = layout.layout.size();
16
17 loop {
18 layout = layout.peel_transparent_wrappers_from_non_1zst(cx);
20
21 return match layout.backend_repr {
22 BackendRepr::Scalar(scalar) => match scalar.primitive() {
23 Primitive::Float(float) => float.size() == outer_size,
24 Primitive::Int(_, _) | Primitive::Pointer(_) => false,
25 },
26 BackendRepr::Memory { .. } => {
27 if let Some((_idx, field)) = layout.non_zst_field_ignore_alignment(cx) {
29 layout = field;
31 continue;
32 } else {
33 false
34 }
35 }
36 _ => false,
37 };
38 }
39}
40
41#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Flavor { }
#[automatically_derived]
impl ::core::clone::Clone for Flavor {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Option<u32>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Flavor { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Flavor { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Flavor {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::General { regparam: __self_0 }, Self::General {
regparam: __arg1_0 }) => __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq)]
42pub(crate) enum Flavor {
43 General { regparam: Option<u32> },
44 FastcallOrVectorcall,
45}
46
47#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for X86Options { }
#[automatically_derived]
impl ::core::clone::Clone for X86Options {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Flavor>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for X86Options { }Copy)]
48pub(crate) struct X86Options {
49 pub flavor: Flavor,
50 pub reg_struct_return: bool,
51}
52
53fn classify_ret<'a, Ty, C>(cx: &C, opts: X86Options, ret: &mut ArgAbi<'a, Ty>)
54where
55 Ty: TyAbiInterface<'a, C> + Copy,
56 C: HasDataLayout + HasTargetSpec,
57{
58 if ret.layout.is_aggregate() && ret.layout.is_sized() {
59 let t = cx.target_spec();
67 if let Some(Float::F16) = ret.layout.complex_float(cx) {
68 let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
70 ret.cast_to(Reg { kind, size: ret.layout.size });
71 } else if t.abi_return_struct_as_int
72 || opts.reg_struct_return
73 || ret.layout.is_complex_number(cx)
74 {
75 if is_single_fp_element(ret.layout, cx) {
78 match ret.layout.size.bytes() {
79 2 => ret.cast_to(Reg::f16()),
80 4 => ret.cast_to(Reg::f32()),
81 8 => ret.cast_to(Reg::f64()),
82 _ => ret.make_indirect(),
83 }
84 } else {
85 match ret.layout.size.bytes() {
86 1 => ret.cast_to(Reg::i8()),
87 2 => ret.cast_to(Reg::i16()),
88 4 => ret.cast_to(Reg::i32()),
89 8 => ret.cast_to(Reg::i64()),
90 _ => ret.make_indirect(),
91 }
92 }
93 } else {
94 ret.make_indirect();
95 }
96 } else {
97 ret.extend_integer_width_to(32);
98 }
99}
100
101fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
102where
103 Ty: TyAbiInterface<'a, C> + Copy,
104 C: HasDataLayout + HasTargetSpec,
105{
106 let t = cx.target_spec();
107 let align_4 = Align::from_bytes(4).unwrap();
108 let align_16 = Align::from_bytes(16).unwrap();
109
110 if arg.layout.is_aggregate() {
111 fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
126 where
127 Ty: TyAbiInterface<'a, C> + Copy,
128 {
129 match layout.backend_repr {
130 BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false,
131 BackendRepr::SimdVector { .. } => true,
132 BackendRepr::Memory { .. } => {
133 for i in 0..layout.fields.count() {
134 if contains_vector(cx, layout.field(cx, i)) {
135 return true;
136 }
137 }
138 false
139 }
140 BackendRepr::SimdScalableVector { .. } => {
141 {
::core::panicking::panic_fmt(format_args!("scalable vectors are unsupported"));
}panic!("scalable vectors are unsupported")
142 }
143 }
144 }
145
146 let byval_align = if arg.layout.align.abi < align_4 {
147 align_4
149 } else if t.is_like_darwin && contains_vector(cx, arg.layout) {
150 align_16
152 } else {
153 align_4
155 };
156
157 arg.pass_by_stack_offset(Some(byval_align));
158 } else {
159 arg.extend_integer_width_to(32);
160 }
161}
162
163pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
164where
165 Ty: TyAbiInterface<'a, C> + Copy,
166 C: HasDataLayout + HasTargetSpec,
167{
168 if !fn_abi.ret.is_ignore() {
169 classify_ret(cx, opts, &mut fn_abi.ret);
170 }
171
172 for arg in fn_abi.args.iter_mut() {
173 if arg.is_ignore() || !arg.layout.is_sized() {
174 continue;
175 }
176
177 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
178 arg.make_indirect();
179 continue;
180 }
181
182 classify_arg(cx, arg);
183 }
184
185 fill_inregs(cx, fn_abi, opts, false);
186}
187
188pub(crate) fn fill_inregs<'a, Ty, C>(
189 cx: &C,
190 fn_abi: &mut FnAbi<'a, Ty>,
191 opts: X86Options,
192 rust_abi: bool,
193) where
194 Ty: TyAbiInterface<'a, C> + Copy,
195{
196 let mut free_regs = match opts.flavor {
214 _ if fn_abi.c_variadic => 0,
215 Flavor::FastcallOrVectorcall => 2,
216 Flavor::General { regparam } => u64::from(regparam.unwrap_or(0)),
217 };
218
219 if free_regs == 0 {
220 return;
221 }
222
223 let has_casts = fn_abi.args.iter().any(|arg| #[allow(non_exhaustive_omitted_patterns)] match arg.mode {
PassMode::Cast { .. } => true,
_ => false,
}matches!(arg.mode, PassMode::Cast { .. }));
226 if has_casts && rust_abi {
227 return;
228 }
229
230 for arg in fn_abi.args.iter_mut() {
231 let attrs = match arg.mode {
232 PassMode::Ignore | PassMode::Indirect { attrs: _, address_space: _, mode: _ } => {
233 continue;
234 }
235 PassMode::Direct(ref mut attrs) => attrs,
236 PassMode::Pair(..)
237 | PassMode::IndirectUnsized { attrs: _, meta_attrs: _ }
238 | PassMode::Cast { .. } => {
239 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("x86 shouldn\'t be passing arguments by {0:?}",
arg.mode)));
}unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
240 }
241 };
242
243 let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
245 {
match (&unit.size, &arg.layout.size) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(unit.size, arg.layout.size);
246 if #[allow(non_exhaustive_omitted_patterns)] match unit.kind {
RegKind::Float | RegKind::Vector { .. } => true,
_ => false,
}matches!(unit.kind, RegKind::Float | RegKind::Vector { .. }) {
247 continue;
248 }
249
250 let size_in_regs = arg.layout.size.bits().div_ceil(32);
251
252 if size_in_regs == 0 {
253 continue;
254 }
255
256 if size_in_regs > free_regs {
257 break;
258 }
259
260 free_regs -= size_in_regs;
261
262 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
263 attrs.set(ArgAttribute::InReg);
264 }
265
266 if free_regs == 0 {
267 break;
268 }
269 }
270}
271
272pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
273where
274 Ty: TyAbiInterface<'a, C> + Copy,
275 C: HasDataLayout + HasTargetSpec,
276{
277 if !fn_abi.ret.is_ignore() {
281 let has_float = match fn_abi.ret.layout.backend_repr {
282 BackendRepr::Scalar(s) => #[allow(non_exhaustive_omitted_patterns)] match s.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s.primitive(), Primitive::Float(_)),
283 BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => {
284 #[allow(non_exhaustive_omitted_patterns)] match s1.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s1.primitive(), Primitive::Float(_))
285 || #[allow(non_exhaustive_omitted_patterns)] match s2.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s2.primitive(), Primitive::Float(_))
286 }
287 _ => false, };
289 if has_float {
290 if cx.target_spec().rustc_abi == Some(RustcAbi::X86Sse2)
291 && fn_abi.ret.layout.backend_repr.is_scalar()
292 && fn_abi.ret.layout.size.bits() <= 128
293 {
294 fn_abi.ret.cast_to(Reg::opaque_vector(fn_abi.ret.layout.size));
298 } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::ZERO).size(cx) {
299 fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
301 } else {
302 fn_abi.ret.make_indirect();
304 }
305 return;
306 }
307 }
308}