@@ -27,9 +27,12 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
2727 ( RegKind :: Float , 4 ) => types:: F32 ,
2828 ( RegKind :: Float , 8 ) => types:: F64 ,
2929 ( RegKind :: Float , 16 ) => types:: F128 ,
30- ( RegKind :: Vector { hint_vector_elem : _ } , size) => {
31- types:: I8 . by ( u32:: try_from ( size) . unwrap ( ) ) . unwrap ( )
32- }
30+ (
31+ RegKind :: Vector {
32+ hint_vector_elem : _,
33+ } ,
34+ size,
35+ ) => types:: I8 . by ( u32:: try_from ( size) . unwrap ( ) ) . unwrap ( ) ,
3336 _ => unreachable ! ( "{:?}" , reg) ,
3437 } ;
3538 AbiParam :: new ( clif_ty)
@@ -55,13 +58,21 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2
5558 ] ;
5659 }
5760
58- let ( rest_count, rem_bytes ) = if cast. rest . unit . size . bytes ( ) == 0 {
59- ( 0 , 0 )
61+ let rest_count = if cast. rest . total == Size :: ZERO {
62+ 0
6063 } else {
61- (
62- cast. rest . total . bytes ( ) / cast. rest . unit . size . bytes ( ) ,
63- cast. rest . total . bytes ( ) % cast. rest . unit . size . bytes ( ) ,
64- )
64+ assert_ne ! ( cast. rest. unit. size, Size :: ZERO ) ;
65+ if cast. rest . total . bytes ( ) % cast. rest . unit . size . bytes ( ) != 0 {
66+ assert_eq ! (
67+ cast. rest. unit. kind,
68+ RegKind :: Integer ,
69+ "only int regs can be split"
70+ ) ;
71+ }
72+ cast. rest
73+ . total
74+ . bytes ( )
75+ . div_ceil ( cast. rest . unit . size . bytes ( ) )
6576 } ;
6677
6778 // Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there
@@ -83,18 +94,39 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2
8394 res. push ( ( offset, arg) ) ;
8495 offset += Size :: from_bytes ( arg. value_type . bytes ( ) ) ;
8596 }
97+ res
98+ }
8699
87- // Append final integer
88- if rem_bytes != 0 {
89- // Only integers can be really split further.
90- assert_eq ! ( cast. rest. unit. kind, RegKind :: Integer ) ;
91- res. push ( (
92- offset,
93- reg_to_abi_param ( Reg { kind : RegKind :: Integer , size : Size :: from_bytes ( rem_bytes) } ) ,
94- ) ) ;
95- }
100+ fn abi_params_size ( params : & [ ( Size , AbiParam ) ] ) -> u64 {
101+ params
102+ . iter ( )
103+ . map ( |( offset, param) | offset. bytes ( ) + u64:: from ( param. value_type . bytes ( ) ) )
104+ . max ( )
105+ . unwrap_or ( 0 )
106+ }
96107
97- res
108+ #[ cfg( test) ]
109+ mod tests {
110+ use rustc_target:: callconv:: Uniform ;
111+
112+ use super :: * ;
113+
114+ #[ test]
115+ fn cast_target_rounds_integer_rest_to_unit_size ( ) {
116+ let reg = Reg {
117+ kind : RegKind :: Integer ,
118+ size : Size :: from_bytes ( 8 ) ,
119+ } ;
120+ let cast = CastTarget :: from ( Uniform :: new ( reg, Size :: from_bytes ( 10 ) ) ) ;
121+
122+ let params = cast_target_to_abi_params ( & cast) ;
123+
124+ assert_eq ! ( params. len( ) , 2 ) ;
125+ assert_eq ! ( params[ 0 ] . 0 , Size :: ZERO ) ;
126+ assert_eq ! ( params[ 0 ] . 1 . value_type, types:: I64 ) ;
127+ assert_eq ! ( params[ 1 ] . 0 , Size :: from_bytes( 8 ) ) ;
128+ assert_eq ! ( params[ 1 ] . 1 . value_type, types:: I64 ) ;
129+ }
98130}
99131
100132impl < ' tcx > ArgAbiExt < ' tcx > for ArgAbi < ' tcx , Ty < ' tcx > > {
@@ -125,22 +157,39 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
125157 } ,
126158 PassMode :: Cast { ref cast, pad_i32 } => {
127159 assert ! ( !pad_i32, "padding support not yet implemented" ) ;
128- cast_target_to_abi_params ( cast) . into_iter ( ) . map ( |( _, param) | param) . collect ( )
160+ cast_target_to_abi_params ( cast)
161+ . into_iter ( )
162+ . map ( |( _, param) | param)
163+ . collect ( )
129164 }
130- PassMode :: Indirect { attrs, meta_attrs : None , on_stack } => {
165+ PassMode :: Indirect {
166+ attrs,
167+ meta_attrs : None ,
168+ on_stack,
169+ } => {
131170 if on_stack {
132171 // Abi requires aligning struct size to pointer size
133- let size = self . layout . size . align_to ( tcx. data_layout . pointer_align ( ) . abi ) ;
172+ let size = self
173+ . layout
174+ . size
175+ . align_to ( tcx. data_layout . pointer_align ( ) . abi ) ;
134176 let size = u32:: try_from ( size. bytes ( ) ) . unwrap ( ) ;
135177 smallvec ! [ apply_attrs_to_abi_param(
136178 AbiParam :: special( pointer_ty( tcx) , ArgumentPurpose :: StructArgument ( size) , ) ,
137179 attrs
138180 ) ]
139181 } else {
140- smallvec ! [ apply_attrs_to_abi_param( AbiParam :: new( pointer_ty( tcx) ) , attrs) ]
182+ smallvec ! [ apply_attrs_to_abi_param(
183+ AbiParam :: new( pointer_ty( tcx) ) ,
184+ attrs
185+ ) ]
141186 }
142187 }
143- PassMode :: Indirect { attrs, meta_attrs : Some ( meta_attrs) , on_stack } => {
188+ PassMode :: Indirect {
189+ attrs,
190+ meta_attrs : Some ( meta_attrs) ,
191+ on_stack,
192+ } => {
144193 assert ! ( !on_stack) ;
145194 smallvec ! [
146195 apply_attrs_to_abi_param( AbiParam :: new( pointer_ty( tcx) ) , attrs) ,
@@ -163,7 +212,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
163212 ) ,
164213 BackendRepr :: SimdVector { .. } => {
165214 let vector_ty = crate :: intrinsics:: clif_vector_type ( tcx, self . layout ) ;
166- ( None , vec ! [ apply_attrs_to_abi_param( AbiParam :: new( vector_ty) , attrs) ] )
215+ (
216+ None ,
217+ vec ! [ apply_attrs_to_abi_param( AbiParam :: new( vector_ty) , attrs) ] ,
218+ )
167219 }
168220 _ => unreachable ! ( "{:?}" , self . layout. backend_repr) ,
169221 } ,
@@ -183,9 +235,16 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
183235 } ,
184236 PassMode :: Cast { ref cast, .. } => (
185237 None ,
186- cast_target_to_abi_params ( cast) . into_iter ( ) . map ( |( _, param) | param) . collect ( ) ,
238+ cast_target_to_abi_params ( cast)
239+ . into_iter ( )
240+ . map ( |( _, param) | param)
241+ . collect ( ) ,
187242 ) ,
188- PassMode :: Indirect { attrs, meta_attrs : None , on_stack } => {
243+ PassMode :: Indirect {
244+ attrs,
245+ meta_attrs : None ,
246+ on_stack,
247+ } => {
189248 assert ! ( !on_stack) ;
190249 (
191250 Some ( apply_attrs_to_abi_param (
@@ -195,7 +254,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
195254 vec ! [ ] ,
196255 )
197256 }
198- PassMode :: Indirect { attrs : _, meta_attrs : Some ( _) , on_stack : _ } => {
257+ PassMode :: Indirect {
258+ attrs : _,
259+ meta_attrs : Some ( _) ,
260+ on_stack : _,
261+ } => {
199262 unreachable ! ( "unsized return value" )
200263 }
201264 }
@@ -207,12 +270,51 @@ pub(super) fn to_casted_value<'tcx>(
207270 arg : CValue < ' tcx > ,
208271 cast : & CastTarget ,
209272) -> SmallVec < [ Value ; 2 ] > {
273+ let layout = arg. layout ( ) ;
210274 let ( ptr, meta) = arg. force_stack ( fx) ;
211275 assert ! ( meta. is_none( ) ) ;
212- cast_target_to_abi_params ( cast)
213- . into_iter ( )
276+ let abi_params = cast_target_to_abi_params ( cast) ;
277+ let abi_param_size = abi_params_size ( & abi_params) ;
278+ let cast_align = cast. align ( fx) . bytes ( ) ;
279+ let layout_align = layout. align . bytes ( ) ;
280+ let slot_align = cast_align. max ( layout_align) ;
281+ let slot_size = abi_param_size
282+ . max ( layout. size . bytes ( ) )
283+ . next_multiple_of ( slot_align) ;
284+ let scratch = fx. create_stack_slot (
285+ u32:: try_from ( slot_size) . unwrap ( ) ,
286+ u32:: try_from ( slot_align) . unwrap ( ) ,
287+ ) ;
288+ let zero = fx. bcx . ins ( ) . iconst ( types:: I8 , 0 ) ;
289+ for offset in 0 ..slot_size {
290+ scratch
291+ . offset_i64 ( fx, offset as i64 )
292+ . store ( fx, zero, MemFlags :: new ( ) ) ;
293+ }
294+
295+ let copy_bytes = abi_param_size. min ( layout. size . bytes ( ) ) ;
296+ if copy_bytes != 0 {
297+ let from_addr = ptr. get_addr ( fx) ;
298+ let to_addr = scratch. get_addr ( fx) ;
299+ fx. bcx . emit_small_memory_copy (
300+ fx. target_config ,
301+ to_addr,
302+ from_addr,
303+ copy_bytes,
304+ slot_align. try_into ( ) . unwrap_or ( 128 ) ,
305+ layout. align . bytes ( ) . try_into ( ) . unwrap_or ( 128 ) ,
306+ true ,
307+ MemFlags :: new ( ) ,
308+ ) ;
309+ }
310+ abi_params
311+ . iter ( )
214312 . map ( |( offset, param) | {
215- ptr. offset_i64 ( fx, offset. bytes ( ) as i64 ) . load ( fx, param. value_type , MemFlags :: new ( ) )
313+ scratch. offset_i64 ( fx, offset. bytes ( ) as i64 ) . load (
314+ fx,
315+ param. value_type ,
316+ MemFlags :: new ( ) ,
317+ )
216318 } )
217319 . collect ( )
218320}
@@ -224,14 +326,15 @@ pub(super) fn from_casted_value<'tcx>(
224326 cast : & CastTarget ,
225327) -> CValue < ' tcx > {
226328 let abi_params = cast_target_to_abi_params ( cast) ;
227- let abi_param_size: u32 = abi_params. iter ( ) . map ( |( _, param) | param. value_type . bytes ( ) ) . sum ( ) ;
228- let layout_size = u32:: try_from ( layout. size . bytes ( ) ) . unwrap ( ) ;
329+ let abi_param_size = abi_params_size ( & abi_params) ;
330+ let cast_align = cast. align ( fx) . bytes ( ) ;
331+ let layout_size = layout. size . bytes ( ) ;
332+ let layout_align = layout. align . bytes ( ) ;
333+ let slot_align = cast_align. max ( layout_align) ;
334+ let slot_size = abi_param_size. max ( layout_size) . next_multiple_of ( slot_align) ;
229335 let ptr = fx. create_stack_slot (
230- // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
231- // It may also be smaller for example when the type is a wrapper around an integer with a
232- // larger alignment than the integer.
233- std:: cmp:: max ( abi_param_size, layout_size) ,
234- u32:: try_from ( layout. align . bytes ( ) ) . unwrap ( ) ,
336+ u32:: try_from ( slot_size) . unwrap ( ) ,
337+ u32:: try_from ( slot_align) . unwrap ( ) ,
235338 ) ;
236339 let mut block_params_iter = block_params. iter ( ) . copied ( ) ;
237340 for ( offset, _) in abi_params {
@@ -293,7 +396,10 @@ pub(super) fn cvalue_for_param<'tcx>(
293396 . into_iter ( )
294397 . map ( |abi_param| {
295398 let block_param = block_params_iter. next ( ) . unwrap ( ) ;
296- assert_eq ! ( fx. bcx. func. dfg. value_type( block_param) , abi_param. value_type) ;
399+ assert_eq ! (
400+ fx. bcx. func. dfg. value_type( block_param) ,
401+ abi_param. value_type
402+ ) ;
297403 block_param
298404 } )
299405 . collect :: < SmallVec < [ _ ; 2 ] > > ( ) ;
@@ -321,7 +427,11 @@ pub(super) fn cvalue_for_param<'tcx>(
321427 PassMode :: Cast { ref cast, .. } => {
322428 from_casted_value ( fx, & block_params, arg_abi. layout , cast)
323429 }
324- PassMode :: Indirect { attrs, meta_attrs : None , on_stack : _ } => {
430+ PassMode :: Indirect {
431+ attrs,
432+ meta_attrs : None ,
433+ on_stack : _,
434+ } => {
325435 assert_eq ! ( block_params. len( ) , 1 , "{:?}" , block_params) ;
326436 if let Some ( pointee_align) = attrs. pointee_align
327437 && pointee_align < arg_abi. layout . align . abi
@@ -339,11 +449,22 @@ pub(super) fn cvalue_for_param<'tcx>(
339449 CValue :: by_ref ( Pointer :: new ( block_params[ 0 ] ) , arg_abi. layout )
340450 }
341451 }
342- PassMode :: Indirect { attrs : _, meta_attrs : Some ( _) , on_stack : _ } => {
452+ PassMode :: Indirect {
453+ attrs : _,
454+ meta_attrs : Some ( _) ,
455+ on_stack : _,
456+ } => {
343457 assert_eq ! ( block_params. len( ) , 2 , "{:?}" , block_params) ;
344- CValue :: by_ref_unsized ( Pointer :: new ( block_params[ 0 ] ) , block_params[ 1 ] , arg_abi. layout )
458+ CValue :: by_ref_unsized (
459+ Pointer :: new ( block_params[ 0 ] ) ,
460+ block_params[ 1 ] ,
461+ arg_abi. layout ,
462+ )
345463 }
346464 } ;
347465
348- Some ( ArgValue { value, is_underaligned_pointee : false } )
466+ Some ( ArgValue {
467+ value,
468+ is_underaligned_pointee : false ,
469+ } )
349470}
0 commit comments