@@ -401,9 +401,9 @@ fn locals_live_across_suspend_points(
401401 movable : bool ,
402402) -> (
403403 liveness:: LiveVarSet ,
404+ Vec < BitSet < GeneratorSavedLocal > > ,
404405 IndexVec < GeneratorSavedLocal , BitSet < GeneratorSavedLocal > > ,
405406 FxHashMap < BasicBlock , liveness:: LiveVarSet > ,
406- BitSet < BasicBlock > ,
407407) {
408408 let dead_unwinds = BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) ) ;
409409 let def_id = source. def_id ( ) ;
@@ -447,13 +447,10 @@ fn locals_live_across_suspend_points(
447447 ) ;
448448
449449 let mut storage_liveness_map = FxHashMap :: default ( ) ;
450-
451- let mut suspending_blocks = BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) ) ;
450+ let mut live_locals_at_suspension_points = Vec :: new ( ) ;
452451
453452 for ( block, data) in body. basic_blocks ( ) . iter_enumerated ( ) {
454453 if let TerminatorKind :: Yield { .. } = data. terminator ( ) . kind {
455- suspending_blocks. insert ( block) ;
456-
457454 let loc = Location {
458455 block : block,
459456 statement_index : data. statements . len ( ) ,
@@ -494,16 +491,25 @@ fn locals_live_across_suspend_points(
494491 // and their storage is live (the `storage_liveness` variable)
495492 storage_liveness. intersect ( & liveness. outs [ block] ) ;
496493
494+ // The generator argument is ignored
495+ storage_liveness. remove ( self_arg ( ) ) ;
496+
497497 let live_locals = storage_liveness;
498498
499- // Add the locals life at this suspension point to the set of locals which live across
499+ // Add the locals live at this suspension point to the set of locals which live across
500500 // any suspension points
501501 set. union ( & live_locals) ;
502+
503+ live_locals_at_suspension_points. push ( live_locals) ;
502504 }
503505 }
504506
505- // The generator argument is ignored
506- set. remove ( self_arg ( ) ) ;
507+ // Renumber our liveness_map bitsets to include only the locals we are
508+ // saving.
509+ let live_locals_at_suspension_points = live_locals_at_suspension_points
510+ . iter ( )
511+ . map ( |live_locals| renumber_bitset ( & live_locals, & set) )
512+ . collect ( ) ;
507513
508514 let storage_conflicts = compute_storage_conflicts (
509515 body,
@@ -512,7 +518,7 @@ fn locals_live_across_suspend_points(
512518 storage_live,
513519 storage_live_analysis) ;
514520
515- ( set, storage_conflicts , storage_liveness_map , suspending_blocks )
521+ ( set, live_locals_at_suspension_points , storage_conflicts , storage_liveness_map )
516522}
517523
518524/// For every saved local, looks for which locals are StorageLive at the same
@@ -611,7 +617,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
611617 FxHashMap < BasicBlock , liveness:: LiveVarSet > )
612618{
613619 // Use a liveness analysis to compute locals which are live across a suspension point
614- let ( live_locals, storage_conflicts , storage_liveness , suspending_blocks ) =
620+ let ( live_locals, live_locals_at_suspension_points , storage_conflicts , storage_liveness ) =
615621 locals_live_across_suspend_points ( tcx, body, source, movable) ;
616622
617623 // Erase regions from the types passed in from typeck so we can compare them with
@@ -641,38 +647,46 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
641647
642648 let dummy_local = LocalDecl :: new_internal ( tcx. mk_unit ( ) , body. span ) ;
643649
644- // Gather live locals and their indices replacing values in body.local_decls with a dummy
645- // to avoid changing local indices
646- let live_decls = live_locals. iter ( ) . map ( |local| {
650+ // Gather live locals and their indices replacing values in body.local_decls
651+ // with a dummy to avoid changing local indices.
652+ let mut locals = IndexVec :: < GeneratorSavedLocal , _ > :: new ( ) ;
653+ let mut tys = IndexVec :: < GeneratorSavedLocal , _ > :: new ( ) ;
654+ let mut decls = IndexVec :: < GeneratorSavedLocal , _ > :: new ( ) ;
655+ for ( idx, local) in live_locals. iter ( ) . enumerate ( ) {
647656 let var = mem:: replace ( & mut body. local_decls [ local] , dummy_local. clone ( ) ) ;
648- ( local, var)
649- } ) ;
657+ locals. push ( local) ;
658+ tys. push ( var. ty ) ;
659+ decls. push ( var) ;
660+ debug ! ( "generator saved local {:?} => {:?}" , GeneratorSavedLocal :: from( idx) , local) ;
661+ }
650662
651- // For now we will access everything via variant #3, leaving empty variants
652- // for the UNRESUMED, RETURNED, and POISONED states.
653- // If there were a yield-less generator without a variant #3, it would not
654- // have any vars to remap, so we would never use this.
655- let variant_index = VariantIdx :: new ( 3 ) ;
663+ // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
664+ const RESERVED_VARIANTS : usize = 3 ;
656665
666+ // Build the generator variant field list.
657667 // Create a map from local indices to generator struct indices.
658- // We also create a vector of the LocalDecls of these locals.
668+ let mut variant_fields: IndexVec < VariantIdx , IndexVec < Field , GeneratorSavedLocal > > =
669+ iter:: repeat ( IndexVec :: new ( ) ) . take ( RESERVED_VARIANTS ) . collect ( ) ;
659670 let mut remap = FxHashMap :: default ( ) ;
660- let mut decls = IndexVec :: new ( ) ;
661- for ( idx, ( local, var) ) in live_decls. enumerate ( ) {
662- remap. insert ( local, ( var. ty , variant_index, idx) ) ;
663- decls. push ( var) ;
671+ for ( suspension_point_idx, live_locals) in live_locals_at_suspension_points. iter ( ) . enumerate ( ) {
672+ let variant_index = VariantIdx :: from ( RESERVED_VARIANTS + suspension_point_idx) ;
673+ let mut fields = IndexVec :: new ( ) ;
674+ for ( idx, saved_local) in live_locals. iter ( ) . enumerate ( ) {
675+ fields. push ( saved_local) ;
676+ // Note that if a field is included in multiple variants, it will be
677+ // added overwritten here. That's fine; fields do not move around
678+ // inside generators, so it doesn't matter which variant index we
679+ // access them by.
680+ remap. insert ( locals[ saved_local] , ( tys[ saved_local] , variant_index, idx) ) ;
681+ }
682+ variant_fields. push ( fields) ;
664683 }
665- debug ! ( "generator saved local mappings: {:?}" , decls) ;
666- let field_tys = decls. iter ( ) . map ( |field| field. ty ) . collect :: < IndexVec < _ , _ > > ( ) ;
667-
668- // Put every var in each variant, for now.
669- let all_vars = ( 0 ..field_tys. len ( ) ) . map ( GeneratorSavedLocal :: from) . collect ( ) ;
670- let empty_variants = iter:: repeat ( IndexVec :: new ( ) ) . take ( 3 ) ;
671- let state_variants = iter:: repeat ( all_vars) . take ( suspending_blocks. count ( ) ) ;
684+ debug ! ( "generator variant_fields = {:?}" , variant_fields) ;
685+ debug ! ( "generator storage_conflicts = {:?}" , storage_conflicts) ;
672686
673687 let layout = GeneratorLayout {
674- field_tys,
675- variant_fields : empty_variants . chain ( state_variants ) . collect ( ) ,
688+ field_tys : tys ,
689+ variant_fields,
676690 storage_conflicts,
677691 __local_debuginfo_codegen_only_do_not_use : decls,
678692 } ;
0 commit comments