1
+ use std:: cmp;
2
+
1
3
use libc:: c_uint;
2
4
use rustc_abi:: BackendRepr :: Scalar ;
5
+ use rustc_abi:: Size ;
3
6
use rustc_abi:: { HasDataLayout , Primitive , Reg , RegKind } ;
7
+ use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
4
8
use rustc_codegen_ssa:: mir:: operand:: OperandValue ;
5
9
use rustc_codegen_ssa:: mir:: place:: { PlaceRef , PlaceValue } ;
6
10
use rustc_codegen_ssa:: { MemFlags , traits:: * } ;
@@ -193,42 +197,39 @@ impl LlvmType for Reg {
193
197
impl LlvmType for CastTarget {
194
198
fn llvm_type < ' ll > ( & self , cx : & CodegenCx < ' ll , ' _ > ) -> & ' ll Type {
195
199
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
198
202
} 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 ( ) )
203
213
} ;
204
214
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.
205
217
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 ( ) ) {
208
222
return rest_ll_unit;
209
223
}
210
224
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) ;
230
226
}
231
227
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 ( ) ;
232
233
cx. type_struct ( & args, false )
233
234
}
234
235
}
@@ -306,7 +307,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
306
307
old_ret_ty = None ;
307
308
}
308
309
309
- for arg in self . args . iter ( ) {
310
+ for arg in args {
310
311
let llarg_ty = match & arg. mode {
311
312
PassMode :: Ignore => continue ,
312
313
PassMode :: Direct ( _) => arg. layout . immediate_llvm_type ( cx) ,
@@ -356,6 +357,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
356
357
cx. type_func ( & llargument_tys, llreturn_ty)
357
358
} ;
358
359
if !transformed_types. is_empty ( ) || old_ret_ty. is_some ( ) {
360
+ trace ! ( "remapping args in {:?} to {:?}" , ty, transformed_types) ;
359
361
cx. remapped_integer_args
360
362
. borrow_mut ( )
361
363
. insert ( ty, ( old_ret_ty, transformed_types) ) ;
@@ -373,7 +375,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
373
375
}
374
376
375
377
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 ( ) {
377
379
llvm:: Attribute :: NoReturn . apply_llfn ( llvm:: AttributePlace :: Function , llfn) ;
378
380
}
379
381
@@ -484,6 +486,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
484
486
// by the LLVM verifier.
485
487
if let Primitive :: Int ( ..) = scalar. primitive ( ) {
486
488
if !scalar. is_bool ( ) && !scalar. is_always_valid ( bx) {
489
+ trace ! ( "apply_attrs_callsite -> range_metadata" ) ;
487
490
bx. range_metadata ( callsite, scalar. valid_range ( bx) ) ;
488
491
}
489
492
}
@@ -532,9 +535,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
532
535
impl < ' a , ' ll , ' tcx > AbiBuilderMethods < ' tcx > for Builder < ' a , ' ll , ' tcx > {
533
536
fn get_param ( & mut self , index : usize ) -> Self :: Value {
534
537
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 {
537
540
let llfnty = LLVMRustGetFunctionType ( self . llfn ( ) ) ;
541
+ trace ! ( "llfnty: {:?}" , llfnty) ;
538
542
// destructure so rustc doesnt complain in the call to transmute_llval
539
543
let Self { cx, llbuilder } = self ;
540
544
let map = cx. remapped_integer_args . borrow ( ) ;
@@ -545,7 +549,9 @@ impl<'a, 'll, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
545
549
}
546
550
}
547
551
val
548
- }
552
+ } ;
553
+ trace ! ( "Get param `{:?}`" , val) ;
554
+ val
549
555
}
550
556
}
551
557
@@ -591,7 +597,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
591
597
on_stack : _,
592
598
} => {
593
599
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) )
595
601
. store ( bx, dst) ;
596
602
}
597
603
// Unsized indirect arguments
@@ -603,35 +609,40 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
603
609
bug ! ( "unsized `ArgAbi` must be handled through `store_fn_arg`" ) ;
604
610
}
605
611
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
+ ) ;
627
640
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" ) ;
632
643
}
633
644
_ => {
634
- OperandValue :: Immediate ( val) . store ( bx, dst) ;
645
+ OperandRef :: from_immediate_or_packed_pair ( bx , val, self . layout ) . val . store ( bx, dst) ;
635
646
}
636
647
}
637
648
}
@@ -665,11 +676,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
665
676
OperandValue :: Ref ( place_val) . store ( bx, dst) ;
666
677
}
667
678
PassMode :: Direct ( _)
668
- | PassMode :: Indirect {
669
- attrs : _,
670
- meta_attrs : None ,
671
- on_stack : _,
672
- }
679
+ | PassMode :: Indirect { attrs : _, meta_attrs : None , on_stack : _, }
673
680
| PassMode :: Cast { .. } => {
674
681
let next_arg = next ( ) ;
675
682
self . store ( bx, next_arg, dst) ;
0 commit comments