@@ -4,14 +4,86 @@ use crate::prelude::*;
44use crate :: value_and_place:: assert_assignable;
55
66use cranelift_codegen:: ir:: ArgumentPurpose ;
7- use rustc_target:: abi:: call:: { ArgAbi , PassMode } ;
7+ use rustc_target:: abi:: call:: { ArgAbi , CastTarget , PassMode , Reg , RegKind } ;
88use smallvec:: { smallvec, SmallVec } ;
99
1010pub ( super ) trait ArgAbiExt < ' tcx > {
1111 fn get_abi_param ( & self , tcx : TyCtxt < ' tcx > ) -> SmallVec < [ AbiParam ; 2 ] > ;
1212 fn get_abi_return ( & self , tcx : TyCtxt < ' tcx > ) -> ( Option < AbiParam > , Vec < AbiParam > ) ;
1313}
1414
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+
1587impl < ' tcx > ArgAbiExt < ' tcx > for ArgAbi < ' tcx , Ty < ' tcx > > {
1688 fn get_abi_param ( & self , tcx : TyCtxt < ' tcx > ) -> SmallVec < [ AbiParam ; 2 ] > {
1789 match self . mode {
@@ -34,7 +106,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
34106 }
35107 _ => unreachable ! ( "{:?}" , self . layout. abi) ,
36108 } ,
37- PassMode :: Cast ( _ ) => smallvec ! [ AbiParam :: new ( pointer_ty ( tcx ) ) ] ,
109+ PassMode :: Cast ( cast ) => cast_target_to_abi_params ( cast ) ,
38110 PassMode :: Indirect {
39111 attrs : _,
40112 extra_attrs : None ,
@@ -87,13 +159,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
87159 }
88160 _ => unreachable ! ( "{:?}" , self . layout. abi) ,
89161 } ,
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 ( ) ) ,
97163 PassMode :: Indirect {
98164 attrs : _,
99165 extra_attrs : None ,
@@ -117,6 +183,60 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
117183 }
118184}
119185
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+
120240/// Get a set of values to be passed as function arguments.
121241pub ( super ) fn adjust_arg_for_abi < ' tcx > (
122242 fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
@@ -131,7 +251,8 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
131251 let ( a, b) = arg. load_scalar_pair ( fx) ;
132252 smallvec ! [ a, b]
133253 }
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) {
135256 ( ptr, None ) => smallvec ! [ ptr. get_addr( fx) ] ,
136257 ( ptr, Some ( meta) ) => smallvec ! [ ptr. get_addr( fx) , meta] ,
137258 } ,
@@ -142,15 +263,22 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
142263/// as necessary.
143264pub ( super ) fn cvalue_for_param < ' tcx > (
144265 fx : & mut FunctionCx < ' _ , ' tcx , impl Module > ,
145- start_block : Block ,
146266 #[ cfg_attr( not( debug_assertions) , allow( unused_variables) ) ] local : Option < mir:: Local > ,
147267 #[ cfg_attr( not( debug_assertions) , allow( unused_variables) ) ] local_field : Option < usize > ,
148268 arg_abi : & ArgAbi < ' tcx , Ty < ' tcx > > ,
269+ block_params_iter : & mut impl Iterator < Item = Value > ,
149270) -> 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 )
152273 . 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+ } )
154282 . collect :: < SmallVec < [ _ ; 2 ] > > ( ) ;
155283
156284 #[ cfg( debug_assertions) ]
@@ -178,8 +306,10 @@ pub(super) fn cvalue_for_param<'tcx>(
178306 arg_abi. layout ,
179307 ) )
180308 }
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 {
183313 attrs : _,
184314 extra_attrs : None ,
185315 on_stack : _,
0 commit comments