1use rustc_abi::{FieldsShape, HasDataLayout, Integer, Numeric, TyAbiInterface, TyAndLayout};
6
7use crate::callconv::{Align, ArgAbi, CastTarget, FnAbi, Reg, RegKind, Uniform};
8use crate::spec::{HasTargetSpec, LlvmAbi, Os};
9
10#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ABI {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ABI::ELFv1 => "ELFv1",
ABI::ELFv2 => "ELFv2",
ABI::AIX => "AIX",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ABI { }
#[automatically_derived]
impl ::core::clone::Clone for ABI {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ABI { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ABI { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ABI {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq)]
11enum ABI {
12 ELFv1, ELFv2, AIX, }
16use ABI::*;
17
18fn is_or_contains_union<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
29where
30 Ty: TyAbiInterface<'a, C> + Copy,
31 C: HasDataLayout,
32{
33 if layout.is_zst() {
34 return false;
35 }
36 match layout.fields {
37 FieldsShape::Primitive => false,
38 FieldsShape::Union(_) => {
41 match layout.non_1zst_field(cx).filter(|_| layout.is_transparent()) {
42 Some((_, field)) => is_or_contains_union(cx, field),
43 None => true,
44 }
45 }
46 FieldsShape::Array { .. } => is_or_contains_union(cx, layout.field(cx, 0)),
47 FieldsShape::Arbitrary { .. } => {
48 (0..layout.fields.count()).any(|i| is_or_contains_union(cx, layout.field(cx, i)))
49 }
50 }
51}
52
53fn is_homogeneous_aggregate<'a, Ty, C>(
54 cx: &C,
55 arg: &mut ArgAbi<'a, Ty>,
56 abi: ABI,
57) -> Option<Uniform>
58where
59 Ty: TyAbiInterface<'a, C> + Copy,
60 C: HasDataLayout,
61{
62 arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
63 if ((abi == ELFv1 || abi == AIX)
66 && (arg.layout.size > unit.size || is_or_contains_union(cx, arg.layout)))
67 || arg.layout.size > unit.size.checked_mul(8, cx).unwrap()
68 {
69 return None;
70 }
71
72 let valid_unit = match unit.kind {
73 RegKind::Integer => false,
74 RegKind::Float => true,
75 RegKind::Vector { .. } => unit.size.bits() == 128,
76 };
77
78 valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size))
79 })
80}
81
82fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
83where
84 Ty: TyAbiInterface<'a, C> + Copy,
85 C: HasDataLayout,
86{
87 if arg.is_ignore() || !arg.layout.is_sized() {
88 return;
90 }
91 if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
92 arg.make_indirect();
93 return;
94 }
95 if !arg.layout.is_aggregate() {
96 arg.extend_integer_width_to(64);
97 return;
98 }
99 if let Some(component) = arg.layout.complex_number(cx) {
100 if let Numeric::Int(Integer::I16, _) = component {
101 return;
104 }
105
106 let reg = Reg { kind: component.reg_kind(), size: component.size() };
107 arg.cast_to(CastTarget::pair(reg, reg));
108 return;
109 }
110
111 if !is_ret && abi == AIX {
116 arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap()));
117 return;
118 }
119
120 if is_ret && (abi == ELFv1 || abi == AIX) {
122 arg.make_indirect();
123 return;
124 }
125
126 if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
127 arg.cast_to(uniform);
128 return;
129 }
130
131 let size = arg.layout.size;
132 if is_ret && size.bits() > 128 {
133 arg.make_indirect();
135 } else if size.bits() <= 64 {
136 arg.cast_to(Reg { kind: RegKind::Integer, size })
139 } else {
140 let reg = if arg.layout.align.bytes() > 8 { Reg::i128() } else { Reg::i64() };
144 arg.cast_to(Uniform::consecutive(
145 reg,
146 size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()),
147 ))
148 };
149}
150
151pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
152where
153 Ty: TyAbiInterface<'a, C> + Copy,
154 C: HasDataLayout + HasTargetSpec,
155{
156 let abi = match cx.target_spec().options.llvm_abiname {
157 LlvmAbi::ElfV1 => ELFv1,
158 LlvmAbi::ElfV2 => ELFv2,
159 LlvmAbi::Unspecified if cx.target_spec().os == Os::Aix => AIX,
160 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
163 };
164
165 classify(cx, &mut fn_abi.ret, abi, true);
166
167 for arg in fn_abi.args.iter_mut() {
168 classify(cx, arg, abi, false);
169 }
170}