@@ -66,8 +66,8 @@ use std::mem;
6666use crate :: transform:: { MirPass , MirSource } ;
6767use crate :: transform:: simplify;
6868use crate :: transform:: no_landing_pads:: no_landing_pads;
69- use crate :: dataflow:: { DataflowResults } ;
70- use crate :: dataflow:: { do_dataflow, DebugFormatted , state_for_location, for_each_location } ;
69+ use crate :: dataflow:: { DataflowResults , DataflowResultsConsumer , FlowAtLocation } ;
70+ use crate :: dataflow:: { do_dataflow, DebugFormatted , state_for_location} ;
7171use crate :: dataflow:: { MaybeStorageLive , HaveBeenBorrowedLocals } ;
7272use crate :: util:: dump_mir;
7373use crate :: util:: liveness;
@@ -541,6 +541,25 @@ fn locals_live_across_suspend_points(
541541 }
542542}
543543
544+ /// Renumbers the items present in `stored_locals` and applies the renumbering
545+ /// to 'input`.
546+ ///
547+ /// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
548+ /// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
549+ fn renumber_bitset ( input : & BitSet < Local > , stored_locals : & liveness:: LiveVarSet )
550+ -> BitSet < GeneratorSavedLocal > {
551+ assert ! ( stored_locals. superset( & input) , "{:?} not a superset of {:?}" , stored_locals, input) ;
552+ let mut out = BitSet :: new_empty ( stored_locals. count ( ) ) ;
553+ for ( idx, local) in stored_locals. iter ( ) . enumerate ( ) {
554+ let saved_local = GeneratorSavedLocal :: from ( idx) ;
555+ if input. contains ( local) {
556+ out. insert ( saved_local) ;
557+ }
558+ }
559+ debug ! ( "renumber_bitset({:?}, {:?}) => {:?}" , input, stored_locals, out) ;
560+ out
561+ }
562+
544563/// For every saved local, looks for which locals are StorageLive at the same
545564/// time. Generates a bitset for every local of all the other locals that may be
546565/// StorageLive simultaneously with that local. This is used in the layout
@@ -550,7 +569,7 @@ fn compute_storage_conflicts(
550569 stored_locals : & liveness:: LiveVarSet ,
551570 ignored : & StorageIgnored ,
552571 storage_live : DataflowResults < ' tcx , MaybeStorageLive < ' mir , ' tcx > > ,
553- storage_live_analysis : MaybeStorageLive < ' mir , ' tcx > ,
572+ _storage_live_analysis : MaybeStorageLive < ' mir , ' tcx > ,
554573) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
555574 assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
556575 assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
@@ -562,26 +581,18 @@ fn compute_storage_conflicts(
562581 let mut ineligible_locals = ignored. 0 . clone ( ) ;
563582 ineligible_locals. intersect ( & stored_locals) ;
564583
565- // Of our remaining candidates, find out if any have overlapping storage
566- // liveness. Those that do must be in the same variant to remain candidates.
567- // FIXME(tmandry): Consider using sparse bitsets here once we have good
568- // benchmarks for generators.
569- let mut local_conflicts: BitMatrix < Local , Local > =
570- BitMatrix :: from_row_n ( & ineligible_locals, body. local_decls . len ( ) ) ;
571-
572- for_each_location ( body, & storage_live_analysis, & storage_live, |state, loc| {
573- let mut eligible_storage_live = state. clone ( ) . to_dense ( ) ;
574- eligible_storage_live. intersect ( & stored_locals) ;
575-
576- for local in eligible_storage_live. iter ( ) {
577- local_conflicts. union_row_with ( & eligible_storage_live, local) ;
578- }
579-
580- if eligible_storage_live. count ( ) > 1 {
581- trace ! ( "at {:?}, eligible_storage_live={:?}" , loc, eligible_storage_live) ;
582- }
583- } ) ;
584+ // Compute the storage conflicts for all eligible locals.
585+ let mut visitor = StorageConflictVisitor {
586+ body,
587+ stored_locals : & stored_locals,
588+ local_conflicts : BitMatrix :: from_row_n ( & ineligible_locals, body. local_decls . len ( ) )
589+ } ;
590+ let mut state = FlowAtLocation :: new ( storage_live) ;
591+ visitor. analyze_results ( & mut state) ;
592+ let local_conflicts = visitor. local_conflicts ;
584593
594+ // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
595+ //
585596 // NOTE: Today we store a full conflict bitset for every local. Technically
586597 // this is twice as many bits as we need, since the relation is symmetric.
587598 // However, in practice these bitsets are not usually large. The layout code
@@ -606,23 +617,64 @@ fn compute_storage_conflicts(
606617 storage_conflicts
607618}
608619
609- /// Renumbers the items present in `stored_locals` and applies the renumbering
610- /// to 'input`.
611- ///
612- /// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
613- /// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
614- fn renumber_bitset ( input : & BitSet < Local > , stored_locals : & liveness:: LiveVarSet )
615- -> BitSet < GeneratorSavedLocal > {
616- assert ! ( stored_locals. superset( & input) , "{:?} not a superset of {:?}" , stored_locals, input) ;
617- let mut out = BitSet :: new_empty ( stored_locals. count ( ) ) ;
618- for ( idx, local) in stored_locals. iter ( ) . enumerate ( ) {
619- let saved_local = GeneratorSavedLocal :: from ( idx) ;
620- if input. contains ( local) {
621- out. insert ( saved_local) ;
620+ struct StorageConflictVisitor < ' body , ' tcx : ' body , ' s > {
621+ body : & ' body Body < ' tcx > ,
622+ stored_locals : & ' s liveness:: LiveVarSet ,
623+ // FIXME(tmandry): Consider using sparse bitsets here once we have good
624+ // benchmarks for generators.
625+ local_conflicts : BitMatrix < Local , Local > ,
626+ }
627+
628+ impl < ' body , ' tcx : ' body , ' s > DataflowResultsConsumer < ' body , ' tcx >
629+ for StorageConflictVisitor < ' body , ' tcx , ' s > {
630+ type FlowState = FlowAtLocation < ' tcx , MaybeStorageLive < ' body , ' tcx > > ;
631+
632+ fn body ( & self ) -> & ' body Body < ' tcx > {
633+ self . body
634+ }
635+
636+ fn visit_block_entry ( & mut self ,
637+ block : BasicBlock ,
638+ flow_state : & Self :: FlowState ) {
639+ // statement_index is only used for logging, so this is fine.
640+ self . apply_state ( flow_state, Location { block, statement_index : 0 } ) ;
641+ }
642+
643+ fn visit_statement_entry ( & mut self ,
644+ loc : Location ,
645+ _stmt : & Statement < ' tcx > ,
646+ flow_state : & Self :: FlowState ) {
647+ self . apply_state ( flow_state, loc) ;
648+ }
649+
650+ fn visit_terminator_entry ( & mut self ,
651+ loc : Location ,
652+ _term : & Terminator < ' tcx > ,
653+ flow_state : & Self :: FlowState ) {
654+ self . apply_state ( flow_state, loc) ;
655+ }
656+ }
657+
658+ impl < ' body , ' tcx : ' body , ' s > StorageConflictVisitor < ' body , ' tcx , ' s > {
659+ fn apply_state ( & mut self ,
660+ flow_state : & FlowAtLocation < ' tcx , MaybeStorageLive < ' body , ' tcx > > ,
661+ loc : Location ) {
662+ // Ignore unreachable blocks.
663+ if self . body . basic_blocks ( ) [ loc. block ] . is_unreachable ( ) {
664+ return ;
665+ }
666+
667+ let mut eligible_storage_live = flow_state. as_dense ( ) . clone ( ) ;
668+ eligible_storage_live. intersect ( & self . stored_locals ) ;
669+
670+ for local in eligible_storage_live. iter ( ) {
671+ self . local_conflicts . union_row_with ( & eligible_storage_live, local) ;
672+ }
673+
674+ if eligible_storage_live. count ( ) > 1 {
675+ trace ! ( "at {:?}, eligible_storage_live={:?}" , loc, eligible_storage_live) ;
622676 }
623677 }
624- debug ! ( "renumber_bitset({:?}, {:?}) => {:?}" , input, stored_locals, out) ;
625- out
626678}
627679
628680fn compute_layout < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
0 commit comments