@@ -12,7 +12,7 @@ use cranelift_codegen::ir::{
1212} ;
1313use cranelift_codegen:: isa:: CallConv ;
1414use cranelift_module:: ModuleError ;
15- use rustc_abi:: { CanonAbi , ExternAbi , X86Call } ;
15+ use rustc_abi:: { Align , CanonAbi , ExternAbi , X86Call } ;
1616use rustc_codegen_ssa:: base:: is_call_from_compiler_builtins_to_upstream_monomorphization;
1717use rustc_codegen_ssa:: errors:: CompilerBuiltinsCannotCall ;
1818use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
@@ -243,10 +243,17 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
243243 self :: returning:: codegen_return_param ( fx, & ssa_analyzed, & mut block_params_iter) ;
244244 assert_eq ! ( fx. local_map. push( ret_place) , RETURN_PLACE ) ;
245245
246- // None means pass_mode == NoPass
246+ struct ArgValue < ' tcx > {
247+ value : Option < CValue < ' tcx > > ,
248+ /// If set, the argument is a byval/byref pointer whose pointee alignment is smaller than
249+ /// the Rust ABI alignment. In that case the argument must be copied to a sufficiently
250+ /// aligned local stack slot before it can be treated as a place.
251+ underaligned_pointee_align : Option < Align > ,
252+ }
253+
247254 enum ArgKind < ' tcx > {
248- Normal ( Option < CValue < ' tcx > > ) ,
249- Spread ( Vec < Option < CValue < ' tcx > > > ) ,
255+ Normal ( ArgValue < ' tcx > ) ,
256+ Spread ( Vec < ArgValue < ' tcx > > ) ,
250257 }
251258
252259 // FIXME implement variadics in cranelift
@@ -280,17 +287,34 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
280287 let mut params = Vec :: new ( ) ;
281288 for ( i, _arg_ty) in tupled_arg_tys. iter ( ) . enumerate ( ) {
282289 let arg_abi = arg_abis_iter. next ( ) . unwrap ( ) ;
283- let param =
290+ let value =
284291 cvalue_for_param ( fx, Some ( local) , Some ( i) , arg_abi, & mut block_params_iter) ;
285- params. push ( param) ;
292+ let underaligned_pointee_align =
293+ match arg_abi. mode {
294+ PassMode :: Indirect { attrs, .. } => attrs
295+ . pointee_align
296+ . filter ( |& pointee_align| pointee_align < arg_abi. layout . align . abi ) ,
297+ _ => None ,
298+ } ;
299+ params. push ( ArgValue { value, underaligned_pointee_align } ) ;
286300 }
287301
288302 ( local, ArgKind :: Spread ( params) , arg_ty)
289303 } else {
290304 let arg_abi = arg_abis_iter. next ( ) . unwrap ( ) ;
291- let param =
305+ let value =
292306 cvalue_for_param ( fx, Some ( local) , None , arg_abi, & mut block_params_iter) ;
293- ( local, ArgKind :: Normal ( param) , arg_ty)
307+ let underaligned_pointee_align = match arg_abi. mode {
308+ PassMode :: Indirect { attrs, .. } => attrs
309+ . pointee_align
310+ . filter ( |& pointee_align| pointee_align < arg_abi. layout . align . abi ) ,
311+ _ => None ,
312+ } ;
313+ (
314+ local,
315+ ArgKind :: Normal ( ArgValue { value, underaligned_pointee_align } ) ,
316+ arg_ty,
317+ )
294318 }
295319 } )
296320 . collect :: < Vec < ( Local , ArgKind < ' tcx > , Ty < ' tcx > ) > > ( ) ;
@@ -311,7 +335,9 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
311335 for ( local, arg_kind, ty) in func_params {
312336 // While this is normally an optimization to prevent an unnecessary copy when an argument is
313337 // not mutated by the current function, this is necessary to support unsized arguments.
314- if let ArgKind :: Normal ( Some ( val) ) = arg_kind {
338+ if let ArgKind :: Normal ( ArgValue { value : Some ( val) , underaligned_pointee_align : None } ) =
339+ arg_kind
340+ {
315341 if let Some ( ( addr, meta) ) = val. try_to_ptr ( ) {
316342 // Ownership of the value at the backing storage for an argument is passed to the
317343 // callee per the ABI, so it is fine to borrow the backing storage of this argument
@@ -336,15 +362,74 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
336362 assert_eq ! ( fx. local_map. push( place) , local) ;
337363
338364 match arg_kind {
339- ArgKind :: Normal ( param) => {
340- if let Some ( param) = param {
365+ ArgKind :: Normal ( ArgValue { value : Some ( param) , underaligned_pointee_align } ) => {
366+ if let Some ( pointee_align) = underaligned_pointee_align
367+ && let Some ( dst_ptr) = place. try_to_ptr ( )
368+ && let Some ( ( src_ptr, None ) ) = param. try_to_ptr ( )
369+ && layout. size != Size :: ZERO
370+ {
371+ let mut flags = MemFlags :: new ( ) ;
372+ flags. set_notrap ( ) ;
373+
374+ let to_addr = dst_ptr. get_addr ( fx) ;
375+ let from_addr = src_ptr. get_addr ( fx) ;
376+ let size = layout. size . bytes ( ) ;
377+
378+ // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum
379+ // alignment that fits in a `u8` if the actual alignment is larger.
380+ let dst_align = layout. align . bytes ( ) . try_into ( ) . unwrap_or ( 128 ) ;
381+ let src_align = pointee_align. bytes ( ) . try_into ( ) . unwrap_or ( 128 ) ;
382+
383+ fx. bcx . emit_small_memory_copy (
384+ fx. target_config ,
385+ to_addr,
386+ from_addr,
387+ size,
388+ dst_align,
389+ src_align,
390+ true ,
391+ flags,
392+ ) ;
393+ } else {
341394 place. write_cvalue ( fx, param) ;
342395 }
343396 }
397+ ArgKind :: Normal ( ArgValue { value : None , underaligned_pointee_align : _ } ) => { }
344398 ArgKind :: Spread ( params) => {
345- for ( i, param) in params. into_iter ( ) . enumerate ( ) {
399+ for ( i, ArgValue { value : param, underaligned_pointee_align } ) in
400+ params. into_iter ( ) . enumerate ( )
401+ {
346402 if let Some ( param) = param {
347- place. place_field ( fx, FieldIdx :: new ( i) ) . write_cvalue ( fx, param) ;
403+ let field_place = place. place_field ( fx, FieldIdx :: new ( i) ) ;
404+ let field_layout = field_place. layout ( ) ;
405+ if let Some ( pointee_align) = underaligned_pointee_align
406+ && let Some ( dst_ptr) = field_place. try_to_ptr ( )
407+ && let Some ( ( src_ptr, None ) ) = param. try_to_ptr ( )
408+ && field_layout. size != Size :: ZERO
409+ {
410+ let mut flags = MemFlags :: new ( ) ;
411+ flags. set_notrap ( ) ;
412+
413+ let to_addr = dst_ptr. get_addr ( fx) ;
414+ let from_addr = src_ptr. get_addr ( fx) ;
415+ let size = field_layout. size . bytes ( ) ;
416+
417+ let dst_align = field_layout. align . bytes ( ) . try_into ( ) . unwrap_or ( 128 ) ;
418+ let src_align = pointee_align. bytes ( ) . try_into ( ) . unwrap_or ( 128 ) ;
419+
420+ fx. bcx . emit_small_memory_copy (
421+ fx. target_config ,
422+ to_addr,
423+ from_addr,
424+ size,
425+ dst_align,
426+ src_align,
427+ true ,
428+ flags,
429+ ) ;
430+ } else {
431+ field_place. write_cvalue ( fx, param) ;
432+ }
348433 }
349434 }
350435 }
0 commit comments