@@ -649,13 +649,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
649649 use SavedLocalEligibility :: * ;
650650
651651 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 ( ) ) ;
655653
656654 // The saved locals not eligible for overlap. These will get
657655 // "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 ( ) ) ;
659657
660658 // Figure out which of our saved locals are fields in only
661659 // one variant. The rest are deemed ineligible for overlap.
@@ -670,7 +668,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
670668 // point, so it is no longer a candidate.
671669 trace ! ( "removing local {:?} in >1 variant ({:?}, {:?})" ,
672670 local, variant_index, idx) ;
673- eligible_locals . remove ( * local) ;
671+ ineligible_locals . insert ( * local) ;
674672 assignments[ * local] = Ineligible ( None ) ;
675673 }
676674 Ineligible ( _) => { } ,
@@ -681,46 +679,50 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
681679 // Next, check every pair of eligible locals to see if they
682680 // conflict.
683681 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) {
685683 continue ;
686684 }
687685
688686 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
690688 // cannot overlap in the generator layout. The only way to guarantee
691689 // this is if they are in the same variant, or one is ineligible
692690 // (which means it is stored in every variant).
693- if !eligible_locals . contains ( local_b) ||
691+ if ineligible_locals . contains ( local_b) ||
694692 assignments[ local_a] == assignments[ local_b]
695693 {
696694 continue ;
697695 }
698696
699697 // 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.
700700 let conflicts_b = & info. storage_conflicts [ local_b] ;
701701 let ( remove, other) = if conflicts_a. count ( ) > conflicts_b. count ( ) {
702702 ( local_a, local_b)
703703 } else {
704704 ( local_b, local_a)
705705 } ;
706- eligible_locals . remove ( remove) ;
706+ ineligible_locals . insert ( remove) ;
707707 assignments[ remove] = Ineligible ( None ) ;
708708 trace ! ( "removing local {:?} due to conflict with {:?}" , remove, other) ;
709709 }
710710 }
711711
712- let mut ineligible_locals = BitSet :: new_filled ( info. field_tys . len ( ) ) ;
713- ineligible_locals. subtract ( & eligible_locals) ;
714-
715712 // Write down the order of our locals that will be promoted to
716713 // 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+ }
719720 }
720721 debug ! ( "generator saved local assignments: {:?}" , assignments) ;
721722
722723 // 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.
724726 let discr_index = substs. prefix_tys ( def_id, tcx) . count ( ) ;
725727 let promoted_tys =
726728 ineligible_locals. iter ( ) . map ( |local| subst_field ( info. field_tys [ local] ) ) ;
@@ -733,20 +735,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
733735 StructKind :: AlwaysSized ) ?;
734736 let ( prefix_size, prefix_align) = ( prefix. size , prefix. align ) ;
735737
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( ) ] ;
744744 for i in 0 ..index. len ( ) {
745745 index[ inverse_index[ i] as usize ] = i as u32 ;
746746 }
747- debug ! ( "renumber_indices () => {:?}" , index) ;
747+ debug ! ( "recompute_memory_index () => {:?}" , index) ;
748748 index
749749 } ;
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.
750755 debug ! ( "prefix = {:#?}" , prefix) ;
751756 let ( outer_fields, promoted_offsets, promoted_memory_index) = match prefix. fields {
752757 FieldPlacement :: Arbitrary { offsets, memory_index } => {
@@ -756,11 +761,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
756761 memory_index. split_at ( discr_index + 1 ) ;
757762 let outer_fields = FieldPlacement :: Arbitrary {
758763 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 ( ) )
760765 } ;
761766 ( outer_fields,
762767 offsets_b. to_vec ( ) ,
763- renumber_indices ( memory_index_b. to_vec ( ) ) )
768+ recompute_memory_index ( & memory_index_b. to_vec ( ) ) )
764769 }
765770 _ => bug ! ( ) ,
766771 } ;
@@ -769,15 +774,17 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
769774 let mut align = prefix. align ;
770775 let variants = info. variant_fields . iter_enumerated ( ) . map ( |( index, variant_fields) | {
771776 // 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] ) ) ;
781788
782789 let mut variant = univariant_uninterned (
783790 & variant_only_tys
@@ -823,7 +830,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
823830 }
824831 variant. fields = FieldPlacement :: Arbitrary {
825832 offsets : combined_offsets,
826- memory_index : renumber_indices ( combined_memory_index) ,
833+ memory_index : recompute_memory_index ( & combined_memory_index) ,
827834 } ;
828835
829836 size = size. max ( variant. size ) ;
0 commit comments