@@ -146,7 +146,7 @@ use rustc_middle::mir::*;
146146use rustc_middle:: ty:: TyCtxt ;
147147use rustc_mir_dataflow:: impls:: { DefUse , MaybeLiveLocals } ;
148148use rustc_mir_dataflow:: points:: DenseLocationMap ;
149- use rustc_mir_dataflow:: { Analysis , EntryStates } ;
149+ use rustc_mir_dataflow:: { Analysis , EntryStates , GenKill } ;
150150use tracing:: { debug, trace} ;
151151
152152pub ( super ) struct DestinationPropagation ;
@@ -502,25 +502,64 @@ impl TwoStepIndex {
502502}
503503
504504/// Add points depending on the result of the given dataflow analysis.
505+ #[ tracing:: instrument( level = "trace" , skip( elements, body) ) ]
505506fn save_as_intervals < ' tcx > (
506507 elements : & DenseLocationMap ,
507508 body : & Body < ' tcx > ,
508509 relevant : & RelevantLocals ,
509510 entry_states : EntryStates < DenseBitSet < Local > > ,
510511) -> SparseIntervalMatrix < RelevantLocal , TwoStepIndex > {
511- let mut values = SparseIntervalMatrix :: new ( 2 * elements. num_points ( ) ) ;
512- let mut state = MaybeLiveLocals . bottom_value ( body) ;
513- let reachable_blocks = traversal:: reachable_as_bitset ( body) ;
512+ struct GenKillIntervalMatrix < ' a > {
513+ values : SparseIntervalMatrix < RelevantLocal , TwoStepIndex > ,
514+ relevant : & ' a RelevantLocals ,
515+ pending : IndexVec < RelevantLocal , Option < TwoStepIndex > > ,
516+ current : TwoStepIndex ,
517+ }
514518
515- let two_step_loc = |location, effect| TwoStepIndex :: new ( elements, location, effect) ;
516- let append_at =
517- |values : & mut SparseIntervalMatrix < _ , _ > , state : & DenseBitSet < Local > , twostep| {
518- for ( relevant, & original) in relevant. original . iter_enumerated ( ) {
519- if state. contains ( original) {
520- values. append ( relevant, twostep) ;
519+ impl GenKill < Local > for GenKillIntervalMatrix < ' _ > {
520+ fn gen_ ( & mut self , elem : Local ) {
521+ let Some ( elem) = self . relevant . shrink [ elem] else { return } ;
522+ let _ = self . pending [ elem] . get_or_insert ( self . current ) ;
523+ }
524+
525+ fn kill ( & mut self , elem : Local ) {
526+ let Some ( elem) = self . relevant . shrink [ elem] else { return } ;
527+ if let Some ( start) = self . pending [ elem] . take ( ) {
528+ debug_assert ! ( start <= self . current) ;
529+ self . values . append_range ( elem, start..self . current ) ;
530+ }
531+ }
532+ }
533+
534+ impl GenKillIntervalMatrix < ' _ > {
535+ fn insert_single ( & mut self , elem : RelevantLocal ) {
536+ // If we have a set pending, we will insert it when killing it, so nothing to do.
537+ if self . pending [ elem] . is_none ( ) {
538+ self . values . append_range ( elem, self . current ..=self . current ) ;
539+ }
540+ }
541+
542+ fn finish_block ( & mut self ) {
543+ for ( elem, start) in self . pending . iter_enumerated_mut ( ) {
544+ if let Some ( start) = start. take ( ) {
545+ debug_assert ! ( start <= self . current) ;
546+ self . values . append_range ( elem, start..=self . current ) ;
521547 }
522548 }
523- } ;
549+ }
550+ }
551+
552+ let mut state = GenKillIntervalMatrix {
553+ values : SparseIntervalMatrix :: new ( 2 * elements. num_points ( ) ) ,
554+ relevant,
555+ pending : IndexVec :: from_elem ( None , & relevant. original ) ,
556+ // Dummy value.
557+ current : TwoStepIndex :: from_u32 ( 0 ) ,
558+ } ;
559+
560+ let reachable_blocks = traversal:: reachable_as_bitset ( body) ;
561+
562+ let two_step_loc = |location, effect| TwoStepIndex :: new ( elements, location, effect) ;
524563
525564 // Iterate blocks in decreasing order, to visit locations in decreasing order. This
526565 // allows to use the more efficient `append` method to interval sets.
@@ -529,14 +568,17 @@ fn save_as_intervals<'tcx>(
529568 continue ;
530569 }
531570
532- state. clone_from ( & entry_states[ block] ) ;
533-
534571 let block_data = & body. basic_blocks [ block] ;
535572 let loc = Location { block, statement_index : block_data. statements . len ( ) } ;
573+ debug_assert ! ( state. pending. iter( ) . all( Option :: is_none) ) ;
574+ state. current = two_step_loc ( loc, Effect :: After ) ;
575+
576+ for local in entry_states[ block] . iter ( ) {
577+ state. gen_ ( local)
578+ }
536579
537580 let term = block_data. terminator ( ) ;
538- let mut twostep = two_step_loc ( loc, Effect :: After ) ;
539- append_at ( & mut values, & state, twostep) ;
581+
540582 // Ensure we have a non-zero live range even for dead stores. This is done by marking all
541583 // the written-to locals as live in the second half of the statement.
542584 // We also ensure that operands read by terminators conflict with writes by that terminator.
@@ -545,25 +587,23 @@ fn save_as_intervals<'tcx>(
545587 if let Some ( relevant) = relevant. shrink [ place. local ] {
546588 match DefUse :: for_place ( place, ctxt) {
547589 DefUse :: Def | DefUse :: Use | DefUse :: PartialWrite => {
548- values . insert ( relevant, twostep ) ;
590+ state . insert_single ( relevant) ;
549591 }
550592 DefUse :: NonUse => { }
551593 }
552594 }
553595 } )
554596 . visit_terminator ( term, loc) ;
555597
556- twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
557- debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
558- MaybeLiveLocals . apply_early_terminator_effect ( & mut state, term, loc) ;
559- MaybeLiveLocals . apply_primary_terminator_effect ( & mut state, term, loc) ;
560- append_at ( & mut values, & state, twostep) ;
598+ state. current = state. current + 1 ;
599+ debug_assert_eq ! ( state. current, two_step_loc( loc, Effect :: Before ) ) ;
600+ MaybeLiveLocals :: transfer_function ( & mut state) . visit_terminator ( term, loc) ;
561601
562602 for ( statement_index, stmt) in block_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
563603 let loc = Location { block, statement_index } ;
564- twostep = TwoStepIndex :: from_u32 ( twostep . as_u32 ( ) + 1 ) ;
565- debug_assert_eq ! ( twostep , two_step_loc( loc, Effect :: After ) ) ;
566- append_at ( & mut values , & state , twostep ) ;
604+ state . current = state . current + 1 ;
605+ debug_assert_eq ! ( state . current , two_step_loc( loc, Effect :: After ) ) ;
606+
567607 // Like terminators, ensure we have a non-zero live range even for dead stores.
568608 // Some rvalues interleave reads and writes, for instance `Rvalue::Aggregate`, see
569609 // https://github.com/rust-lang/rust/issues/146383. By precaution, treat statements
@@ -582,26 +622,26 @@ fn save_as_intervals<'tcx>(
582622 if let Some ( relevant) = relevant. shrink [ place. local ] {
583623 match DefUse :: for_place ( place, ctxt) {
584624 DefUse :: Def | DefUse :: PartialWrite => {
585- values . insert ( relevant, twostep ) ;
625+ state . insert_single ( relevant) ;
586626 }
587627 DefUse :: Use if !is_simple_assignment => {
588- values . insert ( relevant, twostep ) ;
628+ state . insert_single ( relevant) ;
589629 }
590630 DefUse :: Use | DefUse :: NonUse => { }
591631 }
592632 }
593633 } )
594634 . visit_statement ( stmt, loc) ;
595635
596- twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( ) + 1 ) ;
597- debug_assert_eq ! ( twostep, two_step_loc( loc, Effect :: Before ) ) ;
598- MaybeLiveLocals . apply_early_statement_effect ( & mut state, stmt, loc) ;
599- MaybeLiveLocals . apply_primary_statement_effect ( & mut state, stmt, loc) ;
600636 // ... but reads from operands are marked as live here so they do not conflict with
601637 // the all the writes we manually marked as live in the second half of the statement.
602- append_at ( & mut values, & state, twostep) ;
638+ state. current = TwoStepIndex :: from_u32 ( state. current . as_u32 ( ) + 1 ) ;
639+ debug_assert_eq ! ( state. current, two_step_loc( loc, Effect :: Before ) ) ;
640+ MaybeLiveLocals :: transfer_function ( & mut state) . visit_statement ( stmt, loc) ;
603641 }
642+
643+ state. finish_block ( ) ;
604644 }
605645
606- values
646+ state . values
607647}
0 commit comments