1+ use std:: iter;
2+
3+ use rustc_abi:: { BackendRepr , Primitive } ;
4+
15use crate :: abi:: call:: { ArgAbi , FnAbi , Reg , RegKind , Uniform } ;
26use crate :: abi:: { HasDataLayout , TyAbiInterface } ;
7+ use crate :: spec:: { HasTargetSpec , Target } ;
38
49/// Indicates the variant of the AArch64 ABI we are compiling for.
510/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
@@ -15,7 +20,7 @@ pub(crate) enum AbiKind {
1520fn is_homogeneous_aggregate < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > ) -> Option < Uniform >
1621where
1722 Ty : TyAbiInterface < ' a , C > + Copy ,
18- C : HasDataLayout ,
23+ C : HasDataLayout + HasTargetSpec ,
1924{
2025 arg. layout . homogeneous_aggregate ( cx) . ok ( ) . and_then ( |ha| ha. unit ( ) ) . and_then ( |unit| {
2126 let size = arg. layout . size ;
@@ -27,18 +32,50 @@ where
2732
2833 let valid_unit = match unit. kind {
2934 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" ,
3138 RegKind :: Vector => size. bits ( ) == 64 || size. bits ( ) == 128 ,
3239 } ;
3340
3441 valid_unit. then_some ( Uniform :: consecutive ( unit, size) )
3542 } )
3643}
3744
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+
3875fn classify_ret < ' a , Ty , C > ( cx : & C , ret : & mut ArgAbi < ' a , Ty > , kind : AbiKind )
3976where
4077 Ty : TyAbiInterface < ' a , C > + Copy ,
41- C : HasDataLayout ,
78+ C : HasDataLayout + HasTargetSpec ,
4279{
4380 if !ret. layout . is_sized ( ) {
4481 // Not touching this...
5188 // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
5289 ret. extend_integer_width_to ( 32 )
5390 }
91+ softfloat_float_abi ( cx. target_spec ( ) , ret) ;
5492 return ;
5593 }
5694 if let Some ( uniform) = is_homogeneous_aggregate ( cx, ret) {
69107fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > , kind : AbiKind )
70108where
71109 Ty : TyAbiInterface < ' a , C > + Copy ,
72- C : HasDataLayout ,
110+ C : HasDataLayout + HasTargetSpec ,
73111{
74112 if !arg. layout . is_sized ( ) {
75113 // Not touching this...
82120 // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
83121 arg. extend_integer_width_to ( 32 ) ;
84122 }
123+ softfloat_float_abi ( cx. target_spec ( ) , arg) ;
124+
85125 return ;
86126 }
87127 if let Some ( uniform) = is_homogeneous_aggregate ( cx, arg) {
@@ -112,7 +152,7 @@ where
112152pub ( crate ) fn compute_abi_info < ' a , Ty , C > ( cx : & C , fn_abi : & mut FnAbi < ' a , Ty > , kind : AbiKind )
113153where
114154 Ty : TyAbiInterface < ' a , C > + Copy ,
115- C : HasDataLayout ,
155+ C : HasDataLayout + HasTargetSpec ,
116156{
117157 if !fn_abi. ret . is_ignore ( ) {
118158 classify_ret ( cx, & mut fn_abi. ret , kind) ;
@@ -125,3 +165,13 @@ where
125165 classify_arg ( cx, arg, kind) ;
126166 }
127167}
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