134134use rustc_data_structures:: fx:: FxIndexMap ;
135135use rustc_index:: bit_set:: { BitMatrix , DenseBitSet } ;
136136use rustc_index:: interval:: SparseIntervalMatrix ;
137+ use rustc_index:: { IndexVec , newtype_index} ;
137138use rustc_middle:: bug;
138139use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext , Visitor } ;
139140use rustc_middle:: mir:: {
@@ -186,8 +187,13 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
186187 trace ! ( ?candidates) ;
187188 dest_prop_mir_dump ( tcx, body, & points, & live, round_count) ;
188189
189- let mut filter =
190- FilterInformation :: filter_liveness ( & points, & live, & mut write_info, body) ;
190+ let mut filter = FilterInformation :: filter_liveness (
191+ & points,
192+ & live,
193+ & mut write_info,
194+ body,
195+ & candidates,
196+ ) ;
191197
192198 // This is the set of merges we will apply this round. It is a subset of the candidates.
193199 let mut merges = FxIndexMap :: default ( ) ;
@@ -316,6 +322,45 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
316322 }
317323}
318324
325+ //////////////////////////////////////////////////////////
326+ // Relevant locals
327+ //
328+ // Small utility to reduce size of the conflict matrix by only considering locals that appear in
329+ // the candidates
330+
331+ newtype_index ! {
332+ /// Represent a subset of locals which appear in candidates.
333+ struct RelevantLocal { }
334+ }
335+
336+ #[ derive( Debug ) ]
337+ struct RelevantLocals {
338+ original : IndexVec < RelevantLocal , Local > ,
339+ shrink : IndexVec < Local , Option < RelevantLocal > > ,
340+ }
341+
342+ impl RelevantLocals {
343+ #[ tracing:: instrument( level = "trace" , skip( candidates, num_locals) , ret) ]
344+ fn compute ( candidates : & Candidates , num_locals : usize ) -> RelevantLocals {
345+ let mut original = IndexVec :: with_capacity ( candidates. c . len ( ) ) ;
346+ let mut shrink = IndexVec :: from_elem_n ( None , num_locals) ;
347+
348+ // Mark a local as relevant and record it into the maps.
349+ let mut declare = |local| {
350+ shrink. get_or_insert_with ( local, || original. push ( local) ) ;
351+ } ;
352+
353+ for ( & src, destinations) in candidates. c . iter ( ) {
354+ declare ( src) ;
355+ for & dest in destinations {
356+ declare ( dest)
357+ }
358+ }
359+
360+ RelevantLocals { original, shrink }
361+ }
362+ }
363+
319364//////////////////////////////////////////////////////////
320365// Liveness filtering
321366//
@@ -324,7 +369,8 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
324369struct FilterInformation < ' a , ' tcx > {
325370 body : & ' a Body < ' tcx > ,
326371 points : & ' a DenseLocationMap ,
327- conflicts : BitMatrix < Local , Local > ,
372+ relevant : RelevantLocals ,
373+ conflicts : BitMatrix < RelevantLocal , RelevantLocal > ,
328374 write_info : & ' a mut WriteInfo ,
329375 at : Location ,
330376}
@@ -371,12 +417,16 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
371417 live : & SparseIntervalMatrix < Local , PointIndex > ,
372418 write_info : & ' a mut WriteInfo ,
373419 body : & ' a Body < ' tcx > ,
420+ candidates : & Candidates ,
374421 ) -> Self {
375422 let num_locals = body. local_decls . len ( ) ;
423+ let relevant = RelevantLocals :: compute ( candidates, num_locals) ;
424+ let num_relevant = relevant. original . len ( ) ;
376425 let mut this = FilterInformation {
377426 body,
427+ relevant,
378428 points,
379- conflicts : BitMatrix :: new ( num_locals , num_locals ) ,
429+ conflicts : BitMatrix :: new ( num_relevant , num_relevant ) ,
380430 // We don't actually store anything at this scope, we just keep things here to be able
381431 // to reuse the allocation.
382432 write_info,
@@ -404,22 +454,28 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
404454 }
405455
406456 fn record_conflicts ( & mut self , live : & SparseIntervalMatrix < Local , PointIndex > ) {
407- let writes = & self . write_info . writes ;
408- let skip_pair = self . write_info . skip_pair ;
457+ let writes = self . write_info . writes . iter ( ) . filter_map ( |& p| self . relevant . shrink [ p] ) ;
458+
459+ let skip_pair = self . write_info . skip_pair . and_then ( |( p, q) | {
460+ let p = self . relevant . shrink [ p] ?;
461+ let q = self . relevant . shrink [ q] ?;
462+ Some ( ( p, q) )
463+ } ) ;
464+
409465 let at = self . points . point_from_location ( self . at ) ;
410466
411- for & p in writes {
412- for & q in writes {
467+ for p in writes. clone ( ) {
468+ for q in writes. clone ( ) {
413469 if p != q && skip_pair != Some ( ( p, q) ) && skip_pair != Some ( ( q, p) ) {
414470 self . conflicts . insert ( p, q) ;
415471 }
416472 }
417473
418- for q in live . rows ( ) {
474+ for ( q , & original_q ) in self . relevant . original . iter_enumerated ( ) {
419475 if p != q
420476 && skip_pair != Some ( ( p, q) )
421477 && skip_pair != Some ( ( q, p) )
422- && live. contains ( q , at)
478+ && live. contains ( original_q , at)
423479 {
424480 self . conflicts . insert ( p, q) ;
425481 }
@@ -430,14 +486,18 @@ impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
430486 #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
431487 fn record_merge ( & mut self , src : Local , dest : Local ) {
432488 trace ! ( ?self . conflicts, "pre" ) ;
489+ let src = self . relevant . shrink [ src] . expect ( "merged locals are relevant" ) ;
490+ let dest = self . relevant . shrink [ dest] . expect ( "merged locals are relevant" ) ;
433491 self . conflicts . union_rows ( src, dest) ;
434492 self . conflicts . union_cols ( src, dest) ;
435493 trace ! ( ?self . conflicts, "post" ) ;
436494 }
437495
438496 #[ tracing:: instrument( level = "trace" , skip( self ) , ret) ]
439497 fn find_non_conflicting ( & self , src : Local , candidates : & Vec < Local > ) -> Option < Local > {
498+ let src = self . relevant . shrink [ src] . expect ( "merged locals are relevant" ) ;
440499 candidates. iter ( ) . copied ( ) . find ( |& dest| {
500+ let dest = self . relevant . shrink [ dest] . expect ( "merged locals are relevant" ) ;
441501 !self . conflicts . contains ( src, dest) && !self . conflicts . contains ( dest, src)
442502 } )
443503 }
0 commit comments