@@ -7,10 +7,10 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Loc
7
7
use rustc_middle:: traits:: query:: DropckOutlivesResult ;
8
8
use rustc_middle:: ty:: relate:: Relate ;
9
9
use rustc_middle:: ty:: { Ty , TyCtxt , TypeVisitable , TypeVisitableExt } ;
10
- use rustc_mir_dataflow:: ResultsCursor ;
11
10
use rustc_mir_dataflow:: impls:: MaybeInitializedPlaces ;
12
11
use rustc_mir_dataflow:: move_paths:: { HasMoveData , MoveData , MovePathIndex } ;
13
12
use rustc_mir_dataflow:: points:: { DenseLocationMap , PointIndex } ;
13
+ use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
14
14
use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span } ;
15
15
use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
16
16
use rustc_trait_selection:: traits:: ObligationCtxt ;
@@ -37,18 +37,17 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
37
37
/// DROP-LIVE set are to the liveness sets for regions found in the
38
38
/// `dropck_outlives` result of the variable's type (in particular,
39
39
/// this respects `#[may_dangle]` annotations).
40
- pub ( super ) fn trace < ' a , ' tcx > (
40
+ pub ( super ) fn trace < ' tcx > (
41
41
typeck : & mut TypeChecker < ' _ , ' tcx > ,
42
42
location_map : & DenseLocationMap ,
43
- flow_inits : ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces < ' a , ' tcx > > ,
44
43
move_data : & MoveData < ' tcx > ,
45
44
relevant_live_locals : Vec < Local > ,
46
45
boring_locals : Vec < Local > ,
47
46
) {
48
47
let local_use_map = & LocalUseMap :: build ( & relevant_live_locals, location_map, typeck. body ) ;
49
48
let cx = LivenessContext {
50
49
typeck,
51
- flow_inits,
50
+ flow_inits : None ,
52
51
location_map,
53
52
local_use_map,
54
53
move_data,
@@ -65,7 +64,7 @@ pub(super) fn trace<'a, 'tcx>(
65
64
}
66
65
67
66
/// Contextual state for the type-liveness coroutine.
68
- struct LivenessContext < ' a , ' typeck , ' b , ' tcx > {
67
+ struct LivenessContext < ' a , ' typeck , ' tcx > {
69
68
/// Current type-checker, giving us our inference context etc.
70
69
///
71
70
/// This also stores the body we're currently analyzing.
@@ -81,8 +80,8 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
81
80
drop_data : FxIndexMap < Ty < ' tcx > , DropData < ' tcx > > ,
82
81
83
82
/// Results of dataflow tracking which variables (and paths) have been
84
- /// initialized.
85
- flow_inits : ResultsCursor < ' b , ' tcx , MaybeInitializedPlaces < ' b , ' tcx > > ,
83
+ /// initialized. Computed lazily when needed by drop-liveness.
84
+ flow_inits : Option < ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces < ' a , ' tcx > > > ,
86
85
87
86
/// Index indicating where each variable is assigned, used, or
88
87
/// dropped.
@@ -94,8 +93,8 @@ struct DropData<'tcx> {
94
93
region_constraint_data : Option < & ' tcx QueryRegionConstraints < ' tcx > > ,
95
94
}
96
95
97
- struct LivenessResults < ' a , ' typeck , ' b , ' tcx > {
98
- cx : LivenessContext < ' a , ' typeck , ' b , ' tcx > ,
96
+ struct LivenessResults < ' a , ' typeck , ' tcx > {
97
+ cx : LivenessContext < ' a , ' typeck , ' tcx > ,
99
98
100
99
/// Set of points that define the current local.
101
100
defs : DenseBitSet < PointIndex > ,
@@ -116,8 +115,8 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
116
115
stack : Vec < PointIndex > ,
117
116
}
118
117
119
- impl < ' a , ' typeck , ' b , ' tcx > LivenessResults < ' a , ' typeck , ' b , ' tcx > {
120
- fn new ( cx : LivenessContext < ' a , ' typeck , ' b , ' tcx > ) -> Self {
118
+ impl < ' a , ' typeck , ' tcx > LivenessResults < ' a , ' typeck , ' tcx > {
119
+ fn new ( cx : LivenessContext < ' a , ' typeck , ' tcx > ) -> Self {
121
120
let num_points = cx. location_map . num_points ( ) ;
122
121
LivenessResults {
123
122
cx,
@@ -459,20 +458,56 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
459
458
}
460
459
}
461
460
462
- impl < ' tcx > LivenessContext < ' _ , ' _ , ' _ , ' tcx > {
461
+ impl < ' a , ' typeck , ' tcx > LivenessContext < ' a , ' typeck , ' tcx > {
462
+ /// Computes the `MaybeInitializedPlaces` dataflow analysis if it hasn't been done already.
463
+ ///
464
+ /// In practice, the results of this dataflow analysis are rarely needed but can be expensive to
465
+ /// compute on big functions, so we compute them lazily as a fast path when:
466
+ /// - there are relevant live locals
467
+ /// - there are drop points for these relevant live locals.
468
+ ///
469
+ /// This happens as part of the drop-liveness computation: it's the only place checking for
470
+ /// maybe-initializedness of `MovePathIndex`es.
471
+ fn flow_inits ( & mut self ) -> & mut ResultsCursor < ' a , ' tcx , MaybeInitializedPlaces < ' a , ' tcx > > {
472
+ self . flow_inits . get_or_insert_with ( || {
473
+ let tcx = self . typeck . tcx ( ) ;
474
+ let body = self . typeck . body ;
475
+ // FIXME: reduce the `MaybeInitializedPlaces` domain to the useful `MovePath`s.
476
+ //
477
+ // This dataflow analysis computes maybe-initializedness of all move paths, which
478
+ // explains why it can be expensive on big functions. But this data is only used in
479
+ // drop-liveness. Therefore, most of the move paths computed here are ultimately unused,
480
+ // even if the results are computed lazily and "no relevant live locals with drop
481
+ // points" is the common case.
482
+ //
483
+ // So we only need the ones for 1) relevant live locals 2) that have drop points. That's
484
+ // a much, much smaller domain: in our benchmarks, when it's not zero (the most likely
485
+ // case), there are a few dozens compared to e.g. thousands or tens of thousands of
486
+ // locals and move paths.
487
+ let flow_inits = MaybeInitializedPlaces :: new ( tcx, body, self . move_data )
488
+ . iterate_to_fixpoint ( tcx, body, Some ( "borrowck" ) )
489
+ . into_results_cursor ( body) ;
490
+ flow_inits
491
+ } )
492
+ }
493
+ }
494
+
495
+ impl < ' tcx > LivenessContext < ' _ , ' _ , ' tcx > {
463
496
fn body ( & self ) -> & Body < ' tcx > {
464
497
self . typeck . body
465
498
}
499
+
466
500
/// Returns `true` if the local variable (or some part of it) is initialized at the current
467
501
/// cursor position. Callers should call one of the `seek` methods immediately before to point
468
502
/// the cursor to the desired location.
469
- fn initialized_at_curr_loc ( & self , mpi : MovePathIndex ) -> bool {
470
- let state = self . flow_inits . get ( ) ;
503
+ fn initialized_at_curr_loc ( & mut self , mpi : MovePathIndex ) -> bool {
504
+ let flow_inits = self . flow_inits ( ) ;
505
+ let state = flow_inits. get ( ) ;
471
506
if state. contains ( mpi) {
472
507
return true ;
473
508
}
474
509
475
- let move_paths = & self . flow_inits . analysis ( ) . move_data ( ) . move_paths ;
510
+ let move_paths = & flow_inits. analysis ( ) . move_data ( ) . move_paths ;
476
511
move_paths[ mpi] . find_descendant ( move_paths, |mpi| state. contains ( mpi) ) . is_some ( )
477
512
}
478
513
@@ -481,7 +516,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
481
516
/// DROP of some local variable will have an effect -- note that
482
517
/// drops, as they may unwind, are always terminators.
483
518
fn initialized_at_terminator ( & mut self , block : BasicBlock , mpi : MovePathIndex ) -> bool {
484
- self . flow_inits . seek_before_primary_effect ( self . body ( ) . terminator_loc ( block) ) ;
519
+ let terminator_location = self . body ( ) . terminator_loc ( block) ;
520
+ self . flow_inits ( ) . seek_before_primary_effect ( terminator_location) ;
485
521
self . initialized_at_curr_loc ( mpi)
486
522
}
487
523
@@ -491,7 +527,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
491
527
/// **Warning:** Does not account for the result of `Call`
492
528
/// instructions.
493
529
fn initialized_at_exit ( & mut self , block : BasicBlock , mpi : MovePathIndex ) -> bool {
494
- self . flow_inits . seek_after_primary_effect ( self . body ( ) . terminator_loc ( block) ) ;
530
+ let terminator_location = self . body ( ) . terminator_loc ( block) ;
531
+ self . flow_inits ( ) . seek_after_primary_effect ( terminator_location) ;
495
532
self . initialized_at_curr_loc ( mpi)
496
533
}
497
534
0 commit comments