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]
impl ::core::clone::Clone for ArmAbiKind {
#[inline]
fn clone(&self) -> ArmAbiKind { *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::Vector { .. } => size.bits() == 64 || size.bits() == 128,
30 };
31
32 valid_unit.then_some(Uniform::consecutive(unit, size))
33 })
34}
35
36fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi_kind: ArmAbiKind, vfp: bool)
37where
38 Ty: TyAbiInterface<'a, C> + Copy,
39 C: HasDataLayout,
40{
41 if !ret.layout.is_sized() {
42 return;
44 }
45 if !ret.layout.is_aggregate() {
46 ret.extend_integer_width_to(32);
47 return;
48 }
49
50 if vfp {
51 if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
52 ret.cast_to(uniform);
53 return;
54 }
55 }
56
57 let size = ret.layout.size;
58 let bits = size.bits();
59
60 if bits <= 32 {
61 ret.cast_to(Uniform::new(Reg::i32(), size));
63 return;
64 } else if #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) && bits <= 128 {
65 ret.cast_to(Uniform::consecutive(Reg::i32(), size));
67 return;
68 }
69
70 ret.make_indirect();
71}
72
73fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi_kind: ArmAbiKind, vfp: bool)
74where
75 Ty: TyAbiInterface<'a, C> + Copy,
76 C: HasDataLayout,
77{
78 if !arg.layout.is_sized() {
79 return;
81 }
82 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
83 arg.make_indirect();
84 return;
85 }
86 if !arg.layout.is_aggregate() {
87 arg.extend_integer_width_to(32);
88 return;
89 }
90
91 if vfp || #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) {
94 if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
95 arg.cast_to(uniform);
96 return;
97 }
98 }
99
100 if #[allow(non_exhaustive_omitted_patterns)] match abi_kind {
ArmAbiKind::Aapcs16Vfp => true,
_ => false,
}matches!(abi_kind, ArmAbiKind::Aapcs16Vfp) && arg.layout.size.bits() > 128 {
103 arg.make_indirect();
104 return;
105 }
106
107 let align = match abi_kind {
108 ArmAbiKind::Aapcs | ArmAbiKind::AapcsVfp => arg.layout.unadjusted_abi_align.bytes(),
109 ArmAbiKind::Aapcs16Vfp => arg.layout.align.bytes(),
110 };
111
112 let total = arg.layout.size;
113 arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total));
114}
115
116pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
117where
118 Ty: TyAbiInterface<'a, C> + Copy,
119 C: HasDataLayout + HasTargetSpec,
120{
121 let abi_kind = if cx.target_spec().os == Os::WatchOs {
122 ArmAbiKind::Aapcs16Vfp
123 } else if cx.target_spec().cfg_abi == CfgAbi::EabiHf {
124 ArmAbiKind::AapcsVfp
125 } else {
126 ArmAbiKind::Aapcs
127 };
128
129 let is_effectively_vfp = |accept_aapcs16| {
131 if #[allow(non_exhaustive_omitted_patterns)] match fn_abi.conv {
CanonAbi::Arm(ArmCall::Aapcs) => true,
_ => false,
}matches!(fn_abi.conv, CanonAbi::Arm(ArmCall::Aapcs)) {
133 return false;
134 }
135
136 match abi_kind {
137 ArmAbiKind::AapcsVfp => true,
138 ArmAbiKind::Aapcs16Vfp => accept_aapcs16,
139 ArmAbiKind::Aapcs => false,
140 }
141 };
142
143 if !fn_abi.ret.is_ignore() {
144 classify_ret(cx, &mut fn_abi.ret, abi_kind, !fn_abi.c_variadic && is_effectively_vfp(true));
145 }
146
147 let is_arg_vfp = !fn_abi.c_variadic && is_effectively_vfp(false);
148 for arg in fn_abi.args.iter_mut() {
149 if arg.is_ignore() {
150 continue;
151 }
152 classify_arg(cx, arg, abi_kind, is_arg_vfp);
153 }
154}