11use crate :: abi:: FnAbi ;
22use crate :: common:: * ;
3+ use crate :: context:: TypeLowering ;
34use crate :: type_:: Type ;
45use rustc_codegen_ssa:: traits:: * ;
56use rustc_middle:: bug;
@@ -9,6 +10,7 @@ use rustc_middle::ty::{self, Ty, TypeFoldable};
910use rustc_target:: abi:: { Abi , AddressSpace , Align , FieldsShape } ;
1011use rustc_target:: abi:: { Int , Pointer , F32 , F64 } ;
1112use rustc_target:: abi:: { LayoutOf , PointeeInfo , Scalar , Size , TyAndLayoutMethods , Variants } ;
13+ use smallvec:: { smallvec, SmallVec } ;
1214use tracing:: debug;
1315
1416use std:: fmt:: Write ;
@@ -17,6 +19,7 @@ fn uncached_llvm_type<'a, 'tcx>(
1719 cx : & CodegenCx < ' a , ' tcx > ,
1820 layout : TyAndLayout < ' tcx > ,
1921 defer : & mut Option < ( & ' a Type , TyAndLayout < ' tcx > ) > ,
22+ field_remapping : & mut Option < SmallVec < [ u32 ; 4 ] > > ,
2023) -> & ' a Type {
2124 match layout. abi {
2225 Abi :: Scalar ( _) => bug ! ( "handled elsewhere" ) ,
@@ -75,7 +78,8 @@ fn uncached_llvm_type<'a, 'tcx>(
7578 FieldsShape :: Array { count, .. } => cx. type_array ( layout. field ( cx, 0 ) . llvm_type ( cx) , count) ,
7679 FieldsShape :: Arbitrary { .. } => match name {
7780 None => {
78- let ( llfields, packed) = struct_llfields ( cx, layout) ;
81+ let ( llfields, packed, new_field_remapping) = struct_llfields ( cx, layout) ;
82+ * field_remapping = new_field_remapping;
7983 cx. type_struct ( & llfields, packed)
8084 }
8185 Some ( ref name) => {
@@ -90,14 +94,15 @@ fn uncached_llvm_type<'a, 'tcx>(
9094fn struct_llfields < ' a , ' tcx > (
9195 cx : & CodegenCx < ' a , ' tcx > ,
9296 layout : TyAndLayout < ' tcx > ,
93- ) -> ( Vec < & ' a Type > , bool ) {
97+ ) -> ( Vec < & ' a Type > , bool , Option < SmallVec < [ u32 ; 4 ] > > ) {
9498 debug ! ( "struct_llfields: {:#?}" , layout) ;
9599 let field_count = layout. fields . count ( ) ;
96100
97101 let mut packed = false ;
98102 let mut offset = Size :: ZERO ;
99103 let mut prev_effective_align = layout. align . abi ;
100104 let mut result: Vec < _ > = Vec :: with_capacity ( 1 + field_count * 2 ) ;
105+ let mut field_remapping = smallvec ! [ 0 ; field_count] ;
101106 for i in layout. fields . index_by_increasing_offset ( ) {
102107 let target_offset = layout. fields . offset ( i as usize ) ;
103108 let field = layout. field ( cx, i) ;
@@ -116,33 +121,37 @@ fn struct_llfields<'a, 'tcx>(
116121 ) ;
117122 assert ! ( target_offset >= offset) ;
118123 let padding = target_offset - offset;
119- let padding_align = prev_effective_align. min ( effective_field_align) ;
120- assert_eq ! ( offset. align_to( padding_align) + padding, target_offset) ;
121- result. push ( cx. type_padding_filler ( padding, padding_align) ) ;
122- debug ! ( " padding before: {:?}" , padding) ;
123-
124+ if padding != Size :: ZERO {
125+ let padding_align = prev_effective_align. min ( effective_field_align) ;
126+ assert_eq ! ( offset. align_to( padding_align) + padding, target_offset) ;
127+ result. push ( cx. type_padding_filler ( padding, padding_align) ) ;
128+ debug ! ( " padding before: {:?}" , padding) ;
129+ }
130+ field_remapping[ i] = result. len ( ) as u32 ;
124131 result. push ( field. llvm_type ( cx) ) ;
125132 offset = target_offset + field. size ;
126133 prev_effective_align = effective_field_align;
127134 }
135+ let padding_used = result. len ( ) > field_count;
128136 if !layout. is_unsized ( ) && field_count > 0 {
129137 if offset > layout. size {
130138 bug ! ( "layout: {:#?} stride: {:?} offset: {:?}" , layout, layout. size, offset) ;
131139 }
132140 let padding = layout. size - offset;
133- let padding_align = prev_effective_align;
134- assert_eq ! ( offset. align_to( padding_align) + padding, layout. size) ;
135- debug ! (
136- "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}" ,
137- padding, offset, layout. size
138- ) ;
139- result. push ( cx. type_padding_filler ( padding, padding_align) ) ;
140- assert_eq ! ( result. len( ) , 1 + field_count * 2 ) ;
141+ if padding != Size :: ZERO {
142+ let padding_align = prev_effective_align;
143+ assert_eq ! ( offset. align_to( padding_align) + padding, layout. size) ;
144+ debug ! (
145+ "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}" ,
146+ padding, offset, layout. size
147+ ) ;
148+ result. push ( cx. type_padding_filler ( padding, padding_align) ) ;
149+ }
141150 } else {
142151 debug ! ( "struct_llfields: offset: {:?} stride: {:?}" , offset, layout. size) ;
143152 }
144-
145- ( result, packed)
153+ let field_remapping = if padding_used { Some ( field_remapping ) } else { None } ;
154+ ( result, packed, field_remapping )
146155}
147156
148157impl < ' a , ' tcx > CodegenCx < ' a , ' tcx > {
@@ -177,7 +186,7 @@ pub trait LayoutLlvmExt<'tcx> {
177186 index : usize ,
178187 immediate : bool ,
179188 ) -> & ' a Type ;
180- fn llvm_field_index ( & self , index : usize ) -> u64 ;
189+ fn llvm_field_index < ' a > ( & self , cx : & CodegenCx < ' a , ' tcx > , index : usize ) -> u64 ;
181190 fn pointee_info_at < ' a > ( & self , cx : & CodegenCx < ' a , ' tcx > , offset : Size ) -> Option < PointeeInfo > ;
182191}
183192
@@ -234,8 +243,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
234243 Variants :: Single { index } => Some ( index) ,
235244 _ => None ,
236245 } ;
237- if let Some ( & llty) = cx. lltypes . borrow ( ) . get ( & ( self . ty , variant_index) ) {
238- return llty;
246+ if let Some ( ref llty) = cx. type_lowering . borrow ( ) . get ( & ( self . ty , variant_index) ) {
247+ return llty. lltype ;
239248 }
240249
241250 debug ! ( "llvm_type({:#?})" , self ) ;
@@ -247,24 +256,32 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
247256 let normal_ty = cx. tcx . erase_regions ( self . ty ) ;
248257
249258 let mut defer = None ;
259+ let mut field_remapping = None ;
250260 let llty = if self . ty != normal_ty {
251261 let mut layout = cx. layout_of ( normal_ty) ;
252262 if let Some ( v) = variant_index {
253263 layout = layout. for_variant ( cx, v) ;
254264 }
255265 layout. llvm_type ( cx)
256266 } else {
257- uncached_llvm_type ( cx, * self , & mut defer)
267+ uncached_llvm_type ( cx, * self , & mut defer, & mut field_remapping )
258268 } ;
259269 debug ! ( "--> mapped {:#?} to llty={:?}" , self , llty) ;
260270
261- cx. lltypes . borrow_mut ( ) . insert ( ( self . ty , variant_index) , llty) ;
271+ cx. type_lowering . borrow_mut ( ) . insert (
272+ ( self . ty , variant_index) ,
273+ TypeLowering { lltype : llty, field_remapping : field_remapping } ,
274+ ) ;
262275
263276 if let Some ( ( llty, layout) ) = defer {
264- let ( llfields, packed) = struct_llfields ( cx, layout) ;
265- cx. set_struct_body ( llty, & llfields, packed)
277+ let ( llfields, packed, new_field_remapping) = struct_llfields ( cx, layout) ;
278+ cx. set_struct_body ( llty, & llfields, packed) ;
279+ cx. type_lowering
280+ . borrow_mut ( )
281+ . get_mut ( & ( self . ty , variant_index) )
282+ . unwrap ( )
283+ . field_remapping = new_field_remapping;
266284 }
267-
268285 llty
269286 }
270287
@@ -340,7 +357,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
340357 self . scalar_llvm_type_at ( cx, scalar, offset)
341358 }
342359
343- fn llvm_field_index ( & self , index : usize ) -> u64 {
360+ fn llvm_field_index < ' a > ( & self , cx : & CodegenCx < ' a , ' tcx > , index : usize ) -> u64 {
344361 match self . abi {
345362 Abi :: Scalar ( _) | Abi :: ScalarPair ( ..) => {
346363 bug ! ( "TyAndLayout::llvm_field_index({:?}): not applicable" , self )
@@ -354,7 +371,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
354371
355372 FieldsShape :: Array { .. } => index as u64 ,
356373
357- FieldsShape :: Arbitrary { .. } => 1 + ( self . fields . memory_index ( index) as u64 ) * 2 ,
374+ FieldsShape :: Arbitrary { .. } => {
375+ let variant_index = match self . variants {
376+ Variants :: Single { index } => Some ( index) ,
377+ _ => None ,
378+ } ;
379+
380+ // Look up llvm field if indexes do not match memory order due to padding. If
381+ // `field_remapping` is `None` no padding was used and the llvm field index
382+ // matches the memory index.
383+ match cx. type_lowering . borrow ( ) . get ( & ( self . ty , variant_index) ) {
384+ Some ( TypeLowering { field_remapping : Some ( ref remap) , .. } ) => {
385+ remap[ index] as u64
386+ }
387+ Some ( _) => self . fields . memory_index ( index) as u64 ,
388+ None => {
389+ bug ! ( "TyAndLayout::llvm_field_index({:?}): type info not found" , self )
390+ }
391+ }
392+ }
358393 }
359394 }
360395
0 commit comments