1use rustc_abi::{
2 AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
3};
4
5use crate::callconv::{ArgAttribute, FnAbi, PassMode, TyAbiInterface};
6use crate::spec::{HasTargetSpec, RustcAbi};
7
8#[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for Flavor {
#[inline]
fn eq(&self, other: &Flavor) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
9pub(crate) enum Flavor {
10 General,
11 FastcallOrVectorcall,
12}
13
14pub(crate) struct X86Options {
15 pub flavor: Flavor,
16 pub regparm: Option<u32>,
17 pub reg_struct_return: bool,
18}
19
20pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
21where
22 Ty: TyAbiInterface<'a, C> + Copy,
23 C: HasDataLayout + HasTargetSpec,
24{
25 if !fn_abi.ret.is_ignore() {
26 if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() {
27 let t = cx.target_spec();
35 if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) {
36 let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
38 fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size });
39 } else if t.abi_return_struct_as_int
40 || opts.reg_struct_return
41 || fn_abi.ret.layout.is_complex_number(cx)
42 {
43 if fn_abi.ret.layout.is_single_fp_element(cx) {
46 match fn_abi.ret.layout.size.bytes() {
47 4 => fn_abi.ret.cast_to(Reg::f32()),
48 8 => fn_abi.ret.cast_to(Reg::f64()),
49 _ => fn_abi.ret.make_indirect(),
50 }
51 } else {
52 match fn_abi.ret.layout.size.bytes() {
53 1 => fn_abi.ret.cast_to(Reg::i8()),
54 2 => fn_abi.ret.cast_to(Reg::i16()),
55 4 => fn_abi.ret.cast_to(Reg::i32()),
56 8 => fn_abi.ret.cast_to(Reg::i64()),
57 _ => fn_abi.ret.make_indirect(),
58 }
59 }
60 } else {
61 fn_abi.ret.make_indirect();
62 }
63 } else {
64 fn_abi.ret.extend_integer_width_to(32);
65 }
66 }
67
68 for arg in fn_abi.args.iter_mut() {
69 if arg.is_ignore() || !arg.layout.is_sized() {
70 continue;
71 }
72
73 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
74 arg.make_indirect();
75 continue;
76 }
77
78 let t = cx.target_spec();
79 let align_4 = Align::from_bytes(4).unwrap();
80 let align_16 = Align::from_bytes(16).unwrap();
81
82 if arg.layout.is_aggregate() {
83 fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
98 where
99 Ty: TyAbiInterface<'a, C> + Copy,
100 {
101 match layout.backend_repr {
102 BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false,
103 BackendRepr::SimdVector { .. } => true,
104 BackendRepr::Memory { .. } => {
105 for i in 0..layout.fields.count() {
106 if contains_vector(cx, layout.field(cx, i)) {
107 return true;
108 }
109 }
110 false
111 }
112 BackendRepr::SimdScalableVector { .. } => {
113 {
::core::panicking::panic_fmt(format_args!("scalable vectors are unsupported"));
}panic!("scalable vectors are unsupported")
114 }
115 }
116 }
117
118 let byval_align = if arg.layout.align.abi < align_4 {
119 align_4
121 } else if t.is_like_darwin && contains_vector(cx, arg.layout) {
122 align_16
124 } else {
125 align_4
127 };
128
129 arg.pass_by_stack_offset(Some(byval_align));
130 } else {
131 arg.extend_integer_width_to(32);
132 }
133 }
134
135 fill_inregs(cx, fn_abi, opts, false);
136}
137
138pub(crate) fn fill_inregs<'a, Ty, C>(
139 cx: &C,
140 fn_abi: &mut FnAbi<'a, Ty>,
141 opts: X86Options,
142 rust_abi: bool,
143) where
144 Ty: TyAbiInterface<'a, C> + Copy,
145{
146 if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) {
147 return;
148 }
149 let mut free_regs = opts.regparm.unwrap_or(2).into();
160
161 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 { .. }));
164 if has_casts && rust_abi {
165 return;
166 }
167
168 for arg in fn_abi.args.iter_mut() {
169 let attrs = match arg.mode {
170 PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
171 continue;
172 }
173 PassMode::Direct(ref mut attrs) => attrs,
174 PassMode::Pair(..)
175 | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
176 | PassMode::Cast { .. } => {
177 {
::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)
178 }
179 };
180
181 let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
183 {
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);
184 if #[allow(non_exhaustive_omitted_patterns)] match unit.kind {
RegKind::Float | RegKind::Vector { .. } => true,
_ => false,
}matches!(unit.kind, RegKind::Float | RegKind::Vector { .. }) {
185 continue;
186 }
187
188 let size_in_regs = arg.layout.size.bits().div_ceil(32);
189
190 if size_in_regs == 0 {
191 continue;
192 }
193
194 if size_in_regs > free_regs {
195 break;
196 }
197
198 free_regs -= size_in_regs;
199
200 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
201 attrs.set(ArgAttribute::InReg);
202 }
203
204 if free_regs == 0 {
205 break;
206 }
207 }
208}
209
210pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
211where
212 Ty: TyAbiInterface<'a, C> + Copy,
213 C: HasDataLayout + HasTargetSpec,
214{
215 if !fn_abi.ret.is_ignore() {
219 let has_float = match fn_abi.ret.layout.backend_repr {
220 BackendRepr::Scalar(s) => #[allow(non_exhaustive_omitted_patterns)] match s.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s.primitive(), Primitive::Float(_)),
221 BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => {
222 #[allow(non_exhaustive_omitted_patterns)] match s1.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s1.primitive(), Primitive::Float(_))
223 || #[allow(non_exhaustive_omitted_patterns)] match s2.primitive() {
Primitive::Float(_) => true,
_ => false,
}matches!(s2.primitive(), Primitive::Float(_))
224 }
225 _ => false, };
227 if has_float {
228 if cx.target_spec().rustc_abi == Some(RustcAbi::X86Sse2)
229 && fn_abi.ret.layout.backend_repr.is_scalar()
230 && fn_abi.ret.layout.size.bits() <= 128
231 {
232 fn_abi.ret.cast_to(Reg::opaque_vector(fn_abi.ret.layout.size));
236 } else if fn_abi.ret.layout.size <= Primitive::Pointer(AddressSpace::ZERO).size(cx) {
237 fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
239 } else {
240 fn_abi.ret.make_indirect();
242 }
243 return;
244 }
245 }
246}