88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use abi:: { FnType , ArgType , LayoutExt , Reg , Uniform } ;
11+ use abi:: { FnType , ArgType , LayoutExt , Reg , RegKind , Uniform } ;
1212use context:: CrateContext ;
13+ use llvm:: CallConv ;
1314
14- fn classify_ret_ty < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , ret : & mut ArgType < ' tcx > ) {
15+ fn is_homogeneous_aggregate < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , arg : & mut ArgType < ' tcx > )
16+ -> Option < Uniform > {
17+ arg. layout . homogeneous_aggregate ( ccx) . and_then ( |unit| {
18+ let size = arg. layout . size ( ccx) ;
19+
20+ // Ensure we have at most four uniquely addressable members.
21+ if size > unit. size . checked_mul ( 4 , ccx) . unwrap ( ) {
22+ return None ;
23+ }
24+
25+ let valid_unit = match unit. kind {
26+ RegKind :: Integer => false ,
27+ RegKind :: Float => true ,
28+ RegKind :: Vector => size. bits ( ) == 64 || size. bits ( ) == 128
29+ } ;
30+
31+ if valid_unit {
32+ Some ( Uniform {
33+ unit,
34+ total : size
35+ } )
36+ } else {
37+ None
38+ }
39+ } )
40+ }
41+
42+ fn classify_ret_ty < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , ret : & mut ArgType < ' tcx > , vfp : bool ) {
1543 if !ret. layout . is_aggregate ( ) {
1644 ret. extend_integer_width_to ( 32 ) ;
1745 return ;
1846 }
47+
48+ if vfp {
49+ if let Some ( uniform) = is_homogeneous_aggregate ( ccx, ret) {
50+ ret. cast_to ( ccx, uniform) ;
51+ return ;
52+ }
53+ }
54+
1955 let size = ret. layout . size ( ccx) ;
2056 let bits = size. bits ( ) ;
2157 if bits <= 32 {
@@ -35,11 +71,19 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
3571 ret. make_indirect ( ccx) ;
3672}
3773
38- fn classify_arg_ty < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , arg : & mut ArgType < ' tcx > ) {
74+ fn classify_arg_ty < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , arg : & mut ArgType < ' tcx > , vfp : bool ) {
3975 if !arg. layout . is_aggregate ( ) {
4076 arg. extend_integer_width_to ( 32 ) ;
4177 return ;
4278 }
79+
80+ if vfp {
81+ if let Some ( uniform) = is_homogeneous_aggregate ( ccx, arg) {
82+ arg. cast_to ( ccx, uniform) ;
83+ return ;
84+ }
85+ }
86+
4387 let align = arg. layout . align ( ccx) . abi ( ) ;
4488 let total = arg. layout . size ( ccx) ;
4589 arg. cast_to ( ccx, Uniform {
@@ -49,12 +93,18 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
4993}
5094
5195pub fn compute_abi_info < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , fty : & mut FnType < ' tcx > ) {
96+ // If this is a target with a hard-float ABI, and the function is not explicitly
97+ // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
98+ let vfp = ccx. sess ( ) . target . target . llvm_target . ends_with ( "hf" )
99+ && fty. cconv != CallConv :: ArmAapcsCallConv
100+ && !fty. variadic ;
101+
52102 if !fty. ret . is_ignore ( ) {
53- classify_ret_ty ( ccx, & mut fty. ret ) ;
103+ classify_ret_ty ( ccx, & mut fty. ret , vfp ) ;
54104 }
55105
56106 for arg in & mut fty. args {
57107 if arg. is_ignore ( ) { continue ; }
58- classify_arg_ty ( ccx, arg) ;
108+ classify_arg_ty ( ccx, arg, vfp ) ;
59109 }
60110}
0 commit comments