rustc_target/callconv/
arm.rs1use rustc_abi::{ArmCall, CanonAbi, HasDataLayout, TyAbiInterface};
2
3use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
4use crate::spec::{CfgAbi, HasTargetSpec, Os};
5
6#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ArmAbiKind { }
#[automatically_derived]
impl ::core::clone::Clone for ArmAbiKind {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ArmAbiKind { }Copy)]
7enum ArmAbiKind {
8 Aapcs,
9 AapcsVfp,
10 Aapcs16Vfp,
11}
12
13fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
14where
15 Ty: TyAbiInterface<'a, C> + Copy,
16 C: HasDataLayout,
17{
18 arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
19 let size = arg.layout.size;
20
21 if size > unit.size.checked_mul(4, cx).unwrap() {
23 return None;
24 }
25
26 let valid_unit = match unit.kind {
27 RegKind::Integer => false,
28 RegKind::Float => true,
29 RegKind::PpcF128 => ::core::panicking::unreachable_default_msg()unreachable!(),
30 RegKind::Vector { .. } => unit.size.bits() == 64 || unit.size.bits() == 128,
31 };
32
33 valid_unit.then_some(Uniform::consecutive(unit, size))
34 })
35}
36
37fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi_kind: ArmAbiKind, vfp: bool)
38where
39 Ty: TyAbiInterface<'a, C> + Copy,
40 C: HasDataLayout,
41{
42 if !ret.layout.is_sized() {
43 return;
45 }
46 if !ret.layout.is_aggregate() {
47 ret.extend_integer_width_to(32);
48 return;
49 }
50
51 if vfp {
52 if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
53 ret.cast_to(uniform);
54 return;
55 }
56 }
57
58 let size = ret.layout.size;
59 let bits = size.bits();
60
61 if bits <= 32 {
62 ret.cast_to(Uniform::new(Reg::i32(), size));
64 return;
65 } else if #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) && bits <= 128 {
66 ret.cast_to(Uniform::consecutive(Reg::i32(), size));
68 return;
69 }
70
71 ret.make_indirect();
72}
73
74fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi_kind: ArmAbiKind, vfp: bool)
75where
76 Ty: TyAbiInterface<'a, C> + Copy,
77 C: HasDataLayout,
78{
79 if !arg.layout.is_sized() {
80 return;
82 }
83 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
84 arg.make_indirect();
85 return;
86 }
87 if !arg.layout.is_aggregate() {
88 arg.extend_integer_width_to(32);
89 return;
90 }
91
92 if vfp || #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) {
95 if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
96 arg.cast_to(uniform);
97 return;
98 }
99 }
100
101 if #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) && arg.layout.size.bits() > 128 {
104 arg.make_indirect();
105 return;
106 }
107
108 let align = match abi_kind {
109 ArmAbiKind::Aapcs | ArmAbiKind::AapcsVfp => arg.layout.unadjusted_abi_align.bytes(),
110 ArmAbiKind::Aapcs16Vfp => arg.layout.align.bytes(),
111 };
112
113 let total = arg.layout.size;
114 arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total));
115}
116
117pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
118where
119 Ty: TyAbiInterface<'a, C> + Copy,
120 C: HasDataLayout + HasTargetSpec,
121{
122 let abi_kind = if cx.target_spec().os == Os::WatchOs {
123 ArmAbiKind::Aapcs16Vfp
124 } else if cx.target_spec().cfg_abi == CfgAbi::EabiHf {
125 ArmAbiKind::AapcsVfp
126 } else {
127 ArmAbiKind::Aapcs
128 };
129
130 let is_effectively_vfp = |accept_aapcs16| {
132 if #[allow(non_exhaustive_omitted_patterns)] match fn_abi.conv {
CanonAbi::Arm(ArmCall::Aapcs) => true,
_ => false,
}matches!(fn_abi.conv, CanonAbi::Arm(ArmCall::Aapcs)) {
134 return false;
135 }
136
137 match abi_kind {
138 ArmAbiKind::AapcsVfp => true,
139 ArmAbiKind::Aapcs16Vfp => accept_aapcs16,
140 ArmAbiKind::Aapcs => false,
141 }
142 };
143
144 if !fn_abi.ret.is_ignore() {
145 classify_ret(cx, &mut fn_abi.ret, abi_kind, !fn_abi.c_variadic && is_effectively_vfp(true));
146 }
147
148 let is_arg_vfp = !fn_abi.c_variadic && is_effectively_vfp(false);
149 for arg in fn_abi.args.iter_mut() {
150 if arg.is_ignore() {
151 continue;
152 }
153 classify_arg(cx, arg, abi_kind, is_arg_vfp);
154 }
155}