1use rustc_abi::{
5 BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface, TyAndLayout,
6 Variants,
7};
8
9use crate::callconv::{ArgAbi, CastTarget, FnAbi};
10use crate::spec::HasTargetSpec;
11
12#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for Class {
}
#[automatically_derived]impl ::core::clone::Clone for Class {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for Class { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for Class { }
#[automatically_derived]impl ::core::cmp::PartialEq for Class {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for Class { }Eq, #[automatically_derived]impl ::core::cmp::PartialOrd for Class {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]impl ::core::cmp::Ord for Class {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&::core::intrinsics::discriminant_value(self),
&::core::intrinsics::discriminant_value(other))
}
}Ord, #[automatically_derived]impl ::core::fmt::Debug for Class {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_c_like_enum_write_str(f,
"Int Sse SseUp X87 X87Up",
match self {
Class::Int => 0usize,
Class::Sse => 4usize,
Class::SseUp => 8usize,
Class::X87 => 14usize,
Class::X87Up => 18usize,
})
}
}Debug)]
17enum Class {
18 Int,
19 Sse,
20 SseUp,
21 X87,
22 X87Up,
23}
24
25impl Class {
26 fn upper_half(self) -> Class {
27 match self {
28 Class::Sse | Class::SseUp => Class::SseUp,
29 Class::X87 | Class::X87Up => Class::X87Up,
30 Class::Int => Class::Int,
31 }
32 }
33
34 fn merge(self, other: Self) -> Result<Self, Memory> {
35 match (self, other) {
36 (Class::X87 | Class::X87Up, Class::Sse | Class::SseUp) => Err(Memory),
37 (Class::Sse | Class::SseUp, Class::X87 | Class::X87Up) => Err(Memory),
38 _ => Ok(Ord::min(self, other)),
39 }
40 }
41}
42
43#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for Memory {
}
#[automatically_derived]impl ::core::clone::Clone for Memory {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for Memory { }Copy, #[automatically_derived]impl ::core::fmt::Debug for Memory {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Memory")
}
}Debug)]
44struct Memory;
45
46const LARGEST_VECTOR_SIZE: usize = 512;
48const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
49
50fn classify_arg<'a, Ty, C>(
51 cx: &C,
52 arg: &ArgAbi<'a, Ty>,
53) -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory>
54where
55 Ty: TyAbiInterface<'a, C> + Copy,
56 C: HasDataLayout,
57{
58 fn classify<'a, Ty, C>(
59 cx: &C,
60 layout: TyAndLayout<'a, Ty>,
61 cls: &mut [Option<Class>],
62 off: Size,
63 ) -> Result<(), Memory>
64 where
65 Ty: TyAbiInterface<'a, C> + Copy,
66 C: HasDataLayout,
67 {
68 if !off.is_aligned(layout.align) {
69 if !layout.is_zst() {
70 return Err(Memory);
71 }
72 return Ok(());
73 }
74
75 let mut c = match layout.backend_repr {
76 BackendRepr::Scalar(scalar) => match scalar.primitive() {
77 Primitive::Int(..) | Primitive::Pointer(_) => Class::Int,
78 Primitive::Float(Float::X87F80) => Class::X87,
79 Primitive::Float(_) => Class::Sse,
80 },
81
82 BackendRepr::SimdVector { .. } => Class::Sse,
83
84 BackendRepr::SimdScalableVector { .. } => {
::core::panicking::panic_fmt(format_args!("scalable vectors are unsupported"));
}panic!("scalable vectors are unsupported"),
85
86 BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => {
87 for i in 0..layout.fields.count() {
88 let field_off = off + layout.fields.offset(i);
89 classify(cx, layout.field(cx, i), cls, field_off)?;
90 }
91
92 match &layout.variants {
93 Variants::Single { .. } | Variants::Empty => {}
94 Variants::Multiple { variants, .. } => {
95 for variant_idx in variants.indices() {
97 classify(cx, layout.for_variant(cx, variant_idx), cls, off)?;
98 }
99 }
100 }
101
102 return Ok(());
103 }
104 };
105
106 let first = (off.bytes() / 8) as usize;
108 let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
109 for cls in &mut cls[first..=last] {
110 *cls = match cls {
111 Some(old) => Some(Class::merge(*old, c)?),
112 None => Some(c),
113 };
114
115 c = c.upper_half();
117 }
118
119 Ok(())
120 }
121
122 let n = arg.layout.size.bytes().div_ceil(8) as usize;
123 if n > MAX_EIGHTBYTES {
124 return Err(Memory);
125 }
126
127 let mut cls = [None; MAX_EIGHTBYTES];
128 classify(cx, arg.layout, &mut cls, Size::ZERO)?;
129 if n > 2 {
130 if cls[0] != Some(Class::Sse) {
131 return Err(Memory);
132 }
133 if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
134 return Err(Memory);
135 }
136 } else {
137 let mut i = 0;
138 while i < n {
139 if cls[i] == Some(Class::SseUp) {
140 cls[i] = Some(Class::Sse);
141 } else if cls[i] == Some(Class::Sse) {
142 i += 1;
143 while i != n && cls[i] == Some(Class::SseUp) {
144 i += 1;
145 }
146 } else {
147 i += 1;
148 }
149 }
150 }
151
152 if let [Some(Class::X87Up), ..] = cls {
154 return Err(Memory);
155 }
156
157 for [prev, curr] in cls[..n].array_windows() {
158 if *curr == Some(Class::X87Up) && *prev != Some(Class::X87) {
159 return Err(Memory);
160 }
161 }
162
163 Ok(cls)
164}
165
166fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> {
167 let Some(Some(class)) = cls.get(*i) else {
168 return None;
169 };
170
171 match class {
172 Class::Int => {
173 *i += 1;
174 Some(if size.bytes() < 8 { Reg { kind: RegKind::Integer, size } } else { Reg::i64() })
175 }
176 Class::Sse => {
177 let vec_len =
178 1 + cls[*i + 1..].iter().take_while(|&&c| c == Some(Class::SseUp)).count();
179 *i += vec_len;
180 Some(if vec_len == 1 {
181 match size.bytes() {
182 4 => Reg::f32(),
183 _ => Reg::f64(),
184 }
185 } else {
186 Reg::opaque_vector(Size::from_bytes(8) * (vec_len as u64))
187 })
188 }
189 Class::X87 => {
190 let consumed =
191 1 + cls[*i + 1..].iter().take_while(|&&c| c == Some(Class::X87Up)).count();
192 {
match (&consumed, &2) {
(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!(consumed, 2);
193 *i += consumed;
194 Some(Reg::x87_f80())
195 }
196 c => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("reg_component: unhandled class {0:?}", c)));
}unreachable!("reg_component: unhandled class {:?}", c),
197 }
198}
199
200fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
201 let mut i = 0;
202 let lo = reg_component(cls, &mut i, size).unwrap();
203 let offset = Size::from_bytes(8) * (i as u64);
204 let mut target = CastTarget::from(lo);
205 if size > offset {
206 if let Some(hi) = reg_component(cls, &mut i, size - offset) {
207 target = CastTarget::pair(lo, hi);
208 }
209 }
210 {
match (®_component(cls, &mut i, Size::ZERO), &None) {
(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!(reg_component(cls, &mut i, Size::ZERO), None);
211 target
212}
213
214const MAX_INT_REGS: usize = 6; const MAX_SSE_REGS: usize = 8; pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
218where
219 Ty: TyAbiInterface<'a, C> + Copy,
220 C: HasDataLayout + HasTargetSpec,
221{
222 let mut int_regs = MAX_INT_REGS;
223 let mut sse_regs = MAX_SSE_REGS;
224
225 let mut x86_64_arg_or_ret = |arg: &mut ArgAbi<'a, Ty>, is_arg: bool| {
226 if !arg.layout.is_sized() {
227 return;
230 }
231 if is_arg && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
232 int_regs = int_regs.saturating_sub(1);
233 arg.make_indirect();
234 return;
235 }
236 if is_arg && arg.layout.is_x87_f80(cx) {
237 arg.cast_to(Reg::x87_f80());
239 return;
240 }
241 let mut cls_or_mem = classify_arg(cx, arg);
242
243 if is_arg && let Ok(cls) = cls_or_mem {
244 if cls.contains(&Some(Class::X87)) {
245 {
match cls {
[Some(Class::X87), Some(Class::X87Up), ..] => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"[Some(Class::X87), Some(Class::X87Up), ..]",
::core::option::Option::None);
}
}
};std::assert_matches!(cls, [Some(Class::X87), Some(Class::X87Up), ..]);
247 cls_or_mem = Err(Memory);
248 } else {
249 let mut needed_int = 0;
250 let mut needed_sse = 0;
251 for c in cls {
252 match c {
253 Some(Class::Int) => needed_int += 1,
254 Some(Class::Sse) => needed_sse += 1,
255 _ => {}
256 }
257 }
258 match (int_regs.checked_sub(needed_int), sse_regs.checked_sub(needed_sse)) {
259 (Some(left_int), Some(left_sse)) => {
260 int_regs = left_int;
261 sse_regs = left_sse;
262 }
263 _ => {
264 if arg.layout.is_aggregate() {
269 cls_or_mem = Err(Memory);
270 }
271 }
272 }
273 }
274 }
275
276 match cls_or_mem {
277 Err(Memory) => {
278 if is_arg {
279 arg.pass_by_stack_offset(None);
282 } else {
283 arg.make_indirect();
285 {
match (&int_regs, &MAX_INT_REGS) {
(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!(int_regs, MAX_INT_REGS);
288 int_regs -= 1;
289 }
290 }
291 Ok(ref cls) => {
292 if arg.layout.is_aggregate() {
294 let size = arg.layout.size;
295 arg.cast_to(cast_target(cls, size));
296 } else if is_arg || cx.target_spec().is_like_darwin {
297 arg.extend_integer_width_to(32);
298 }
299 if !is_arg && arg.layout.backend_repr.is_bool() {
302 arg.extend_integer_width_to(8);
303 }
304 }
305 }
306 };
307
308 if !fn_abi.ret.is_ignore() {
309 x86_64_arg_or_ret(&mut fn_abi.ret, false);
310 }
311
312 for arg in fn_abi.args.iter_mut() {
313 if arg.is_ignore() {
314 continue;
315 }
316 x86_64_arg_or_ret(arg, true);
317 }
318}