1
- // FIXME: This needs an audit for correctness and completeness.
2
-
3
1
use rustc_abi:: {
4
- BackendRepr , FieldsShape , Float , HasDataLayout , Primitive , Reg , Scalar , Size , TyAbiInterface ,
5
- TyAndLayout ,
2
+ Align , BackendRepr , FieldsShape , Float , HasDataLayout , Primitive , Reg , Size , TyAbiInterface ,
3
+ TyAndLayout , Variants ,
6
4
} ;
7
5
8
6
use crate :: callconv:: { ArgAbi , ArgAttribute , CastTarget , FnAbi , Uniform } ;
9
7
use crate :: spec:: HasTargetSpec ;
10
8
11
- #[ derive( Clone , Debug ) ]
12
- struct Sdata {
13
- pub prefix : [ Option < Reg > ; 8 ] ,
14
- pub prefix_index : usize ,
15
- pub last_offset : Size ,
16
- pub has_float : bool ,
17
- pub arg_attribute : ArgAttribute ,
9
+ #[ derive( Copy , Clone ) ]
10
+ enum DoubleWord {
11
+ F64 ,
12
+ F128Start ,
13
+ F128End ,
14
+ Words ( [ Word ; 2 ] ) ,
18
15
}
19
16
20
- fn arg_scalar < C > ( cx : & C , scalar : & Scalar , offset : Size , mut data : Sdata ) -> Sdata
21
- where
22
- C : HasDataLayout ,
23
- {
24
- let dl = cx. data_layout ( ) ;
25
-
26
- if !matches ! ( scalar. primitive( ) , Primitive :: Float ( Float :: F32 | Float :: F64 ) ) {
27
- return data;
28
- }
29
-
30
- data. has_float = true ;
31
-
32
- if !data. last_offset . is_aligned ( dl. f64_align . abi ) && data. last_offset < offset {
33
- if data. prefix_index == data. prefix . len ( ) {
34
- return data;
35
- }
36
- data. prefix [ data. prefix_index ] = Some ( Reg :: i32 ( ) ) ;
37
- data. prefix_index += 1 ;
38
- data. last_offset = data. last_offset + Reg :: i32 ( ) . size ;
39
- }
40
-
41
- for _ in 0 ..( ( offset - data. last_offset ) . bits ( ) / 64 )
42
- . min ( ( data. prefix . len ( ) - data. prefix_index ) as u64 )
43
- {
44
- data. prefix [ data. prefix_index ] = Some ( Reg :: i64 ( ) ) ;
45
- data. prefix_index += 1 ;
46
- data. last_offset = data. last_offset + Reg :: i64 ( ) . size ;
47
- }
48
-
49
- if data. last_offset < offset {
50
- if data. prefix_index == data. prefix . len ( ) {
51
- return data;
52
- }
53
- data. prefix [ data. prefix_index ] = Some ( Reg :: i32 ( ) ) ;
54
- data. prefix_index += 1 ;
55
- data. last_offset = data. last_offset + Reg :: i32 ( ) . size ;
56
- }
57
-
58
- if data. prefix_index == data. prefix . len ( ) {
59
- return data;
60
- }
61
-
62
- if scalar. primitive ( ) == Primitive :: Float ( Float :: F32 ) {
63
- data. arg_attribute = ArgAttribute :: InReg ;
64
- data. prefix [ data. prefix_index ] = Some ( Reg :: f32 ( ) ) ;
65
- data. last_offset = offset + Reg :: f32 ( ) . size ;
66
- } else {
67
- data. prefix [ data. prefix_index ] = Some ( Reg :: f64 ( ) ) ;
68
- data. last_offset = offset + Reg :: f64 ( ) . size ;
69
- }
70
- data. prefix_index += 1 ;
71
- data
17
+ #[ derive( Copy , Clone ) ]
18
+ enum Word {
19
+ F32 ,
20
+ Integer ,
72
21
}
73
22
74
- fn arg_scalar_pair < C > (
23
+ fn classify < ' a , Ty , C > (
75
24
cx : & C ,
76
- scalar1 : & Scalar ,
77
- scalar2 : & Scalar ,
78
- mut offset : Size ,
79
- mut data : Sdata ,
80
- ) -> Sdata
81
- where
82
- C : HasDataLayout ,
83
- {
84
- data = arg_scalar ( cx, scalar1, offset, data) ;
85
- match ( scalar1. primitive ( ) , scalar2. primitive ( ) ) {
86
- ( Primitive :: Float ( Float :: F32 ) , _) => offset += Reg :: f32 ( ) . size ,
87
- ( _, Primitive :: Float ( Float :: F64 ) ) => offset += Reg :: f64 ( ) . size ,
88
- ( Primitive :: Int ( i, _signed) , _) => offset += i. size ( ) ,
89
- ( Primitive :: Pointer ( _) , _) => offset += Reg :: i64 ( ) . size ,
90
- _ => { }
91
- }
92
-
93
- if !offset. bytes ( ) . is_multiple_of ( 4 )
94
- && matches ! ( scalar2. primitive( ) , Primitive :: Float ( Float :: F32 | Float :: F64 ) )
95
- {
96
- offset += Size :: from_bytes ( 4 - ( offset. bytes ( ) % 4 ) ) ;
97
- }
98
- data = arg_scalar ( cx, scalar2, offset, data) ;
99
- data
100
- }
101
-
102
- fn parse_structure < ' a , Ty , C > (
103
- cx : & C ,
104
- layout : TyAndLayout < ' a , Ty > ,
105
- mut data : Sdata ,
106
- mut offset : Size ,
107
- ) -> Sdata
108
- where
25
+ arg_layout : & TyAndLayout < ' a , Ty > ,
26
+ offset : Size ,
27
+ double_words : & mut [ DoubleWord ; 4 ] ,
28
+ ) where
109
29
Ty : TyAbiInterface < ' a , C > + Copy ,
110
30
C : HasDataLayout ,
111
31
{
112
- if let FieldsShape :: Union ( _) = layout. fields {
113
- return data;
114
- }
115
-
116
- match layout. backend_repr {
117
- BackendRepr :: Scalar ( scalar) => {
118
- data = arg_scalar ( cx, & scalar, offset, data) ;
119
- }
120
- BackendRepr :: Memory { .. } => {
121
- for i in 0 ..layout. fields . count ( ) {
122
- if offset < layout. fields . offset ( i) {
123
- offset = layout. fields . offset ( i) ;
32
+ match arg_layout. backend_repr {
33
+ BackendRepr :: Scalar ( scalar) => match scalar. primitive ( ) {
34
+ Primitive :: Float ( float)
35
+ if offset. is_aligned ( float. align ( cx) . abi . min ( Align :: from_bytes ( 8 ) . unwrap ( ) ) ) =>
36
+ {
37
+ let index = offset. bytes_usize ( ) / 8 ;
38
+ match float {
39
+ Float :: F128 => {
40
+ double_words[ index] = DoubleWord :: F128Start ;
41
+ double_words[ index + 1 ] = DoubleWord :: F128End ;
42
+ }
43
+ Float :: F64 => {
44
+ double_words[ index] = DoubleWord :: F64 ;
45
+ }
46
+ Float :: F32 => {
47
+ if let DoubleWord :: Words ( words) = & mut double_words[ index] {
48
+ words[ ( offset. bytes_usize ( ) % 8 ) / 4 ] = Word :: F32 ;
49
+ } else {
50
+ unreachable ! ( ) ;
51
+ }
52
+ }
53
+ Float :: F16 => {
54
+ // FIXME(llvm/llvm-project#97981): f16 doesn't have a proper ABI in LLVM on
55
+ // sparc64 yet. Once it does, double-check if it needs to be passed in a
56
+ // floating-point register here.
57
+ }
124
58
}
125
- data = parse_structure ( cx, layout. field ( cx, i) , data. clone ( ) , offset) ;
126
59
}
127
- }
128
- _ => {
129
- if let BackendRepr :: ScalarPair ( scalar1, scalar2) = & layout. backend_repr {
130
- data = arg_scalar_pair ( cx, scalar1, scalar2, offset, data) ;
60
+ _ => { }
61
+ } ,
62
+ BackendRepr :: SimdVector { .. } => { }
63
+ BackendRepr :: ScalarPair ( ..) | BackendRepr :: Memory { .. } => match arg_layout. fields {
64
+ FieldsShape :: Primitive => {
65
+ unreachable ! ( "aggregates can't have `FieldsShape::Primitive`" )
131
66
}
132
- }
67
+ FieldsShape :: Union ( _) => {
68
+ if !arg_layout. is_zst ( ) {
69
+ if arg_layout. is_transparent ( ) {
70
+ let non_1zst_elem = arg_layout. non_1zst_field ( cx) . expect ( "not exactly one non-1-ZST field in non-ZST repr(transparent) union" ) . 1 ;
71
+ classify ( cx, & non_1zst_elem, offset, double_words) ;
72
+ }
73
+ }
74
+ }
75
+ FieldsShape :: Array { .. } => { }
76
+ FieldsShape :: Arbitrary { .. } => match arg_layout. variants {
77
+ Variants :: Multiple { .. } => { }
78
+ Variants :: Single { .. } | Variants :: Empty => {
79
+ for i in arg_layout. fields . index_by_increasing_offset ( ) {
80
+ classify (
81
+ cx,
82
+ & arg_layout. field ( cx, i) ,
83
+ offset + arg_layout. fields . offset ( i) ,
84
+ double_words,
85
+ ) ;
86
+ }
87
+ }
88
+ } ,
89
+ } ,
133
90
}
134
-
135
- data
136
91
}
137
92
138
- fn classify_arg < ' a , Ty , C > ( cx : & C , arg : & mut ArgAbi < ' a , Ty > , in_registers_max : Size )
139
- where
93
+ fn classify_arg < ' a , Ty , C > (
94
+ cx : & C ,
95
+ arg : & mut ArgAbi < ' a , Ty > ,
96
+ in_registers_max : Size ,
97
+ total_double_word_count : & mut usize ,
98
+ ) where
140
99
Ty : TyAbiInterface < ' a , C > + Copy ,
141
100
C : HasDataLayout ,
142
101
{
102
+ let pad = !total_double_word_count. is_multiple_of ( 2 ) && arg. layout . align . abi . bytes ( ) == 16 ;
103
+ let double_word_count = arg. layout . size . bytes_usize ( ) . div_ceil ( 8 ) ;
104
+ let start_double_word_count = * total_double_word_count + usize:: from ( pad) ;
143
105
if !arg. layout . is_aggregate ( ) {
144
106
arg. extend_integer_width_to ( 64 ) ;
107
+ * total_double_word_count = start_double_word_count + double_word_count;
145
108
return ;
146
109
}
147
110
148
111
let total = arg. layout . size ;
149
112
if total > in_registers_max {
150
113
arg. make_indirect ( ) ;
114
+ * total_double_word_count += 1 ;
151
115
return ;
152
116
}
153
117
154
- match arg. layout . fields {
155
- FieldsShape :: Primitive => unreachable ! ( ) ,
156
- FieldsShape :: Array { .. } => {
157
- // Arrays are passed indirectly
158
- arg. make_indirect ( ) ;
159
- return ;
160
- }
161
- FieldsShape :: Union ( _) => {
162
- // Unions and are always treated as a series of 64-bit integer chunks
163
- }
164
- FieldsShape :: Arbitrary { .. } => {
165
- // Structures with floating point numbers need special care.
118
+ * total_double_word_count = start_double_word_count + double_word_count;
166
119
167
- let mut data = parse_structure (
168
- cx,
169
- arg. layout ,
170
- Sdata {
171
- prefix : [ None ; 8 ] ,
172
- prefix_index : 0 ,
173
- last_offset : Size :: ZERO ,
174
- has_float : false ,
175
- arg_attribute : ArgAttribute :: default ( ) ,
176
- } ,
177
- Size :: ZERO ,
178
- ) ;
120
+ let mut double_words = [ DoubleWord :: Words ( [ Word :: Integer ; 2 ] ) ; 4 ] ;
121
+ classify ( cx, & arg. layout , Size :: ZERO , & mut double_words) ;
179
122
180
- if data. has_float {
181
- // Structure { float, int, int } doesn't like to be handled like
182
- // { float, long int }. Other way around it doesn't mind.
183
- if data. last_offset < arg. layout . size
184
- && !data. last_offset . bytes ( ) . is_multiple_of ( 8 )
185
- && data. prefix_index < data. prefix . len ( )
186
- {
187
- data. prefix [ data. prefix_index ] = Some ( Reg :: i32 ( ) ) ;
188
- data. prefix_index += 1 ;
189
- data. last_offset += Reg :: i32 ( ) . size ;
190
- }
123
+ let mut regs = [ None ; 8 ] ;
124
+ let mut i = 0 ;
125
+ let mut push = |reg| {
126
+ regs[ i] = Some ( reg) ;
127
+ i += 1 ;
128
+ } ;
129
+ let mut attrs = ArgAttribute :: empty ( ) ;
191
130
192
- let mut rest_size = arg. layout . size - data. last_offset ;
193
- if !rest_size. bytes ( ) . is_multiple_of ( 8 ) && data. prefix_index < data. prefix . len ( ) {
194
- data. prefix [ data. prefix_index ] = Some ( Reg :: i32 ( ) ) ;
195
- rest_size = rest_size - Reg :: i32 ( ) . size ;
131
+ for ( index, double_word) in double_words. into_iter ( ) . enumerate ( ) {
132
+ if arg. layout . size . bytes_usize ( ) <= index * 8 {
133
+ break ;
134
+ }
135
+ match double_word {
136
+ // `f128` must be aligned to be assigned a float register.
137
+ DoubleWord :: F128Start if ( start_double_word_count + index) . is_multiple_of ( 2 ) => {
138
+ push ( Reg :: f128 ( ) ) ;
139
+ }
140
+ DoubleWord :: F128Start => {
141
+ push ( Reg :: i64 ( ) ) ;
142
+ push ( Reg :: i64 ( ) ) ;
143
+ }
144
+ DoubleWord :: F128End => { } // Already handled by `F128Start`
145
+ DoubleWord :: F64 => push ( Reg :: f64 ( ) ) ,
146
+ DoubleWord :: Words ( [ Word :: Integer , Word :: Integer ] ) => push ( Reg :: i64 ( ) ) ,
147
+ DoubleWord :: Words ( words) => {
148
+ attrs |= ArgAttribute :: InReg ;
149
+ for word in words {
150
+ match word {
151
+ Word :: F32 => push ( Reg :: f32 ( ) ) ,
152
+ Word :: Integer => push ( Reg :: i32 ( ) ) ,
153
+ }
196
154
}
197
-
198
- arg. cast_to (
199
- CastTarget :: prefixed ( data. prefix , Uniform :: new ( Reg :: i64 ( ) , rest_size) )
200
- . with_attrs ( data. arg_attribute . into ( ) ) ,
201
- ) ;
202
- return ;
203
155
}
204
156
}
205
157
}
206
158
207
- arg. cast_to ( Uniform :: new ( Reg :: i64 ( ) , total) ) ;
159
+ if let [ Some ( reg) , None , ..] = regs {
160
+ arg. cast_to_and_pad_i32 ( CastTarget :: from ( reg) . with_attrs ( attrs. into ( ) ) , pad) ;
161
+ } else {
162
+ arg. cast_to_and_pad_i32 (
163
+ CastTarget :: prefixed ( regs, Uniform :: new ( Reg :: i8 ( ) , Size :: ZERO ) )
164
+ . with_attrs ( attrs. into ( ) ) ,
165
+ pad,
166
+ ) ;
167
+ }
208
168
}
209
169
210
170
pub ( crate ) fn compute_abi_info < ' a , Ty , C > ( cx : & C , fn_abi : & mut FnAbi < ' a , Ty > )
@@ -213,9 +173,10 @@ where
213
173
C : HasDataLayout + HasTargetSpec ,
214
174
{
215
175
if !fn_abi. ret . is_ignore ( ) {
216
- classify_arg ( cx, & mut fn_abi. ret , Size :: from_bytes ( 32 ) ) ;
176
+ classify_arg ( cx, & mut fn_abi. ret , Size :: from_bytes ( 32 ) , & mut 0 ) ;
217
177
}
218
178
179
+ let mut double_word_count = 0 ;
219
180
for arg in fn_abi. args . iter_mut ( ) {
220
181
if arg. is_ignore ( ) {
221
182
// sparc64-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
@@ -224,9 +185,10 @@ where
224
185
&& arg. layout . is_zst ( )
225
186
{
226
187
arg. make_indirect_from_ignore ( ) ;
188
+ double_word_count += 1 ;
227
189
}
228
- return ;
190
+ continue ;
229
191
}
230
- classify_arg ( cx, arg, Size :: from_bytes ( 16 ) ) ;
192
+ classify_arg ( cx, arg, Size :: from_bytes ( 16 ) , & mut double_word_count ) ;
231
193
}
232
194
}
0 commit comments