@@ -256,7 +256,62 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
256
256
assert ! ( ( cases. len( ) - 1 ) as i64 >= 0 ) ;
257
257
let bounds = IntBounds { ulo : 0 , uhi : ( cases. len ( ) - 1 ) as u64 ,
258
258
slo : 0 , shi : ( cases. len ( ) - 1 ) as i64 } ;
259
- let ity = range_to_inttype ( cx, hint, & bounds) ;
259
+ let min_ity = range_to_inttype ( cx, hint, & bounds) ;
260
+
261
+ // Create the set of structs that represent each variant
262
+ // Use the minimum integer type we figured out above
263
+ let fields : Vec < _ > = cases. iter ( ) . map ( |c| {
264
+ let mut ftys = vec ! ( ty_of_inttype( min_ity) ) ;
265
+ ftys. push_all ( c. tys . as_slice ( ) ) ;
266
+ if dtor { ftys. push ( ty:: mk_bool ( ) ) ; }
267
+ mk_struct ( cx, ftys. as_slice ( ) , false , t)
268
+ } ) . collect ( ) ;
269
+
270
+
271
+ // Check to see if we should use a different type for the
272
+ // discriminant. If the overall alignment of the type is
273
+ // the same as the first field in each variant, we can safely use
274
+ // an alignment-sized type.
275
+ // We increase the size of the discriminant to avoid LLVM copying
276
+ // padding when it doesn't need to. This normally causes unaligned
277
+ // load/stores and excessive memcpy/memset operations. By using a
278
+ // bigger integer size, LLVM can be sure about it's contents and
279
+ // won't be so conservative.
280
+ // This check is needed to avoid increasing the size of types when
281
+ // the alignment of the first field is smaller than the overall
282
+ // alignment of the type.
283
+ let ( _, align) = union_size_and_align ( fields. as_slice ( ) ) ;
284
+ let mut use_align = true ;
285
+ for st in fields. iter ( ) {
286
+ // Get the first non-zero-sized field
287
+ let field = st. fields . iter ( ) . skip ( 1 ) . filter ( |ty| {
288
+ let t = type_of:: sizing_type_of ( cx, * * ty) ;
289
+ machine:: llsize_of_real ( cx, t) != 0 ||
290
+ // This case is only relevant for zero-sized types with large alignment
291
+ machine:: llalign_of_min ( cx, t) != 1
292
+ } ) . next ( ) ;
293
+
294
+ if let Some ( field) = field {
295
+ let field_align = type_of:: align_of ( cx, * field) ;
296
+ if field_align != align {
297
+ use_align = false ;
298
+ break ;
299
+ }
300
+ }
301
+ }
302
+ let ity = if use_align {
303
+ // Use the overall alignment
304
+ match align {
305
+ 1 => attr:: UnsignedInt ( ast:: TyU8 ) ,
306
+ 2 => attr:: UnsignedInt ( ast:: TyU16 ) ,
307
+ 4 => attr:: UnsignedInt ( ast:: TyU32 ) ,
308
+ 8 if machine:: llalign_of_min ( cx, Type :: i64 ( cx) ) == 8 =>
309
+ attr:: UnsignedInt ( ast:: TyU64 ) ,
310
+ _ => min_ity // use min_ity as a fallback
311
+ }
312
+ } else {
313
+ min_ity
314
+ } ;
260
315
261
316
let fields : Vec < _ > = cases. iter ( ) . map ( |c| {
262
317
let mut ftys = vec ! ( ty_of_inttype( ity) ) ;
@@ -570,7 +625,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
570
625
let discr_ty = ll_inttype ( cx, ity) ;
571
626
let discr_size = machine:: llsize_of_alloc ( cx, discr_ty) ;
572
627
let align_units = ( size + align_s - 1 ) / align_s - 1 ;
573
- let pad_ty = match align_s {
628
+ let fill_ty = match align_s {
574
629
1 => Type :: array ( & Type :: i8 ( cx) , align_units) ,
575
630
2 => Type :: array ( & Type :: i16 ( cx) , align_units) ,
576
631
4 => Type :: array ( & Type :: i32 ( cx) , align_units) ,
@@ -580,11 +635,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
580
635
align_units) ,
581
636
_ => panic ! ( "unsupported enum alignment: {}" , align)
582
637
} ;
583
- assert_eq ! ( machine:: llalign_of_min( cx, pad_ty ) , align) ;
638
+ assert_eq ! ( machine:: llalign_of_min( cx, fill_ty ) , align) ;
584
639
assert_eq ! ( align_s % discr_size, 0 ) ;
585
- let fields = vec ! ( discr_ty,
586
- Type :: array( & discr_ty, align_s / discr_size - 1 ) ,
587
- pad_ty ) ;
640
+ let fields = [ discr_ty,
641
+ Type :: array ( & discr_ty, align_s / discr_size - 1 ) ,
642
+ fill_ty ] ;
588
643
match name {
589
644
None => Type :: struct_ ( cx, fields[ ] , false ) ,
590
645
Some ( name) => {
0 commit comments