1
+ use std:: iter;
2
+
3
+ use rustc_abi:: { BackendRepr , Primitive } ;
4
+
1
5
use crate :: abi:: call:: { 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 < Uniform >
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,50 @@ 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 < Ty > ( 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
50
+ // the ABI depend on whether `neon` instructions are enabled.
51
+ // Instead, we follow the "softfloat" ABI, which specifies that floats should be passed as
52
+ // equivalently sized integers.
53
+ if let BackendRepr :: Scalar ( s) = arg. layout . backend_repr
54
+ && let Primitive :: Float ( f) = s. primitive ( )
55
+ {
56
+ arg. cast_to ( Reg { kind : RegKind :: Integer , size : f. size ( ) } ) ;
57
+ } else if let BackendRepr :: ScalarPair ( s1, s2) = arg. layout . backend_repr
58
+ && ( matches ! ( s1. primitive( ) , Primitive :: Float ( _) )
59
+ || matches ! ( s2. primitive( ) , Primitive :: Float ( _) ) )
60
+ {
61
+ // This case can only be reached for the Rust ABI, so we can do whatever we want here as
62
+ // long as it does not depend on target features (i.e., as long as we do not use float
63
+ // registers). So we pass small things in integer registers and large things via pointer
64
+ // indirection. This means we lose the nice "pass it as two arguments" optimization, but we
65
+ // currently just have to way to combine a `PassMode::Cast` with that optimization (and we
66
+ // need a cast since we want to pass the float as an int).
67
+ if arg. layout . size . bits ( ) <= target. pointer_width . into ( ) {
68
+ arg. cast_to ( Reg { kind : RegKind :: Integer , size : arg. layout . size } ) ;
69
+ } else {
70
+ arg. make_indirect ( ) ;
71
+ }
72
+ }
73
+ }
74
+
38
75
fn classify_ret < ' a , Ty , C > ( cx : & C , ret : & mut ArgAbi < ' a , Ty > , kind : AbiKind )
39
76
where
40
77
Ty : TyAbiInterface < ' a , C > + Copy ,
41
- C : HasDataLayout ,
78
+ C : HasDataLayout + HasTargetSpec ,
42
79
{
43
80
if !ret. layout . is_sized ( ) {
44
81
// Not touching this...
51
88
// See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
52
89
ret. extend_integer_width_to ( 32 )
53
90
}
91
+ softfloat_float_abi ( cx. target_spec ( ) , ret) ;
54
92
return ;
55
93
}
56
94
if let Some ( uniform) = is_homogeneous_aggregate ( cx, ret) {
69
107
fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > , kind : AbiKind )
70
108
where
71
109
Ty : TyAbiInterface < ' a , C > + Copy ,
72
- C : HasDataLayout ,
110
+ C : HasDataLayout + HasTargetSpec ,
73
111
{
74
112
if !arg. layout . is_sized ( ) {
75
113
// Not touching this...
82
120
// See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
83
121
arg. extend_integer_width_to ( 32 ) ;
84
122
}
123
+ softfloat_float_abi ( cx. target_spec ( ) , arg) ;
124
+
85
125
return ;
86
126
}
87
127
if let Some ( uniform) = is_homogeneous_aggregate ( cx, arg) {
@@ -112,7 +152,7 @@ where
112
152
pub ( crate ) fn compute_abi_info < ' a , Ty , C > ( cx : & C , fn_abi : & mut FnAbi < ' a , Ty > , kind : AbiKind )
113
153
where
114
154
Ty : TyAbiInterface < ' a , C > + Copy ,
115
- C : HasDataLayout ,
155
+ C : HasDataLayout + HasTargetSpec ,
116
156
{
117
157
if !fn_abi. ret . is_ignore ( ) {
118
158
classify_ret ( cx, & mut fn_abi. ret , kind) ;
@@ -125,3 +165,13 @@ where
125
165
classify_arg ( cx, arg, kind) ;
126
166
}
127
167
}
168
+
169
+ pub ( crate ) fn compute_rust_abi_info < ' a , Ty , C > ( cx : & C , fn_abi : & mut FnAbi < ' a , Ty > )
170
+ where
171
+ Ty : TyAbiInterface < ' a , C > + Copy ,
172
+ C : HasDataLayout + HasTargetSpec ,
173
+ {
174
+ for arg in fn_abi. args . iter_mut ( ) . chain ( iter:: once ( & mut fn_abi. ret ) ) {
175
+ softfloat_float_abi ( cx. target_spec ( ) , arg) ;
176
+ }
177
+ }
0 commit comments