8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use abi:: { FnType , ArgType , LayoutExt , Reg , Uniform } ;
11
+ use abi:: { FnType , ArgType , LayoutExt , Reg , RegKind , Uniform } ;
12
12
use context:: CrateContext ;
13
+ use llvm:: CallConv ;
13
14
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 ) {
15
43
if !ret. layout . is_aggregate ( ) {
16
44
ret. extend_integer_width_to ( 32 ) ;
17
45
return ;
18
46
}
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
+
19
55
let size = ret. layout . size ( ccx) ;
20
56
let bits = size. bits ( ) ;
21
57
if bits <= 32 {
@@ -35,11 +71,19 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
35
71
ret. make_indirect ( ccx) ;
36
72
}
37
73
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 ) {
39
75
if !arg. layout . is_aggregate ( ) {
40
76
arg. extend_integer_width_to ( 32 ) ;
41
77
return ;
42
78
}
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
+
43
87
let align = arg. layout . align ( ccx) . abi ( ) ;
44
88
let total = arg. layout . size ( ccx) ;
45
89
arg. cast_to ( ccx, Uniform {
@@ -49,12 +93,18 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
49
93
}
50
94
51
95
pub 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
+
52
102
if !fty. ret . is_ignore ( ) {
53
- classify_ret_ty ( ccx, & mut fty. ret ) ;
103
+ classify_ret_ty ( ccx, & mut fty. ret , vfp ) ;
54
104
}
55
105
56
106
for arg in & mut fty. args {
57
107
if arg. is_ignore ( ) { continue ; }
58
- classify_arg_ty ( ccx, arg) ;
108
+ classify_arg_ty ( ccx, arg, vfp ) ;
59
109
}
60
110
}
0 commit comments