@@ -66,8 +66,8 @@ use std::mem;
66
66
use crate :: transform:: { MirPass , MirSource } ;
67
67
use crate :: transform:: simplify;
68
68
use 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} ;
71
71
use crate :: dataflow:: { MaybeStorageLive , HaveBeenBorrowedLocals } ;
72
72
use crate :: util:: dump_mir;
73
73
use crate :: util:: liveness;
@@ -541,6 +541,25 @@ fn locals_live_across_suspend_points(
541
541
}
542
542
}
543
543
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
+
544
563
/// For every saved local, looks for which locals are StorageLive at the same
545
564
/// time. Generates a bitset for every local of all the other locals that may be
546
565
/// StorageLive simultaneously with that local. This is used in the layout
@@ -550,7 +569,7 @@ fn compute_storage_conflicts(
550
569
stored_locals : & liveness:: LiveVarSet ,
551
570
ignored : & StorageIgnored ,
552
571
storage_live : DataflowResults < ' tcx , MaybeStorageLive < ' mir , ' tcx > > ,
553
- storage_live_analysis : MaybeStorageLive < ' mir , ' tcx > ,
572
+ _storage_live_analysis : MaybeStorageLive < ' mir , ' tcx > ,
554
573
) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
555
574
assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
556
575
assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
@@ -562,26 +581,18 @@ fn compute_storage_conflicts(
562
581
let mut ineligible_locals = ignored. 0 . clone ( ) ;
563
582
ineligible_locals. intersect ( & stored_locals) ;
564
583
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 ;
584
593
594
+ // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
595
+ //
585
596
// NOTE: Today we store a full conflict bitset for every local. Technically
586
597
// this is twice as many bits as we need, since the relation is symmetric.
587
598
// However, in practice these bitsets are not usually large. The layout code
@@ -606,23 +617,64 @@ fn compute_storage_conflicts(
606
617
storage_conflicts
607
618
}
608
619
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) ;
622
676
}
623
677
}
624
- debug ! ( "renumber_bitset({:?}, {:?}) => {:?}" , input, stored_locals, out) ;
625
- out
626
678
}
627
679
628
680
fn compute_layout < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
0 commit comments