@@ -794,7 +794,7 @@ fn univariant(
794
794
let mut align = if pack. is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
795
795
let mut inverse_memory_index: IndexVec < u32 , FieldIdx > = fields. indices ( ) . collect ( ) ;
796
796
let optimize = !repr. inhibit_struct_field_reordering_opt ( ) ;
797
- if optimize {
797
+ if optimize && fields . len ( ) > 1 {
798
798
let end = if let StructKind :: MaybeUnsized = kind { fields. len ( ) - 1 } else { fields. len ( ) } ;
799
799
let optimizing = & mut inverse_memory_index. raw [ ..end] ;
800
800
@@ -814,7 +814,12 @@ fn univariant(
814
814
// Otherwise we just leave things alone and actually optimize the type's fields
815
815
} else {
816
816
let max_field_align = fields. iter ( ) . map ( |f| f. align ( ) . abi . bytes ( ) ) . max ( ) . unwrap_or ( 1 ) ;
817
- let any_niche = fields. iter ( ) . any ( |f| f. largest_niche ( ) . is_some ( ) ) ;
817
+ let largest_niche_size = fields
818
+ . iter ( )
819
+ . filter_map ( |f| f. largest_niche ( ) )
820
+ . map ( |n| n. available ( dl) )
821
+ . max ( )
822
+ . unwrap_or ( 0 ) ;
818
823
819
824
// Calculates a sort key to group fields by their alignment or possibly some size-derived
820
825
// pseudo-alignment.
@@ -829,13 +834,23 @@ fn univariant(
829
834
//
830
835
let align = layout. align ( ) . abi . bytes ( ) ;
831
836
let size = layout. size ( ) . bytes ( ) ;
837
+ let niche_size = layout. largest_niche ( ) . map ( |n| n. available ( dl) ) . unwrap_or ( 0 ) ;
832
838
// group [u8; 4] with align-4 or [u8; 6] with align-2 fields
833
839
let size_as_align = align. max ( size) . trailing_zeros ( ) ;
834
- // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
835
- // to the front in the first case (for aligned loads) but keep the bool in front
836
- // in the second case for its niches.
837
- let size_as_align = if any_niche {
838
- max_field_align. trailing_zeros ( ) . min ( size_as_align)
840
+ let size_as_align = if largest_niche_size > 0 {
841
+ match niche_bias {
842
+ // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
843
+ // to the front in the first case (for aligned loads) but keep the bool in front
844
+ // in the second case for its niches.
845
+ NicheBias :: Start => max_field_align. trailing_zeros ( ) . min ( size_as_align) ,
846
+ // When moving niches towards the end of the struct then for
847
+ // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
848
+ // in the align-1 group because its bool can be moved closer to the end.
849
+ NicheBias :: End if niche_size == largest_niche_size => {
850
+ align. trailing_zeros ( )
851
+ }
852
+ NicheBias :: End => size_as_align,
853
+ }
839
854
} else {
840
855
size_as_align
841
856
} ;
0 commit comments