@@ -162,10 +162,19 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
162162 trace ! ( ?def_id) ;
163163
164164 let borrowed = rustc_mir_dataflow:: impls:: borrowed_locals ( body) ;
165+ let points = DenseLocationMap :: new ( body) ;
166+
167+ candidates. reset_and_find ( body, & borrowed) ;
168+ trace ! ( ?candidates) ;
169+ if candidates. c . is_empty ( ) {
170+ return ;
171+ }
172+
173+ let relevant = RelevantLocals :: compute ( & candidates, body. local_decls . len ( ) ) ;
165174
166175 let live = MaybeLiveLocals . iterate_to_fixpoint ( tcx, body, Some ( "MaybeLiveLocals-DestProp" ) ) ;
167- let points = DenseLocationMap :: new ( body ) ;
168- let mut live = save_as_intervals ( & points, body, live. analysis , live. results ) ;
176+ let mut live =
177+ save_as_intervals ( & points, body, & relevant . original , live. analysis , live. results ) ;
169178
170179 // In order to avoid having to collect data for every single pair of locals in the body, we
171180 // do not allow doing more than one merge for places that are derived from the same local at
@@ -181,22 +190,14 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
181190 // https://github.com/rust-lang/regex/tree/b5372864e2df6a2f5e543a556a62197f50ca3650
182191 let mut round_count = 0 ;
183192 loop {
184- // PERF: Can we do something smarter than recalculating the candidates and liveness
185- // results?
186- candidates. reset_and_find ( body, & borrowed) ;
187- trace ! ( ?candidates) ;
188- if candidates. c . is_empty ( ) {
189- break ;
190- }
191-
192- dest_prop_mir_dump ( tcx, body, & points, & live, round_count) ;
193+ dest_prop_mir_dump ( tcx, body, & points, & live, & relevant, round_count) ;
193194
194195 let mut filter = FilterInformation :: filter_liveness (
195196 & points,
196197 & live,
197198 & mut write_info,
198199 body,
199- & candidates ,
200+ & relevant ,
200201 ) ;
201202
202203 // This is the set of merges we will apply this round. It is a subset of the candidates.
@@ -216,6 +217,10 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
216217 merged_locals. insert ( src) ;
217218 merged_locals. insert ( dest) ;
218219
220+ // `find_non_conflicting` ensures this is true.
221+ let src = relevant. shrink [ src] . expect ( "merged locals are relevant" ) ;
222+ let dest = relevant. shrink [ dest] . expect ( "merged locals are relevant" ) ;
223+
219224 // Update liveness information based on the merge we just performed.
220225 // Every location where `src` was live, `dest` will be live.
221226 live. union_rows ( src, dest) ;
@@ -232,6 +237,12 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
232237 round_count += 1 ;
233238
234239 apply_merges ( body, tcx, merges, merged_locals) ;
240+
241+ candidates. reset_and_find ( body, & borrowed) ;
242+ trace ! ( ?candidates) ;
243+ if candidates. c . is_empty ( ) {
244+ break ;
245+ }
235246 }
236247
237248 trace ! ( round_count) ;
@@ -373,7 +384,7 @@ impl RelevantLocals {
373384struct FilterInformation < ' a , ' tcx > {
374385 body : & ' a Body < ' tcx > ,
375386 points : & ' a DenseLocationMap ,
376- relevant : RelevantLocals ,
387+ relevant : & ' a RelevantLocals ,
377388 conflicts : BitMatrix < RelevantLocal , RelevantLocal > ,
378389 write_info : & ' a mut WriteInfo ,
379390 at : Location ,
@@ -418,13 +429,11 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
418429 /// locals as also being read from.
419430 fn filter_liveness (
420431 points : & ' a DenseLocationMap ,
421- live : & SparseIntervalMatrix < Local , PointIndex > ,
432+ live : & SparseIntervalMatrix < RelevantLocal , PointIndex > ,
422433 write_info : & ' a mut WriteInfo ,
423434 body : & ' a Body < ' tcx > ,
424- candidates : & Candidates ,
435+ relevant : & ' a RelevantLocals ,
425436 ) -> Self {
426- let num_locals = body. local_decls . len ( ) ;
427- let relevant = RelevantLocals :: compute ( candidates, num_locals) ;
428437 let num_relevant = relevant. original . len ( ) ;
429438 let mut this = FilterInformation {
430439 body,
@@ -441,7 +450,7 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
441450 this
442451 }
443452
444- fn internal_filter_liveness ( & mut self , live : & SparseIntervalMatrix < Local , PointIndex > ) {
453+ fn internal_filter_liveness ( & mut self , live : & SparseIntervalMatrix < RelevantLocal , PointIndex > ) {
445454 for ( block, data) in traversal:: preorder ( self . body ) {
446455 self . at = Location { block, statement_index : data. statements . len ( ) } ;
447456 self . write_info . for_terminator ( & data. terminator ( ) . kind ) ;
@@ -457,7 +466,7 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
457466 trace ! ( ?self . conflicts, "initial conflicts" ) ;
458467 }
459468
460- fn record_conflicts ( & mut self , live : & SparseIntervalMatrix < Local , PointIndex > ) {
469+ fn record_conflicts ( & mut self , live : & SparseIntervalMatrix < RelevantLocal , PointIndex > ) {
461470 let writes = self . write_info . writes . iter ( ) . filter_map ( |& p| self . relevant . shrink [ p] ) ;
462471
463472 let skip_pair = self . write_info . skip_pair . and_then ( |( p, q) | {
@@ -475,11 +484,11 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
475484 }
476485 }
477486
478- for ( q , & original_q ) in self . relevant . original . iter_enumerated ( ) {
487+ for q in self . relevant . original . indices ( ) {
479488 if p != q
480489 && skip_pair != Some ( ( p, q) )
481490 && skip_pair != Some ( ( q, p) )
482- && live. contains ( original_q , at)
491+ && live. contains ( q , at)
483492 {
484493 self . conflicts . insert ( p, q) ;
485494 }
@@ -488,21 +497,21 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
488497 }
489498
490499 #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
491- fn record_merge ( & mut self , src : Local , dest : Local ) {
500+ fn record_merge ( & mut self , src : RelevantLocal , dest : RelevantLocal ) {
492501 trace ! ( ?self . conflicts, "pre" ) ;
493- let src = self . relevant . shrink [ src] . expect ( "merged locals are relevant" ) ;
494- let dest = self . relevant . shrink [ dest] . expect ( "merged locals are relevant" ) ;
495502 self . conflicts . union_rows ( src, dest) ;
496503 self . conflicts . union_cols ( src, dest) ;
497504 trace ! ( ?self . conflicts, "post" ) ;
498505 }
499506
500507 #[ tracing:: instrument( level = "trace" , skip( self ) , ret) ]
501508 fn find_non_conflicting ( & self , src : Local , candidates : & Vec < Local > ) -> Option < Local > {
502- let src = self . relevant . shrink [ src] . expect ( "merged locals are relevant" ) ;
509+ // Refuse to merge if the local is not marked relevant.
510+ let src = self . relevant . shrink [ src] ?;
503511 candidates. iter ( ) . copied ( ) . find ( |& dest| {
504- let dest = self . relevant . shrink [ dest] . expect ( "merged locals are relevant" ) ;
505- !self . conflicts . contains ( src, dest) && !self . conflicts . contains ( dest, src)
512+ self . relevant . shrink [ dest] . is_some_and ( |dest| {
513+ !self . conflicts . contains ( src, dest) && !self . conflicts . contains ( dest, src)
514+ } )
506515 } )
507516 }
508517}
@@ -773,12 +782,16 @@ fn dest_prop_mir_dump<'tcx>(
773782 tcx : TyCtxt < ' tcx > ,
774783 body : & Body < ' tcx > ,
775784 points : & DenseLocationMap ,
776- live : & SparseIntervalMatrix < Local , PointIndex > ,
785+ live : & SparseIntervalMatrix < RelevantLocal , PointIndex > ,
786+ relevant : & RelevantLocals ,
777787 round : usize ,
778788) {
779789 let locals_live_at = |location| {
780790 let location = points. point_from_location ( location) ;
781- live. rows ( ) . filter ( |& r| live. contains ( r, location) ) . collect :: < Vec < _ > > ( )
791+ live. rows ( )
792+ . filter ( |& r| live. contains ( r, location) )
793+ . map ( |rl| relevant. original [ rl] )
794+ . collect :: < Vec < _ > > ( )
782795 } ;
783796 dump_mir ( tcx, false , "DestinationPropagation-dataflow" , & round, body, |pass_where, w| {
784797 if let PassWhere :: BeforeLocation ( loc) = pass_where {
0 commit comments