1
1
use crate :: abi:: FnAbi ;
2
2
use crate :: common:: * ;
3
+ use crate :: context:: TypeLowering ;
3
4
use crate :: type_:: Type ;
4
5
use rustc_codegen_ssa:: traits:: * ;
5
6
use rustc_middle:: bug;
@@ -9,6 +10,7 @@ use rustc_middle::ty::{self, Ty, TypeFoldable};
9
10
use rustc_target:: abi:: { Abi , AddressSpace , Align , FieldsShape } ;
10
11
use rustc_target:: abi:: { Int , Pointer , F32 , F64 } ;
11
12
use rustc_target:: abi:: { LayoutOf , PointeeInfo , Scalar , Size , TyAndLayoutMethods , Variants } ;
13
+ use smallvec:: { smallvec, SmallVec } ;
12
14
use tracing:: debug;
13
15
14
16
use std:: fmt:: Write ;
@@ -17,6 +19,7 @@ fn uncached_llvm_type<'a, 'tcx>(
17
19
cx : & CodegenCx < ' a , ' tcx > ,
18
20
layout : TyAndLayout < ' tcx > ,
19
21
defer : & mut Option < ( & ' a Type , TyAndLayout < ' tcx > ) > ,
22
+ field_remapping : & mut Option < SmallVec < [ u32 ; 4 ] > > ,
20
23
) -> & ' a Type {
21
24
match layout. abi {
22
25
Abi :: Scalar ( _) => bug ! ( "handled elsewhere" ) ,
@@ -75,7 +78,8 @@ fn uncached_llvm_type<'a, 'tcx>(
75
78
FieldsShape :: Array { count, .. } => cx. type_array ( layout. field ( cx, 0 ) . llvm_type ( cx) , count) ,
76
79
FieldsShape :: Arbitrary { .. } => match name {
77
80
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;
79
83
cx. type_struct ( & llfields, packed)
80
84
}
81
85
Some ( ref name) => {
@@ -90,14 +94,15 @@ fn uncached_llvm_type<'a, 'tcx>(
90
94
fn struct_llfields < ' a , ' tcx > (
91
95
cx : & CodegenCx < ' a , ' tcx > ,
92
96
layout : TyAndLayout < ' tcx > ,
93
- ) -> ( Vec < & ' a Type > , bool ) {
97
+ ) -> ( Vec < & ' a Type > , bool , Option < SmallVec < [ u32 ; 4 ] > > ) {
94
98
debug ! ( "struct_llfields: {:#?}" , layout) ;
95
99
let field_count = layout. fields . count ( ) ;
96
100
97
101
let mut packed = false ;
98
102
let mut offset = Size :: ZERO ;
99
103
let mut prev_effective_align = layout. align . abi ;
100
104
let mut result: Vec < _ > = Vec :: with_capacity ( 1 + field_count * 2 ) ;
105
+ let mut field_remapping = smallvec ! [ 0 ; field_count] ;
101
106
for i in layout. fields . index_by_increasing_offset ( ) {
102
107
let target_offset = layout. fields . offset ( i as usize ) ;
103
108
let field = layout. field ( cx, i) ;
@@ -116,33 +121,37 @@ fn struct_llfields<'a, 'tcx>(
116
121
) ;
117
122
assert ! ( target_offset >= offset) ;
118
123
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 ;
124
131
result. push ( field. llvm_type ( cx) ) ;
125
132
offset = target_offset + field. size ;
126
133
prev_effective_align = effective_field_align;
127
134
}
135
+ let padding_used = result. len ( ) > field_count;
128
136
if !layout. is_unsized ( ) && field_count > 0 {
129
137
if offset > layout. size {
130
138
bug ! ( "layout: {:#?} stride: {:?} offset: {:?}" , layout, layout. size, offset) ;
131
139
}
132
140
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
+ }
141
150
} else {
142
151
debug ! ( "struct_llfields: offset: {:?} stride: {:?}" , offset, layout. size) ;
143
152
}
144
-
145
- ( result, packed)
153
+ let field_remapping = if padding_used { Some ( field_remapping ) } else { None } ;
154
+ ( result, packed, field_remapping )
146
155
}
147
156
148
157
impl < ' a , ' tcx > CodegenCx < ' a , ' tcx > {
@@ -177,7 +186,7 @@ pub trait LayoutLlvmExt<'tcx> {
177
186
index : usize ,
178
187
immediate : bool ,
179
188
) -> & ' 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 ;
181
190
fn pointee_info_at < ' a > ( & self , cx : & CodegenCx < ' a , ' tcx > , offset : Size ) -> Option < PointeeInfo > ;
182
191
}
183
192
@@ -234,8 +243,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
234
243
Variants :: Single { index } => Some ( index) ,
235
244
_ => None ,
236
245
} ;
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 ;
239
248
}
240
249
241
250
debug ! ( "llvm_type({:#?})" , self ) ;
@@ -247,24 +256,32 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
247
256
let normal_ty = cx. tcx . erase_regions ( self . ty ) ;
248
257
249
258
let mut defer = None ;
259
+ let mut field_remapping = None ;
250
260
let llty = if self . ty != normal_ty {
251
261
let mut layout = cx. layout_of ( normal_ty) ;
252
262
if let Some ( v) = variant_index {
253
263
layout = layout. for_variant ( cx, v) ;
254
264
}
255
265
layout. llvm_type ( cx)
256
266
} else {
257
- uncached_llvm_type ( cx, * self , & mut defer)
267
+ uncached_llvm_type ( cx, * self , & mut defer, & mut field_remapping )
258
268
} ;
259
269
debug ! ( "--> mapped {:#?} to llty={:?}" , self , llty) ;
260
270
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
+ ) ;
262
275
263
276
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;
266
284
}
267
-
268
285
llty
269
286
}
270
287
@@ -340,7 +357,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
340
357
self . scalar_llvm_type_at ( cx, scalar, offset)
341
358
}
342
359
343
- fn llvm_field_index ( & self , index : usize ) -> u64 {
360
+ fn llvm_field_index < ' a > ( & self , cx : & CodegenCx < ' a , ' tcx > , index : usize ) -> u64 {
344
361
match self . abi {
345
362
Abi :: Scalar ( _) | Abi :: ScalarPair ( ..) => {
346
363
bug ! ( "TyAndLayout::llvm_field_index({:?}): not applicable" , self )
@@ -354,7 +371,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
354
371
355
372
FieldsShape :: Array { .. } => index as u64 ,
356
373
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
+ }
358
393
}
359
394
}
360
395
0 commit comments