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 match abi {
64 ELFv1 | AIX => {
65 if arg.layout.size > unit.size || is_or_contains_union(cx, arg.layout) {
67 return None;
68 }
69 }
70 ELFv2 => {
71 let max_members = if unit.kind == RegKind::PpcF128 { 4 } else { 8 };
73
74 if arg.layout.size > unit.size.checked_mul(max_members, cx).unwrap() {
76 return None;
77 }
78 }
79 }
80
81 let valid_unit = match unit.kind {
82 RegKind::Integer => false,
83 RegKind::Float | RegKind::PpcF128 => true,
84 RegKind::Vector { .. } => unit.size.bits() == 128,
85 };
86
87 valid_unit.then_some(Uniform::new(unit, arg.layout.size))
88 })
89}
90
91fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
92where
93 Ty: TyAbiInterface<'a, C> + Copy,
94 C: HasDataLayout,
95{
96 if arg.is_ignore() || !arg.layout.is_sized() {
97 return;
99 }
100 if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
101 arg.make_indirect();
102 return;
103 }
104 if !arg.layout.is_aggregate() {
105 arg.extend_integer_width_to(64);
106 return;
107 }
108 if let Some(component) = arg.layout.complex_number(cx) {
109 if let Numeric::Int(Integer::I16, _) = component {
110 return;
113 }
114
115 let reg = Reg { kind: component.reg_kind(), size: component.size() };
116 arg.cast_to(CastTarget::pair(reg, reg));
117 return;
118 }
119
120 if !is_ret && abi == AIX {
125 arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap()));
126 return;
127 }
128
129 if is_ret && (abi == ELFv1 || abi == AIX) {
131 arg.make_indirect();
132 return;
133 }
134
135 if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
136 arg.cast_to(uniform);
137 return;
138 }
139
140 let size = arg.layout.size;
141 if is_ret && size.bits() > 128 {
142 arg.make_indirect();
144 } else if size.bits() <= 64 {
145 arg.cast_to(Reg { kind: RegKind::Integer, size })
148 } else {
149 let reg = if arg.layout.align.bytes() > 8 { Reg::i128() } else { Reg::i64() };
153 arg.cast_to(Uniform::consecutive(
154 reg,
155 size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()),
156 ))
157 };
158}
159
160pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
161where
162 Ty: TyAbiInterface<'a, C> + Copy,
163 C: HasDataLayout + HasTargetSpec,
164{
165 let abi = match cx.target_spec().options.llvm_abiname {
166 LlvmAbi::ElfV1 => ELFv1,
167 LlvmAbi::ElfV2 => ELFv2,
168 LlvmAbi::Unspecified if cx.target_spec().os == Os::Aix => AIX,
169 _ => ::core::panicking::unreachable_default_msg()unreachable!(),
172 };
173
174 classify(cx, &mut fn_abi.ret, abi, true);
175
176 for arg in fn_abi.args.iter_mut() {
177 classify(cx, arg, abi, false);
178 }
179}