aarch64 softfloat target: always pass floats in int registers · rust-lang/rust@666bcbd (original) (raw)
``
1
`+
use std::iter;
`
``
2
+
``
3
`+
use rustc_abi::{BackendRepr, Primitive};
`
``
4
+
1
5
`use crate::abi:🤙:{ArgAbi, FnAbi, Reg, RegKind, Uniform};
`
2
6
`use crate::abi::{HasDataLayout, TyAbiInterface};
`
``
7
`+
use crate::spec::{HasTargetSpec, Target};
`
3
8
``
4
9
`/// Indicates the variant of the AArch64 ABI we are compiling for.
`
5
10
`/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
`
`@@ -15,7 +20,7 @@ pub(crate) enum AbiKind {
`
15
20
`fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option
`
16
21
`where
`
17
22
`Ty: TyAbiInterface<'a, C> + Copy,
`
18
``
`-
C: HasDataLayout,
`
``
23
`+
C: HasDataLayout + HasTargetSpec,
`
19
24
`{
`
20
25
` arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
`
21
26
`let size = arg.layout.size;
`
`@@ -27,18 +32,52 @@ where
`
27
32
``
28
33
`let valid_unit = match unit.kind {
`
29
34
`RegKind::Integer => false,
`
30
``
`-
RegKind::Float => true,
`
``
35
`+
// The softfloat ABI treats floats like integers, so they
`
``
36
`+
// do not get homogeneous aggregate treatment.
`
``
37
`+
RegKind::Float => cx.target_spec().abi != "softfloat",
`
31
38
`RegKind::Vector => size.bits() == 64 || size.bits() == 128,
`
32
39
`};
`
33
40
``
34
41
` valid_unit.then_some(Uniform::consecutive(unit, size))
`
35
42
`})
`
36
43
`}
`
37
44
``
``
45
`+
fn softfloat_float_abi(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
`
``
46
`+
if target.abi != "softfloat" {
`
``
47
`+
return;
`
``
48
`+
}
`
``
49
`+
// Do not use the float registers for passing arguments, as that would make LLVM pick the ABI
`
``
50
`` +
// and its choice depends on whether neon
instructions are enabled. Instead, we follow the
``
``
51
`+
// AAPCS "softfloat" ABI, which specifies that floats should be passed as equivalently-sized
`
``
52
`+
// integers. Nominally this only exists for "R" profile chips, but sometimes people don't want
`
``
53
`+
// to use hardfloats even if the hardware supports them, so we do this for all softfloat
`
``
54
`+
// targets.
`
``
55
`+
if let BackendRepr::Scalar(s) = arg.layout.backend_repr
`
``
56
`+
&& let Primitive::Float(f) = s.primitive()
`
``
57
`+
{
`
``
58
`+
arg.cast_to(Reg { kind: RegKind::Integer, size: f.size() });
`
``
59
`+
} else if let BackendRepr::ScalarPair(s1, s2) = arg.layout.backend_repr
`
``
60
`+
&& (matches!(s1.primitive(), Primitive::Float(_))
`
``
61
`+
|| matches!(s2.primitive(), Primitive::Float(_)))
`
``
62
`+
{
`
``
63
`+
// This case can only be reached for the Rust ABI, so we can do whatever we want here as
`
``
64
`+
// long as it does not depend on target features (i.e., as long as we do not use float
`
``
65
`+
// registers). So we pass small things in integer registers and large things via pointer
`
``
66
`+
// indirection. This means we lose the nice "pass it as two arguments" optimization, but we
`
``
67
`` +
// currently just have to way to combine a PassMode::Cast
with that optimization (and we
``
``
68
`+
// need a cast since we want to pass the float as an int).
`
``
69
`+
if arg.layout.size.bits() <= target.pointer_width.into() {
`
``
70
`+
arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size });
`
``
71
`+
} else {
`
``
72
`+
arg.make_indirect();
`
``
73
`+
}
`
``
74
`+
}
`
``
75
`+
}
`
``
76
+
38
77
`fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
`
39
78
`where
`
40
79
`Ty: TyAbiInterface<'a, C> + Copy,
`
41
``
`-
C: HasDataLayout,
`
``
80
`+
C: HasDataLayout + HasTargetSpec,
`
42
81
`{
`
43
82
`if !ret.layout.is_sized() {
`
44
83
`// Not touching this...
`
`@@ -51,6 +90,7 @@ where
`
51
90
`// See also: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly
`
52
91
` ret.extend_integer_width_to(32)
`
53
92
`}
`
``
93
`+
softfloat_float_abi(cx.target_spec(), ret);
`
54
94
`return;
`
55
95
`}
`
56
96
`if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
`
`@@ -69,7 +109,7 @@ where
`
69
109
`fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
`
70
110
`where
`
71
111
`Ty: TyAbiInterface<'a, C> + Copy,
`
72
``
`-
C: HasDataLayout,
`
``
112
`+
C: HasDataLayout + HasTargetSpec,
`
73
113
`{
`
74
114
`if !arg.layout.is_sized() {
`
75
115
`// Not touching this...
`
`@@ -82,6 +122,8 @@ where
`
82
122
`// See also: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly
`
83
123
` arg.extend_integer_width_to(32);
`
84
124
`}
`
``
125
`+
softfloat_float_abi(cx.target_spec(), arg);
`
``
126
+
85
127
`return;
`
86
128
`}
`
87
129
`if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
`
`@@ -112,7 +154,7 @@ where
`
112
154
`pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind)
`
113
155
`where
`
114
156
`Ty: TyAbiInterface<'a, C> + Copy,
`
115
``
`-
C: HasDataLayout,
`
``
157
`+
C: HasDataLayout + HasTargetSpec,
`
116
158
`{
`
117
159
`if !fn_abi.ret.is_ignore() {
`
118
160
`classify_ret(cx, &mut fn_abi.ret, kind);
`
`@@ -125,3 +167,13 @@ where
`
125
167
`classify_arg(cx, arg, kind);
`
126
168
`}
`
127
169
`}
`
``
170
+
``
171
`+
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
`
``
172
`+
where
`
``
173
`+
Ty: TyAbiInterface<'a, C> + Copy,
`
``
174
`+
C: HasDataLayout + HasTargetSpec,
`
``
175
`+
{
`
``
176
`+
for arg in fn_abi.args.iter_mut().chain(iter::once(&mut fn_abi.ret)) {
`
``
177
`+
softfloat_float_abi(cx.target_spec(), arg);
`
``
178
`+
}
`
``
179
`+
}
`