1
1
// FIXME: This needs an audit for correctness and completeness.
2
2
3
- use crate :: abi:: call:: { ArgAbi , FnAbi , Reg , RegKind , Uniform } ;
4
- use crate :: abi:: { HasDataLayout , TyAbiInterface } ;
3
+ use crate :: abi:: call:: {
4
+ ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , CastTarget , FnAbi , Reg , RegKind , Uniform ,
5
+ } ;
6
+ use crate :: abi:: { self , HasDataLayout , Size , TyAbiInterface } ;
5
7
6
8
fn is_homogeneous_aggregate < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > ) -> Option < Uniform >
7
9
where
@@ -16,41 +18,15 @@ where
16
18
17
19
let valid_unit = match unit. kind {
18
20
RegKind :: Integer => false ,
19
- RegKind :: Float => true ,
21
+ RegKind :: Float => false ,
20
22
RegKind :: Vector => arg. layout . size . bits ( ) == 128 ,
21
23
} ;
22
24
23
25
valid_unit. then_some ( Uniform { unit, total : arg. layout . size } )
24
26
} )
25
27
}
26
28
27
- fn classify_ret < ' a , Ty , C > ( cx : & C , ret : & mut ArgAbi < ' a , Ty > )
28
- where
29
- Ty : TyAbiInterface < ' a , C > + Copy ,
30
- C : HasDataLayout ,
31
- {
32
- if !ret. layout . is_aggregate ( ) {
33
- ret. extend_integer_width_to ( 64 ) ;
34
- return ;
35
- }
36
-
37
- if let Some ( uniform) = is_homogeneous_aggregate ( cx, ret) {
38
- ret. cast_to ( uniform) ;
39
- return ;
40
- }
41
- let size = ret. layout . size ;
42
- let bits = size. bits ( ) ;
43
- if bits <= 256 {
44
- let unit = Reg :: i64 ( ) ;
45
- ret. cast_to ( Uniform { unit, total : size } ) ;
46
- return ;
47
- }
48
-
49
- // don't return aggregates in registers
50
- ret. make_indirect ( ) ;
51
- }
52
-
53
- fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > )
29
+ fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > , in_registers_max : Size )
54
30
where
55
31
Ty : TyAbiInterface < ' a , C > + Copy ,
56
32
C : HasDataLayout ,
@@ -60,13 +36,97 @@ where
60
36
return ;
61
37
}
62
38
39
+ // This doesn't intentionally handle structures with floats which needs
40
+ // special care below.
63
41
if let Some ( uniform) = is_homogeneous_aggregate ( cx, arg) {
64
42
arg. cast_to ( uniform) ;
65
43
return ;
66
44
}
67
45
46
+ if let abi:: FieldsShape :: Arbitrary { .. } = arg. layout . fields {
47
+ let dl = cx. data_layout ( ) ;
48
+ let size = arg. layout . size ;
49
+ let mut prefix = [ None ; 8 ] ;
50
+ let mut prefix_index = 0 ;
51
+ let mut last_offset = Size :: ZERO ;
52
+ let mut has_float = false ;
53
+ let mut arg_attribute = ArgAttribute :: default ( ) ;
54
+
55
+ for i in 0 ..arg. layout . fields . count ( ) {
56
+ let field = arg. layout . field ( cx, i) ;
57
+ let offset = arg. layout . fields . offset ( i) ;
58
+
59
+ if let abi:: Abi :: Scalar ( scalar) = & field. abi {
60
+ if scalar. value == abi:: F32 || scalar. value == abi:: F64 {
61
+ has_float = true ;
62
+
63
+ if !last_offset. is_aligned ( dl. f64_align . abi ) && last_offset < offset {
64
+ if prefix_index == prefix. len ( ) {
65
+ break ;
66
+ }
67
+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
68
+ prefix_index += 1 ;
69
+ last_offset = last_offset + Reg :: i32 ( ) . size ;
70
+ }
71
+
72
+ for _ in 0 ..( ( offset - last_offset) . bits ( ) / 64 )
73
+ . min ( ( prefix. len ( ) - prefix_index) as u64 )
74
+ {
75
+ prefix[ prefix_index] = Some ( Reg :: i64 ( ) ) ;
76
+ prefix_index += 1 ;
77
+ last_offset = last_offset + Reg :: i64 ( ) . size ;
78
+ }
79
+
80
+ if last_offset < offset {
81
+ if prefix_index == prefix. len ( ) {
82
+ break ;
83
+ }
84
+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
85
+ prefix_index += 1 ;
86
+ last_offset = last_offset + Reg :: i32 ( ) . size ;
87
+ }
88
+
89
+ if prefix_index == prefix. len ( ) {
90
+ break ;
91
+ }
92
+
93
+ if scalar. value == abi:: F32 {
94
+ arg_attribute = ArgAttribute :: InReg ;
95
+ prefix[ prefix_index] = Some ( Reg :: f32 ( ) ) ;
96
+ last_offset = offset + Reg :: f32 ( ) . size ;
97
+ } else {
98
+ prefix[ prefix_index] = Some ( Reg :: f64 ( ) ) ;
99
+ last_offset = offset + Reg :: f64 ( ) . size ;
100
+ }
101
+ prefix_index += 1 ;
102
+ }
103
+ }
104
+ }
105
+
106
+ if has_float && arg. layout . size <= in_registers_max {
107
+ let mut rest_size = size - last_offset;
108
+
109
+ if ( rest_size. raw % 8 ) != 0 && prefix_index < prefix. len ( ) {
110
+ prefix[ prefix_index] = Some ( Reg :: i32 ( ) ) ;
111
+ rest_size = rest_size - Reg :: i32 ( ) . size ;
112
+ }
113
+
114
+ arg. cast_to ( CastTarget {
115
+ prefix,
116
+ rest : Uniform { unit : Reg :: i64 ( ) , total : rest_size } ,
117
+ attrs : ArgAttributes {
118
+ regular : arg_attribute,
119
+ arg_ext : ArgExtension :: None ,
120
+ pointee_size : Size :: ZERO ,
121
+ pointee_align : None ,
122
+ } ,
123
+ } ) ;
124
+ return ;
125
+ }
126
+ }
127
+
68
128
let total = arg. layout . size ;
69
- if total. bits ( ) > 128 {
129
+ if total > in_registers_max {
70
130
arg. make_indirect ( ) ;
71
131
return ;
72
132
}
@@ -80,13 +140,13 @@ where
80
140
C : HasDataLayout ,
81
141
{
82
142
if !fn_abi. ret . is_ignore ( ) {
83
- classify_ret ( cx, & mut fn_abi. ret ) ;
143
+ classify_arg ( cx, & mut fn_abi. ret , Size { raw : 32 } ) ;
84
144
}
85
145
86
146
for arg in & mut fn_abi. args {
87
147
if arg. is_ignore ( ) {
88
148
continue ;
89
149
}
90
- classify_arg ( cx, arg) ;
150
+ classify_arg ( cx, arg, Size { raw : 16 } ) ;
91
151
}
92
152
}
0 commit comments