@@ -401,9 +401,9 @@ fn locals_live_across_suspend_points(
401
401
movable : bool ,
402
402
) -> (
403
403
liveness:: LiveVarSet ,
404
+ Vec < BitSet < GeneratorSavedLocal > > ,
404
405
IndexVec < GeneratorSavedLocal , BitSet < GeneratorSavedLocal > > ,
405
406
FxHashMap < BasicBlock , liveness:: LiveVarSet > ,
406
- BitSet < BasicBlock > ,
407
407
) {
408
408
let dead_unwinds = BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) ) ;
409
409
let def_id = source. def_id ( ) ;
@@ -447,13 +447,10 @@ fn locals_live_across_suspend_points(
447
447
) ;
448
448
449
449
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 ( ) ;
452
451
453
452
for ( block, data) in body. basic_blocks ( ) . iter_enumerated ( ) {
454
453
if let TerminatorKind :: Yield { .. } = data. terminator ( ) . kind {
455
- suspending_blocks. insert ( block) ;
456
-
457
454
let loc = Location {
458
455
block : block,
459
456
statement_index : data. statements . len ( ) ,
@@ -494,16 +491,25 @@ fn locals_live_across_suspend_points(
494
491
// and their storage is live (the `storage_liveness` variable)
495
492
storage_liveness. intersect ( & liveness. outs [ block] ) ;
496
493
494
+ // The generator argument is ignored
495
+ storage_liveness. remove ( self_arg ( ) ) ;
496
+
497
497
let live_locals = storage_liveness;
498
498
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
500
500
// any suspension points
501
501
set. union ( & live_locals) ;
502
+
503
+ live_locals_at_suspension_points. push ( live_locals) ;
502
504
}
503
505
}
504
506
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 ( ) ;
507
513
508
514
let storage_conflicts = compute_storage_conflicts (
509
515
body,
@@ -512,7 +518,7 @@ fn locals_live_across_suspend_points(
512
518
storage_live,
513
519
storage_live_analysis) ;
514
520
515
- ( set, storage_conflicts , storage_liveness_map , suspending_blocks )
521
+ ( set, live_locals_at_suspension_points , storage_conflicts , storage_liveness_map )
516
522
}
517
523
518
524
/// 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>,
611
617
FxHashMap < BasicBlock , liveness:: LiveVarSet > )
612
618
{
613
619
// 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 ) =
615
621
locals_live_across_suspend_points ( tcx, body, source, movable) ;
616
622
617
623
// 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>,
641
647
642
648
let dummy_local = LocalDecl :: new_internal ( tcx. mk_unit ( ) , body. span ) ;
643
649
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 ( ) {
647
656
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
+ }
650
662
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 ;
656
665
666
+ // Build the generator variant field list.
657
667
// 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 ( ) ;
659
670
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) ;
664
683
}
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) ;
672
686
673
687
let layout = GeneratorLayout {
674
- field_tys,
675
- variant_fields : empty_variants . chain ( state_variants ) . collect ( ) ,
688
+ field_tys : tys ,
689
+ variant_fields,
676
690
storage_conflicts,
677
691
__local_debuginfo_codegen_only_do_not_use : decls,
678
692
} ;
0 commit comments