@@ -649,13 +649,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
649
649
use SavedLocalEligibility :: * ;
650
650
651
651
let mut assignments: IndexVec < GeneratorSavedLocal , SavedLocalEligibility > =
652
- iter:: repeat ( Unassigned )
653
- . take ( info. field_tys . len ( ) )
654
- . collect ( ) ;
652
+ IndexVec :: from_elem_n ( Unassigned , info. field_tys . len ( ) ) ;
655
653
656
654
// The saved locals not eligible for overlap. These will get
657
655
// "promoted" to the prefix of our generator.
658
- let mut eligible_locals = BitSet :: new_filled ( info. field_tys . len ( ) ) ;
656
+ let mut ineligible_locals = BitSet :: new_empty ( info. field_tys . len ( ) ) ;
659
657
660
658
// Figure out which of our saved locals are fields in only
661
659
// one variant. The rest are deemed ineligible for overlap.
@@ -670,7 +668,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
670
668
// point, so it is no longer a candidate.
671
669
trace ! ( "removing local {:?} in >1 variant ({:?}, {:?})" ,
672
670
local, variant_index, idx) ;
673
- eligible_locals . remove ( * local) ;
671
+ ineligible_locals . insert ( * local) ;
674
672
assignments[ * local] = Ineligible ( None ) ;
675
673
}
676
674
Ineligible ( _) => { } ,
@@ -681,46 +679,50 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
681
679
// Next, check every pair of eligible locals to see if they
682
680
// conflict.
683
681
for ( local_a, conflicts_a) in info. storage_conflicts . iter_enumerated ( ) {
684
- if !eligible_locals . contains ( local_a) {
682
+ if ineligible_locals . contains ( local_a) {
685
683
continue ;
686
684
}
687
685
688
686
for local_b in conflicts_a. iter ( ) {
689
- // local_a and local_b have overlapping storage, therefore they
687
+ // local_a and local_b are storage live at the same time , therefore they
690
688
// cannot overlap in the generator layout. The only way to guarantee
691
689
// this is if they are in the same variant, or one is ineligible
692
690
// (which means it is stored in every variant).
693
- if !eligible_locals . contains ( local_b) ||
691
+ if ineligible_locals . contains ( local_b) ||
694
692
assignments[ local_a] == assignments[ local_b]
695
693
{
696
694
continue ;
697
695
}
698
696
699
697
// If they conflict, we will choose one to make ineligible.
698
+ // This is not always optimal; it's just a greedy heuristic
699
+ // that seems to produce good results most of the time.
700
700
let conflicts_b = & info. storage_conflicts [ local_b] ;
701
701
let ( remove, other) = if conflicts_a. count ( ) > conflicts_b. count ( ) {
702
702
( local_a, local_b)
703
703
} else {
704
704
( local_b, local_a)
705
705
} ;
706
- eligible_locals . remove ( remove) ;
706
+ ineligible_locals . insert ( remove) ;
707
707
assignments[ remove] = Ineligible ( None ) ;
708
708
trace ! ( "removing local {:?} due to conflict with {:?}" , remove, other) ;
709
709
}
710
710
}
711
711
712
- let mut ineligible_locals = BitSet :: new_filled ( info. field_tys . len ( ) ) ;
713
- ineligible_locals. subtract ( & eligible_locals) ;
714
-
715
712
// Write down the order of our locals that will be promoted to
716
713
// the prefix.
717
- for ( idx, local) in ineligible_locals. iter ( ) . enumerate ( ) {
718
- assignments[ local] = Ineligible ( Some ( idx as u32 ) ) ;
714
+ {
715
+ let mut idx = 0u32 ;
716
+ for local in ineligible_locals. iter ( ) {
717
+ assignments[ local] = Ineligible ( Some ( idx) ) ;
718
+ idx += 1 ;
719
+ }
719
720
}
720
721
debug ! ( "generator saved local assignments: {:?}" , assignments) ;
721
722
722
723
// Build a prefix layout, including "promoting" all ineligible
723
- // locals as part of the prefix.
724
+ // locals as part of the prefix. We compute the layout of all of
725
+ // these fields at once to get optimal packing.
724
726
let discr_index = substs. prefix_tys ( def_id, tcx) . count ( ) ;
725
727
let promoted_tys =
726
728
ineligible_locals. iter ( ) . map ( |local| subst_field ( info. field_tys [ local] ) ) ;
@@ -733,20 +735,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
733
735
StructKind :: AlwaysSized ) ?;
734
736
let ( prefix_size, prefix_align) = ( prefix. size , prefix. align ) ;
735
737
736
- // Split the prefix layout into the "outer" fields (upvars and
737
- // discriminant) and the "promoted" fields. Promoted fields will
738
- // get included in each variant that requested them in
739
- // GeneratorLayout.
740
- let renumber_indices = |mut index : Vec < u32 > | -> Vec < u32 > {
741
- debug ! ( "renumber_indices({:?})" , index) ;
742
- let mut inverse_index = ( 0 ..index. len ( ) as u32 ) . collect :: < Vec < _ > > ( ) ;
743
- inverse_index. sort_unstable_by_key ( |i| index[ * i as usize ] ) ;
738
+ let recompute_memory_index = |offsets : & Vec < u32 > | -> Vec < u32 > {
739
+ debug ! ( "recompute_memory_index({:?})" , offsets) ;
740
+ let mut inverse_index = ( 0 ..offsets. len ( ) as u32 ) . collect :: < Vec < _ > > ( ) ;
741
+ inverse_index. sort_unstable_by_key ( |i| offsets[ * i as usize ] ) ;
742
+
743
+ let mut index = vec ! [ 0 ; offsets. len( ) ] ;
744
744
for i in 0 ..index. len ( ) {
745
745
index[ inverse_index[ i] as usize ] = i as u32 ;
746
746
}
747
- debug ! ( "renumber_indices () => {:?}" , index) ;
747
+ debug ! ( "recompute_memory_index () => {:?}" , index) ;
748
748
index
749
749
} ;
750
+
751
+ // Split the prefix layout into the "outer" fields (upvars and
752
+ // discriminant) and the "promoted" fields. Promoted fields will
753
+ // get included in each variant that requested them in
754
+ // GeneratorLayout.
750
755
debug ! ( "prefix = {:#?}" , prefix) ;
751
756
let ( outer_fields, promoted_offsets, promoted_memory_index) = match prefix. fields {
752
757
FieldPlacement :: Arbitrary { offsets, memory_index } => {
@@ -756,11 +761,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
756
761
memory_index. split_at ( discr_index + 1 ) ;
757
762
let outer_fields = FieldPlacement :: Arbitrary {
758
763
offsets : offsets_a. to_vec ( ) ,
759
- memory_index : renumber_indices ( memory_index_a. to_vec ( ) )
764
+ memory_index : recompute_memory_index ( & memory_index_a. to_vec ( ) )
760
765
} ;
761
766
( outer_fields,
762
767
offsets_b. to_vec ( ) ,
763
- renumber_indices ( memory_index_b. to_vec ( ) ) )
768
+ recompute_memory_index ( & memory_index_b. to_vec ( ) ) )
764
769
}
765
770
_ => bug ! ( ) ,
766
771
} ;
@@ -769,15 +774,17 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
769
774
let mut align = prefix. align ;
770
775
let variants = info. variant_fields . iter_enumerated ( ) . map ( |( index, variant_fields) | {
771
776
// Only include overlap-eligible fields when we compute our variant layout.
772
- let variant_only_tys = variant_fields. iter ( ) . flat_map ( |local| {
773
- let ty = info. field_tys [ * local] ;
774
- match assignments[ * local] {
775
- Unassigned => bug ! ( ) ,
776
- Assigned ( v) if v == index => Some ( subst_field ( ty) ) ,
777
- Assigned ( _) => bug ! ( "assignment does not match variant" ) ,
778
- Ineligible ( _) => None ,
779
- }
780
- } ) ;
777
+ let variant_only_tys = variant_fields
778
+ . iter ( )
779
+ . filter ( |local| {
780
+ match assignments[ * * local] {
781
+ Unassigned => bug ! ( ) ,
782
+ Assigned ( v) if v == index => true ,
783
+ Assigned ( _) => bug ! ( "assignment does not match variant" ) ,
784
+ Ineligible ( _) => false ,
785
+ }
786
+ } )
787
+ . map ( |local| subst_field ( info. field_tys [ * local] ) ) ;
781
788
782
789
let mut variant = univariant_uninterned (
783
790
& variant_only_tys
@@ -823,7 +830,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
823
830
}
824
831
variant. fields = FieldPlacement :: Arbitrary {
825
832
offsets : combined_offsets,
826
- memory_index : renumber_indices ( combined_memory_index) ,
833
+ memory_index : recompute_memory_index ( & combined_memory_index) ,
827
834
} ;
828
835
829
836
size = size. max ( variant. size ) ;
0 commit comments