Skip to content

Commit 430e230

Browse files
committed
fast path: compute MaybeInitializedPlaces lazily
Only drop-liveness checks for maybe-initializedness of move paths, and it does so only for the relevant live locals that have drop points. This adds a fast path by computing this dataflow analysis only when checking for such initializedness. This avoids this expensive computation for the common case. For example, it avoids computing initializedness for 20K locals in the `cranelift-codegen` benchmark, it has 7K relevant live locals but none with drop points. That saves 900ms on end-to-end compilation times.
1 parent 10d39f5 commit 430e230

File tree

1 file changed

+33
-11
lines changed
  • compiler/rustc_borrowck/src/type_check/liveness

1 file changed

+33
-11
lines changed

compiler/rustc_borrowck/src/type_check/liveness/trace.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,9 @@ 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-
let flow_inits = MaybeInitializedPlaces::new(typeck.tcx(), typeck.body, move_data)
49-
.iterate_to_fixpoint(typeck.tcx(), typeck.body, Some("borrowck"))
50-
.into_results_cursor(typeck.body);
5148
let cx = LivenessContext {
5249
typeck,
53-
flow_inits,
50+
flow_inits: None,
5451
location_map,
5552
local_use_map,
5653
move_data,
@@ -83,8 +80,8 @@ struct LivenessContext<'a, 'typeck, 'tcx> {
8380
drop_data: FxIndexMap<Ty<'tcx>, DropData<'tcx>>,
8481

8582
/// Results of dataflow tracking which variables (and paths) have been
86-
/// initialized.
87-
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
83+
/// initialized. Computed lazily when needed by drop-liveness.
84+
flow_inits: Option<ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>>,
8885

8986
/// Index indicating where each variable is assigned, used, or
9087
/// dropped.
@@ -461,6 +458,28 @@ impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> {
461458
}
462459
}
463460

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+
let flow_inits = MaybeInitializedPlaces::new(tcx, body, self.move_data)
476+
.iterate_to_fixpoint(tcx, body, Some("borrowck"))
477+
.into_results_cursor(body);
478+
flow_inits
479+
})
480+
}
481+
}
482+
464483
impl<'tcx> LivenessContext<'_, '_, 'tcx> {
465484
fn body(&self) -> &Body<'tcx> {
466485
self.typeck.body
@@ -469,13 +488,14 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
469488
/// Returns `true` if the local variable (or some part of it) is initialized at the current
470489
/// cursor position. Callers should call one of the `seek` methods immediately before to point
471490
/// the cursor to the desired location.
472-
fn initialized_at_curr_loc(&self, mpi: MovePathIndex) -> bool {
473-
let state = self.flow_inits.get();
491+
fn initialized_at_curr_loc(&mut self, mpi: MovePathIndex) -> bool {
492+
let flow_inits = self.flow_inits();
493+
let state = flow_inits.get();
474494
if state.contains(mpi) {
475495
return true;
476496
}
477497

478-
let move_paths = &self.flow_inits.analysis().move_data().move_paths;
498+
let move_paths = &flow_inits.analysis().move_data().move_paths;
479499
move_paths[mpi].find_descendant(move_paths, |mpi| state.contains(mpi)).is_some()
480500
}
481501

@@ -484,7 +504,8 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
484504
/// DROP of some local variable will have an effect -- note that
485505
/// drops, as they may unwind, are always terminators.
486506
fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
487-
self.flow_inits.seek_before_primary_effect(self.body().terminator_loc(block));
507+
let terminator_location = self.body().terminator_loc(block);
508+
self.flow_inits().seek_before_primary_effect(terminator_location);
488509
self.initialized_at_curr_loc(mpi)
489510
}
490511

@@ -494,7 +515,8 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
494515
/// **Warning:** Does not account for the result of `Call`
495516
/// instructions.
496517
fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
497-
self.flow_inits.seek_after_primary_effect(self.body().terminator_loc(block));
518+
let terminator_location = self.body().terminator_loc(block);
519+
self.flow_inits().seek_after_primary_effect(terminator_location);
498520
self.initialized_at_curr_loc(mpi)
499521
}
500522

0 commit comments

Comments
 (0)