@@ -4,14 +4,86 @@ use crate::prelude::*;
4
4
use crate :: value_and_place:: assert_assignable;
5
5
6
6
use cranelift_codegen:: ir:: ArgumentPurpose ;
7
- use rustc_target:: abi:: call:: { ArgAbi , PassMode } ;
7
+ use rustc_target:: abi:: call:: { ArgAbi , CastTarget , PassMode , Reg , RegKind } ;
8
8
use smallvec:: { smallvec, SmallVec } ;
9
9
10
10
pub ( super ) trait ArgAbiExt < ' tcx > {
11
11
fn get_abi_param ( & self , tcx : TyCtxt < ' tcx > ) -> SmallVec < [ AbiParam ; 2 ] > ;
12
12
fn get_abi_return ( & self , tcx : TyCtxt < ' tcx > ) -> ( Option < AbiParam > , Vec < AbiParam > ) ;
13
13
}
14
14
15
+ fn reg_to_abi_param ( reg : Reg ) -> AbiParam {
16
+ let clif_ty = match ( reg. kind , reg. size . bytes ( ) ) {
17
+ ( RegKind :: Integer , 1 ) => types:: I8 ,
18
+ ( RegKind :: Integer , 2 ) => types:: I16 ,
19
+ ( RegKind :: Integer , 4 ) => types:: I32 ,
20
+ ( RegKind :: Integer , 8 ) => types:: I64 ,
21
+ ( RegKind :: Integer , 16 ) => types:: I128 ,
22
+ ( RegKind :: Float , 4 ) => types:: F32 ,
23
+ ( RegKind :: Float , 8 ) => types:: F64 ,
24
+ ( RegKind :: Vector , size) => types:: I8 . by ( u16:: try_from ( size) . unwrap ( ) ) . unwrap ( ) ,
25
+ _ => unreachable ! ( "{:?}" , reg) ,
26
+ } ;
27
+ AbiParam :: new ( clif_ty)
28
+ }
29
+
30
+ fn cast_target_to_abi_params ( cast : CastTarget ) -> SmallVec < [ AbiParam ; 2 ] > {
31
+ let ( rest_count, rem_bytes) = if cast. rest . unit . size . bytes ( ) == 0 {
32
+ ( 0 , 0 )
33
+ } else {
34
+ (
35
+ cast. rest . total . bytes ( ) / cast. rest . unit . size . bytes ( ) ,
36
+ cast. rest . total . bytes ( ) % cast. rest . unit . size . bytes ( ) ,
37
+ )
38
+ } ;
39
+
40
+ if cast. prefix . iter ( ) . all ( |x| x. is_none ( ) ) {
41
+ // Simplify to a single unit when there is no prefix and size <= unit size
42
+ if cast. rest . total <= cast. rest . unit . size {
43
+ let clif_ty = match ( cast. rest . unit . kind , cast. rest . unit . size . bytes ( ) ) {
44
+ ( RegKind :: Integer , 1 ) => types:: I8 ,
45
+ ( RegKind :: Integer , 2 ) => types:: I16 ,
46
+ ( RegKind :: Integer , 3 ..=4 ) => types:: I32 ,
47
+ ( RegKind :: Integer , 5 ..=8 ) => types:: I64 ,
48
+ ( RegKind :: Integer , 9 ..=16 ) => types:: I128 ,
49
+ ( RegKind :: Float , 4 ) => types:: F32 ,
50
+ ( RegKind :: Float , 8 ) => types:: F64 ,
51
+ ( RegKind :: Vector , size) => types:: I8 . by ( u16:: try_from ( size) . unwrap ( ) ) . unwrap ( ) ,
52
+ _ => unreachable ! ( "{:?}" , cast. rest. unit) ,
53
+ } ;
54
+ return smallvec ! [ AbiParam :: new( clif_ty) ] ;
55
+ }
56
+ }
57
+
58
+ // Create list of fields in the main structure
59
+ let mut args = cast
60
+ . prefix
61
+ . iter ( )
62
+ . flatten ( )
63
+ . map ( |& kind| {
64
+ reg_to_abi_param ( Reg {
65
+ kind,
66
+ size : cast. prefix_chunk_size ,
67
+ } )
68
+ } )
69
+ . chain ( ( 0 ..rest_count) . map ( |_| reg_to_abi_param ( cast. rest . unit ) ) )
70
+ . collect :: < SmallVec < _ > > ( ) ;
71
+
72
+ // Append final integer
73
+ if rem_bytes != 0 {
74
+ // Only integers can be really split further.
75
+ assert_eq ! ( cast. rest. unit. kind, RegKind :: Integer ) ;
76
+ args. push ( reg_to_abi_param ( Reg {
77
+ kind : RegKind :: Integer ,
78
+ size : Size :: from_bytes ( rem_bytes) ,
79
+ } ) ) ;
80
+ }
81
+
82
+ args
83
+ }
84
+
85
+ // FIXME respect argument extension mode
86
+
15
87
impl < ' tcx > ArgAbiExt < ' tcx > for ArgAbi < ' tcx , Ty < ' tcx > > {
16
88
fn get_abi_param ( & self , tcx : TyCtxt < ' tcx > ) -> SmallVec < [ AbiParam ; 2 ] > {
17
89
match self . mode {
@@ -34,7 +106,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
34
106
}
35
107
_ => unreachable ! ( "{:?}" , self . layout. abi) ,
36
108
} ,
37
- PassMode :: Cast ( _ ) => smallvec ! [ AbiParam :: new ( pointer_ty ( tcx ) ) ] ,
109
+ PassMode :: Cast ( cast ) => cast_target_to_abi_params ( cast ) ,
38
110
PassMode :: Indirect {
39
111
attrs : _,
40
112
extra_attrs : None ,
@@ -87,13 +159,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
87
159
}
88
160
_ => unreachable ! ( "{:?}" , self . layout. abi) ,
89
161
} ,
90
- PassMode :: Cast ( _) => (
91
- Some ( AbiParam :: special (
92
- pointer_ty ( tcx) ,
93
- ArgumentPurpose :: StructReturn ,
94
- ) ) ,
95
- vec ! [ ] ,
96
- ) ,
162
+ PassMode :: Cast ( cast) => ( None , cast_target_to_abi_params ( cast) . into_iter ( ) . collect ( ) ) ,
97
163
PassMode :: Indirect {
98
164
attrs : _,
99
165
extra_attrs : None ,
@@ -117,6 +183,60 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
117
183
}
118
184
}
119
185
186
+ pub ( super ) fn to_casted_value < ' tcx > (
187
+ fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
188
+ arg : CValue < ' tcx > ,
189
+ cast : CastTarget ,
190
+ ) -> SmallVec < [ Value ; 2 ] > {
191
+ let ( ptr, meta) = arg. force_stack ( fx) ;
192
+ assert ! ( meta. is_none( ) ) ;
193
+ let mut offset = 0 ;
194
+ cast_target_to_abi_params ( cast)
195
+ . into_iter ( )
196
+ . map ( |param| {
197
+ let val = ptr
198
+ . offset_i64 ( fx, offset)
199
+ . load ( fx, param. value_type , MemFlags :: new ( ) ) ;
200
+ offset += i64:: from ( param. value_type . bytes ( ) ) ;
201
+ val
202
+ } )
203
+ . collect ( )
204
+ }
205
+
206
+ pub ( super ) fn from_casted_value < ' tcx > (
207
+ fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
208
+ block_params : & [ Value ] ,
209
+ layout : TyAndLayout < ' tcx > ,
210
+ cast : CastTarget ,
211
+ ) -> CValue < ' tcx > {
212
+ let abi_params = cast_target_to_abi_params ( cast) ;
213
+ let size = abi_params
214
+ . iter ( )
215
+ . map ( |param| param. value_type . bytes ( ) )
216
+ . sum ( ) ;
217
+ // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
218
+ assert ! ( u64 :: from( size) >= layout. size. bytes( ) ) ;
219
+ let stack_slot = fx. bcx . create_stack_slot ( StackSlotData {
220
+ kind : StackSlotKind :: ExplicitSlot ,
221
+ size,
222
+ offset : None ,
223
+ } ) ;
224
+ let ptr = Pointer :: new ( fx. bcx . ins ( ) . stack_addr ( pointer_ty ( fx. tcx ) , stack_slot, 0 ) ) ;
225
+ let mut offset = 0 ;
226
+ let mut block_params_iter = block_params. into_iter ( ) . copied ( ) ;
227
+ for param in abi_params {
228
+ let val = ptr. offset_i64 ( fx, offset) . store (
229
+ fx,
230
+ block_params_iter. next ( ) . unwrap ( ) ,
231
+ MemFlags :: new ( ) ,
232
+ ) ;
233
+ offset += i64:: from ( param. value_type . bytes ( ) ) ;
234
+ val
235
+ }
236
+ assert_eq ! ( block_params_iter. next( ) , None , "Leftover block param" ) ;
237
+ CValue :: by_ref ( ptr, layout)
238
+ }
239
+
120
240
/// Get a set of values to be passed as function arguments.
121
241
pub ( super ) fn adjust_arg_for_abi < ' tcx > (
122
242
fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
@@ -131,7 +251,8 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
131
251
let ( a, b) = arg. load_scalar_pair ( fx) ;
132
252
smallvec ! [ a, b]
133
253
}
134
- PassMode :: Cast ( _) | PassMode :: Indirect { .. } => match arg. force_stack ( fx) {
254
+ PassMode :: Cast ( cast) => to_casted_value ( fx, arg, cast) ,
255
+ PassMode :: Indirect { .. } => match arg. force_stack ( fx) {
135
256
( ptr, None ) => smallvec ! [ ptr. get_addr( fx) ] ,
136
257
( ptr, Some ( meta) ) => smallvec ! [ ptr. get_addr( fx) , meta] ,
137
258
} ,
@@ -142,15 +263,22 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
142
263
/// as necessary.
143
264
pub ( super ) fn cvalue_for_param < ' tcx > (
144
265
fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
145
- start_block : Block ,
146
266
#[ cfg_attr( not( debug_assertions) , allow( unused_variables) ) ] local : Option < mir:: Local > ,
147
267
#[ cfg_attr( not( debug_assertions) , allow( unused_variables) ) ] local_field : Option < usize > ,
148
268
arg_abi : & ArgAbi < ' tcx , Ty < ' tcx > > ,
269
+ block_params_iter : & mut impl Iterator < Item = Value > ,
149
270
) -> Option < CValue < ' tcx > > {
150
- let clif_types = arg_abi. get_abi_param ( fx . tcx ) ;
151
- let block_params = clif_types
271
+ let block_params = arg_abi
272
+ . get_abi_param ( fx . tcx )
152
273
. into_iter ( )
153
- . map ( |abi_param| fx. bcx . append_block_param ( start_block, abi_param. value_type ) )
274
+ . map ( |abi_param| {
275
+ let block_param = block_params_iter. next ( ) . unwrap ( ) ;
276
+ assert_eq ! (
277
+ fx. bcx. func. dfg. value_type( block_param) ,
278
+ abi_param. value_type
279
+ ) ;
280
+ block_param
281
+ } )
154
282
. collect :: < SmallVec < [ _ ; 2 ] > > ( ) ;
155
283
156
284
#[ cfg( debug_assertions) ]
@@ -178,8 +306,10 @@ pub(super) fn cvalue_for_param<'tcx>(
178
306
arg_abi. layout ,
179
307
) )
180
308
}
181
- PassMode :: Cast ( _)
182
- | PassMode :: Indirect {
309
+ PassMode :: Cast ( cast) => {
310
+ Some ( from_casted_value ( fx, & block_params, arg_abi. layout , cast) )
311
+ }
312
+ PassMode :: Indirect {
183
313
attrs : _,
184
314
extra_attrs : None ,
185
315
on_stack : _,
0 commit comments