1+ use std:: cmp;
2+
13use libc:: c_uint;
24use rustc_abi:: BackendRepr :: Scalar ;
5+ use rustc_abi:: Size ;
36use rustc_abi:: { HasDataLayout , Primitive , Reg , RegKind } ;
7+ use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
48use rustc_codegen_ssa:: mir:: operand:: OperandValue ;
59use rustc_codegen_ssa:: mir:: place:: { PlaceRef , PlaceValue } ;
610use rustc_codegen_ssa:: { MemFlags , traits:: * } ;
@@ -193,42 +197,39 @@ impl LlvmType for Reg {
193197impl LlvmType for CastTarget {
194198 fn llvm_type < ' ll > ( & self , cx : & CodegenCx < ' ll , ' _ > ) -> & ' ll Type {
195199 let rest_ll_unit = self . rest . unit . llvm_type ( cx) ;
196- let ( rest_count, rem_bytes ) = if self . rest . unit . size . bytes ( ) == 0 {
197- ( 0 , 0 )
200+ let rest_count = if self . rest . total == Size :: ZERO {
201+ 0
198202 } else {
199- (
200- self . rest . total . bytes ( ) / self . rest . unit . size . bytes ( ) ,
201- self . rest . total . bytes ( ) % self . rest . unit . size . bytes ( ) ,
202- )
203+ assert_ne ! (
204+ self . rest. unit. size,
205+ Size :: ZERO ,
206+ "total size {:?} cannot be divided into units of zero size" ,
207+ self . rest. total
208+ ) ;
209+ if self . rest . total . bytes ( ) % self . rest . unit . size . bytes ( ) != 0 {
210+ assert_eq ! ( self . rest. unit. kind, RegKind :: Integer , "only int regs can be split" ) ;
211+ }
212+ self . rest . total . bytes ( ) . div_ceil ( self . rest . unit . size . bytes ( ) )
203213 } ;
204214
215+ // Simplify to a single unit or an array if there's no prefix.
216+ // This produces the same layout, but using a simpler type.
205217 if self . prefix . iter ( ) . all ( |x| x. is_none ( ) ) {
206- // Simplify to a single unit when there is no prefix and size <= unit size
207- if self . rest . total <= self . rest . unit . size {
218+ // We can't do this if is_consecutive is set and the unit would get
219+ // split on the target. Currently, this is only relevant for i128
220+ // registers.
221+ if rest_count == 1 && ( !self . rest . is_consecutive || self . rest . unit != Reg :: i128 ( ) ) {
208222 return rest_ll_unit;
209223 }
210224
211- // Simplify to array when all chunks are the same size and type
212- if rem_bytes == 0 {
213- return cx. type_array ( rest_ll_unit, rest_count) ;
214- }
215- }
216-
217- // Create list of fields in the main structure
218- let mut args: Vec < _ > = self
219- . prefix
220- . iter ( )
221- . flat_map ( |option_reg| option_reg. map ( |reg| reg. llvm_type ( cx) ) )
222- . chain ( ( 0 ..rest_count) . map ( |_| rest_ll_unit) )
223- . collect ( ) ;
224-
225- // Append final integer
226- if rem_bytes != 0 {
227- // Only integers can be really split further.
228- assert_eq ! ( self . rest. unit. kind, RegKind :: Integer ) ;
229- args. push ( cx. type_ix ( rem_bytes * 8 ) ) ;
225+ return cx. type_array ( rest_ll_unit, rest_count) ;
230226 }
231227
228+ // Generate a struct type with the prefix and the "rest" arguments.
229+ let prefix_args =
230+ self . prefix . iter ( ) . flat_map ( |option_reg| option_reg. map ( |reg| reg. llvm_type ( cx) ) ) ;
231+ let rest_args = ( 0 ..rest_count) . map ( |_| rest_ll_unit) ;
232+ let args: Vec < _ > = prefix_args. chain ( rest_args) . collect ( ) ;
232233 cx. type_struct ( & args, false )
233234 }
234235}
@@ -306,7 +307,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
306307 old_ret_ty = None ;
307308 }
308309
309- for arg in self . args . iter ( ) {
310+ for arg in args {
310311 let llarg_ty = match & arg. mode {
311312 PassMode :: Ignore => continue ,
312313 PassMode :: Direct ( _) => arg. layout . immediate_llvm_type ( cx) ,
@@ -356,6 +357,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
356357 cx. type_func ( & llargument_tys, llreturn_ty)
357358 } ;
358359 if !transformed_types. is_empty ( ) || old_ret_ty. is_some ( ) {
360+ trace ! ( "remapping args in {:?} to {:?}" , ty, transformed_types) ;
359361 cx. remapped_integer_args
360362 . borrow_mut ( )
361363 . insert ( ty, ( old_ret_ty, transformed_types) ) ;
@@ -373,7 +375,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
373375 }
374376
375377 fn apply_attrs_llfn ( & self , cx : & CodegenCx < ' ll , ' tcx > , llfn : & ' ll Value ) {
376- if self . ret . layout . backend_repr . is_uninhabited ( ) {
378+ if self . ret . layout . is_uninhabited ( ) {
377379 llvm:: Attribute :: NoReturn . apply_llfn ( llvm:: AttributePlace :: Function , llfn) ;
378380 }
379381
@@ -484,6 +486,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
484486 // by the LLVM verifier.
485487 if let Primitive :: Int ( ..) = scalar. primitive ( ) {
486488 if !scalar. is_bool ( ) && !scalar. is_always_valid ( bx) {
489+ trace ! ( "apply_attrs_callsite -> range_metadata" ) ;
487490 bx. range_metadata ( callsite, scalar. valid_range ( bx) ) ;
488491 }
489492 }
@@ -532,9 +535,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
532535impl < ' a , ' ll , ' tcx > AbiBuilderMethods < ' tcx > for Builder < ' a , ' ll , ' tcx > {
533536 fn get_param ( & mut self , index : usize ) -> Self :: Value {
534537 let val = llvm:: get_param ( self . llfn ( ) , index as c_uint ) ;
535- trace ! ( "Get param `{:?}`" , val) ;
536- unsafe {
538+ // trace!("Get param `{:?}`", val);
539+ let val = unsafe {
537540 let llfnty = LLVMRustGetFunctionType ( self . llfn ( ) ) ;
541+ trace ! ( "llfnty: {:?}" , llfnty) ;
538542 // destructure so rustc doesnt complain in the call to transmute_llval
539543 let Self { cx, llbuilder } = self ;
540544 let map = cx. remapped_integer_args . borrow ( ) ;
@@ -545,7 +549,9 @@ impl<'a, 'll, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
545549 }
546550 }
547551 val
548- }
552+ } ;
553+ trace ! ( "Get param `{:?}`" , val) ;
554+ val
549555 }
550556}
551557
@@ -591,7 +597,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
591597 on_stack : _,
592598 } => {
593599 let align = attrs. pointee_align . unwrap_or ( self . layout . align . abi ) ;
594- OperandValue :: Ref ( PlaceValue :: new_sized ( val, self . layout . align . pref ) )
600+ OperandValue :: Ref ( PlaceValue :: new_sized ( val, align) )
595601 . store ( bx, dst) ;
596602 }
597603 // Unsized indirect arguments
@@ -603,35 +609,40 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
603609 bug ! ( "unsized `ArgAbi` must be handled through `store_fn_arg`" ) ;
604610 }
605611 PassMode :: Cast { pad_i32 : _, cast } => {
606- let can_store_through_cast_ptr = false ;
607- if can_store_through_cast_ptr {
608- let cast_ptr_llty = bx. type_ptr_to ( cast. llvm_type ( bx) ) ;
609- let cast_dst = bx. pointercast ( dst. val . llval , cast_ptr_llty) ;
610- bx. store ( val, cast_dst, self . layout . align . abi ) ;
611- } else {
612- let scratch_size = cast. size ( bx) ;
613- let scratch_align = cast. align ( bx) ;
614- let llscratch = bx. alloca ( scratch_size, scratch_align) ;
615- bx. lifetime_start ( llscratch, scratch_size) ;
616-
617- bx. store ( val, llscratch, scratch_align) ;
618-
619- bx. memcpy (
620- dst. val . llval ,
621- self . layout . align . abi ,
622- llscratch,
623- scratch_align,
624- bx. const_usize ( self . layout . size . bytes ( ) ) ,
625- MemFlags :: empty ( ) ,
626- ) ;
612+ trace ! ( "store cast" ) ;
613+ // The ABI mandates that the value is passed as a different struct representation.
614+ // Spill and reload it from the stack to convert from the ABI representation to
615+ // the Rust representation.
616+ let scratch_size = cast. size ( bx) ;
617+ let scratch_align = cast. align ( bx) ;
618+ // Note that the ABI type may be either larger or smaller than the Rust type,
619+ // due to the presence or absence of trailing padding. For example:
620+ // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
621+ // when passed by value, making it smaller.
622+ // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
623+ // when passed by value, making it larger.
624+ let copy_bytes =
625+ cmp:: min ( cast. unaligned_size ( bx) . bytes ( ) , self . layout . size . bytes ( ) ) ;
626+ // Allocate some scratch space...
627+ let llscratch = bx. alloca ( scratch_size, scratch_align) ;
628+ bx. lifetime_start ( llscratch, scratch_size) ;
629+ // ...store the value...
630+ bx. store ( val, llscratch, scratch_align) ;
631+ // ... and then memcpy it to the intended destination.
632+ bx. memcpy (
633+ dst. val . llval ,
634+ self . layout . align . abi ,
635+ llscratch,
636+ scratch_align,
637+ bx. const_usize ( copy_bytes) ,
638+ MemFlags :: empty ( ) ,
639+ ) ;
627640
628- bx. lifetime_end ( llscratch, scratch_size) ;
629- bx. lifetime_end ( llscratch, scratch_size) ;
630- bx. lifetime_end ( llscratch, scratch_size) ;
631- }
641+ bx. lifetime_end ( llscratch, scratch_size) ;
642+ trace ! ( "store cast end" ) ;
632643 }
633644 _ => {
634- OperandValue :: Immediate ( val) . store ( bx, dst) ;
645+ OperandRef :: from_immediate_or_packed_pair ( bx , val, self . layout ) . val . store ( bx, dst) ;
635646 }
636647 }
637648 }
@@ -665,11 +676,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
665676 OperandValue :: Ref ( place_val) . store ( bx, dst) ;
666677 }
667678 PassMode :: Direct ( _)
668- | PassMode :: Indirect {
669- attrs : _,
670- meta_attrs : None ,
671- on_stack : _,
672- }
679+ | PassMode :: Indirect { attrs : _, meta_attrs : None , on_stack : _, }
673680 | PassMode :: Cast { .. } => {
674681 let next_arg = next ( ) ;
675682 self . store ( bx, next_arg, dst) ;
0 commit comments