@@ -7,10 +7,10 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Loc
77use rustc_middle:: traits:: query:: DropckOutlivesResult ;
88use rustc_middle:: ty:: relate:: Relate ;
99use rustc_middle:: ty:: { Ty , TyCtxt , TypeVisitable , TypeVisitableExt } ;
10- use rustc_mir_dataflow:: impls:: MaybeInitializedPlaces ;
10+ use rustc_mir_dataflow:: impls:: { FilteringMovePathIndexMapper , MaybeInitializedPlaces2 } ;
1111use rustc_mir_dataflow:: move_paths:: { HasMoveData , MoveData , MovePathIndex } ;
1212use rustc_mir_dataflow:: points:: { DenseLocationMap , PointIndex } ;
13- use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
13+ use rustc_mir_dataflow:: { Analysis , ResultsCursor , on_all_children_bits } ;
1414use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span } ;
1515use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
1616use rustc_trait_selection:: traits:: ObligationCtxt ;
@@ -45,13 +45,29 @@ pub(super) fn trace<'tcx>(
4545 boring_locals : Vec < Local > ,
4646) {
4747 let local_use_map = & LocalUseMap :: build ( & relevant_live_locals, location_map, typeck. body ) ;
48+
49+ let mut dense_mpis = smallvec:: SmallVec :: new ( ) ;
50+ for & local in relevant_live_locals. iter ( ) {
51+ let Some ( mpi) = move_data. rev_lookup . find_local ( local) else { unreachable ! ( ) } ;
52+
53+ // We only compute initializedness in drop-liveness on locals with drop points.
54+ if local_use_map. drops ( local) . next ( ) . is_none ( ) {
55+ continue ;
56+ }
57+
58+ on_all_children_bits ( move_data, mpi, |child| {
59+ dense_mpis. push ( child) ;
60+ } ) ;
61+ }
62+
4863 let cx = LivenessContext {
4964 typeck,
5065 flow_inits : None ,
5166 location_map,
5267 local_use_map,
5368 move_data,
5469 drop_data : FxIndexMap :: default ( ) ,
70+ dense_mpis,
5571 } ;
5672
5773 let mut results = LivenessResults :: new ( cx) ;
@@ -81,11 +97,15 @@ struct LivenessContext<'a, 'typeck, 'tcx> {
8197
8298 /// Results of dataflow tracking which variables (and paths) have been
8399 /// initialized. Computed lazily when needed by drop-liveness.
84- flow_inits : Option < ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces < ' a , ' tcx > > > ,
100+ flow_inits : Option <
101+ ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces2 < ' a , ' tcx , FilteringMovePathIndexMapper > > ,
102+ > ,
85103
86104 /// Index indicating where each variable is assigned, used, or
87105 /// dropped.
88106 local_use_map : & ' a LocalUseMap ,
107+
108+ dense_mpis : smallvec:: SmallVec < [ MovePathIndex ; 1 ] > ,
89109}
90110
91111struct DropData < ' tcx > {
@@ -468,7 +488,10 @@ impl<'a, 'typeck, 'tcx> LivenessContext<'a, 'typeck, 'tcx> {
468488 ///
469489 /// This happens as part of the drop-liveness computation: it's the only place checking for
470490 /// maybe-initializedness of `MovePathIndex`es.
471- fn flow_inits ( & mut self ) -> & mut ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces < ' a , ' tcx > > {
491+ fn flow_inits (
492+ & mut self ,
493+ ) -> & mut ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces2 < ' a , ' tcx , FilteringMovePathIndexMapper > >
494+ {
472495 self . flow_inits . get_or_insert_with ( || {
473496 let tcx = self . typeck . tcx ( ) ;
474497 let body = self . typeck . body ;
@@ -484,9 +507,85 @@ impl<'a, 'typeck, 'tcx> LivenessContext<'a, 'typeck, 'tcx> {
484507 // a much, much smaller domain: in our benchmarks, when it's not zero (the most likely
485508 // case), there are a few dozens compared to e.g. thousands or tens of thousands of
486509 // locals and move paths.
487- let flow_inits = MaybeInitializedPlaces :: new ( tcx, body, self . move_data )
510+ // eprintln!(
511+ // "computing flow_inits: {} MPIs total, {} relevant MPIs",
512+ // self.move_data.move_paths.len(),
513+ // self.dense_mpis.len()
514+ // );
515+
516+ // FIXME: use the sparse vec + bitset metadata trick instead of a map!
517+
518+ // let map_timer = std::time::Instant::now();
519+ // let mut sparse_map = FxIndexMap::default();
520+ // for (idx, &dense_idx) in self.dense_mpis.iter().enumerate() {
521+ // let sparse_idx = SparseMovePathIndex::from_usize(idx);
522+ // sparse_map.insert(dense_idx, sparse_idx);
523+ // }
524+ // // for local in body.args_iter() {
525+ // // let Some(mpi) = self.move_data.rev_lookup.find_local(local) else { unreachable!() };
526+ // // self.dense_mpis.push(mpi);
527+ // // map.insert(mpi, self.dense_mpis.len());
528+ // // }
529+
530+ // let map_len = sparse_map.len();
531+ // let mapper = FilteringMovePathIndexMapper { sparse_map };
532+ // let map_elapsed = map_timer.elapsed();
533+
534+ // // let mapper = rustc_mir_dataflow::impls::NoOpMapper;
535+
536+ // let sparse_bitset_timer = std::time::Instant::now();
537+
538+ // // let mut sparse_bitset = Sparse32::new(self.dense_mpis.len());
539+ // // // FIXME: do this in asc order to keep idxes stable and not shuffle the vec inside
540+ // // for &dense_idx in self.dense_mpis.iter() {
541+ // // sparse_bitset.insert(dense_idx);
542+ // // }
543+
544+ // let sparse_bitset = Sparse32::new(&self.dense_mpis);
545+
546+ // // let sparse_bitset_elapsed = sparse_bitset_timer.elapsed();
547+ // // let sparse_bitset_len = sparse_bitset.dense.len();
548+
549+ // // let sparse_bitset_timer = std::time::Instant::now();
550+
551+ // let mut sparse_bitset = Sparse::new(
552+ // 1 + self.dense_mpis.iter().max().unwrap().as_usize(),
553+ // self.dense_mpis.len(),
554+ // );
555+ // // FIXME: do this in asc order to keep idxes stable and not shuffle the vec inside
556+ // for &dense_idx in self.dense_mpis.iter() {
557+ // sparse_bitset.insert(dense_idx);
558+ // }
559+ // // also: move this into the sparse ctor, so that prefixes can be computed there after inserting stuff
560+
561+ // sparse_bitset.compute_prefixes();
562+
563+ // // let sparse_bitset_elapsed = sparse_bitset_timer.elapsed();
564+ // // let sparse_bitset_len = sparse_bitset.sparse.len();
565+
566+ // let mapper = sparse_bitset;
567+
568+ // let timer = std::time::Instant::now();
569+ let flow_inits = MaybeInitializedPlaces2 :: new ( tcx, body, self . move_data )
570+ . filter_move_paths ( & self . dense_mpis )
571+ // .with_mapper(mapper)
488572 . iterate_to_fixpoint ( tcx, body, Some ( "borrowck" ) )
489573 . into_results_cursor ( body) ;
574+ // let elapsed = timer.elapsed();
575+
576+ // use std::sync::OnceLock;
577+ // static PROFILE: OnceLock<bool> = OnceLock::new();
578+ // if *PROFILE.get_or_init(|| std::env::var("LETSGO1").is_ok()) {
579+ // eprintln!(
580+ // "flow_inits took {:?} ns, map of {} took: {} ns, sparse bitset of {} took {} ns, {:?}",
581+ // elapsed.as_nanos(),
582+ // map_len,
583+ // map_elapsed.as_nanos(),
584+ // sparse_bitset_len,
585+ // sparse_bitset_elapsed.as_nanos(),
586+ // body.span,
587+ // );
588+ // }
490589 flow_inits
491590 } )
492591 }
@@ -502,13 +601,24 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
502601 /// the cursor to the desired location.
503602 fn initialized_at_curr_loc ( & mut self , mpi : MovePathIndex ) -> bool {
504603 let flow_inits = self . flow_inits ( ) ;
604+ let analysis = flow_inits. analysis ( ) ;
605+ let idx = analysis
606+ . map_index ( mpi)
607+ . unwrap_or_else ( || unreachable ! ( "dataflow is somehow missing MPI {mpi:?}" ) ) ;
505608 let state = flow_inits. get ( ) ;
506- if state. contains ( mpi ) {
609+ if state. contains ( idx ) {
507610 return true ;
508611 }
509612
510- let move_paths = & flow_inits. analysis ( ) . move_data ( ) . move_paths ;
511- move_paths[ mpi] . find_descendant ( move_paths, |mpi| state. contains ( mpi) ) . is_some ( )
613+ let move_paths = & analysis. move_data ( ) . move_paths ;
614+ move_paths[ mpi]
615+ . find_descendant ( move_paths, |mpi| {
616+ let idx = analysis
617+ . map_index ( mpi)
618+ . unwrap_or_else ( || unreachable ! ( "dataflow is somehow missing MPI {mpi:?}" ) ) ;
619+ state. contains ( idx)
620+ } )
621+ . is_some ( )
512622 }
513623
514624 /// Returns `true` if the local variable (or some part of it) is initialized in
0 commit comments