Skip to content

Commit 9414d24

Browse files
committed
invert order of liveness and subset traversal
During traversal, instead of checking: for each live region r at point p, whether the issuing region can reach r, we do this in the opposite order: for each rechable region r, is r live at point p. This will prevent continuously checking regions that are live at point p and that we know aren't reachable by the issuing region. If it did, we wouldn't need to compute the scope in the first place.
1 parent 04d93a6 commit 9414d24

File tree

3 files changed

+41
-45
lines changed

3 files changed

+41
-45
lines changed

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![deny(rustc::untranslatable_diagnostic)]
22
#![deny(rustc::diagnostic_outside_of_impl)]
3-
use rustc_data_structures::fx::FxIndexMap;
3+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
44
use rustc_index::bit_set::BitSet;
55
use rustc_middle::mir::{
66
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
@@ -251,9 +251,9 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
251251
body: &'a Body<'tcx>,
252252
regioncx: &'a RegionInferenceContext<'tcx>,
253253
loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
254-
placeholders: Vec<RegionVid>,
255-
reachability: BitSet<ConstraintSccIndex>,
256-
reachability_stack: Vec<ConstraintSccIndex>,
254+
placeholders: FxHashSet<ConstraintSccIndex>,
255+
reachability: BitSet<RegionVid>,
256+
reachability_stack: Vec<RegionVid>,
257257
}
258258

259259
impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
@@ -272,6 +272,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
272272
);
273273
is_placeholder
274274
})
275+
.map(|r| regioncx.constraint_sccs.scc(r))
275276
.collect();
276277

277278
Self {
@@ -281,7 +282,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
281282
regioncx,
282283
loans_out_of_scope_at_location: FxIndexMap::default(),
283284
placeholders,
284-
reachability: BitSet::new_empty(regioncx.constraint_sccs.num_sccs()),
285+
reachability: BitSet::new_empty(regioncx.regions().count()),
285286
reachability_stack: vec![],
286287
}
287288
}
@@ -302,38 +303,51 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
302303
// regions via member constraints. (The `OutOfScopePrecomputer` wouldn't be called on a
303304
// region that outlives free regions via outlives constraints.)
304305

305-
let liveness = &self.regioncx.liveness_constraints;
306306
let sccs = &self.regioncx.constraint_sccs;
307+
let member_constraints = &self.regioncx.member_constraints;
307308

308-
let issuing_region_scc = sccs.scc(issuing_region);
309-
self.reachability_stack.push(issuing_region_scc);
310-
self.reachability.insert(issuing_region_scc);
309+
self.reachability_stack.push(issuing_region);
310+
self.reachability.insert(issuing_region);
311311

312-
let member_constraints = &self.regioncx.member_constraints;
312+
let static_region = self.regioncx.universal_regions().fr_static;
313+
while let Some(region) = self.reachability_stack.pop() {
314+
let scc = sccs.scc(region);
313315

314-
while let Some(scc) = self.reachability_stack.pop() {
315316
// Handle successors of this SCC:
316317
//
317-
// 1. Push outlives successors to the worklist stack
318-
for &succ_scc in sccs.successors(scc) {
319-
if self.reachability.insert(succ_scc) {
320-
self.reachability_stack.push(succ_scc);
321-
}
322-
}
323-
324-
// 2. Deal with member constraints
318+
// 1. Via member constraints
325319
//
326320
// The issuing region can flow into the choice regions here, and they are either:
327321
// - placeholders or free regions themselves,
328322
// - or also transitively outlive a free region.
329323
//
330324
// That is to say, if there are member constraints here, the loan escapes the
331325
// function and cannot go out of scope. We can early return.
332-
if member_constraints.indices(scc).next().is_some() {
326+
//
327+
// 2. Via placeholders
328+
//
329+
// If the issuing region outlives placeholders, its loan escapes the function and
330+
// cannot go out of scope. We can early return.
331+
if member_constraints.indices(scc).next().is_some() || self.placeholders.contains(&scc)
332+
{
333333
self.reachability_stack.clear();
334334
self.reachability.clear();
335335
return;
336336
}
337+
338+
// 3. Via outlives successors, which we want to record and traverse, so we add them
339+
// to the worklist stack
340+
let successors = self.regioncx.constraint_graph.outgoing_edges(
341+
region,
342+
&self.regioncx.constraints,
343+
static_region,
344+
);
345+
for outlives_constraint in successors {
346+
let succ = outlives_constraint.sub;
347+
if self.reachability.insert(succ) {
348+
self.reachability_stack.push(succ);
349+
}
350+
}
337351
}
338352

339353
// We visit one BB at a time. The complication is that we may start in the
@@ -364,23 +378,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
364378
// live regions.
365379
let mut issuing_region_can_reach_live_regions = false;
366380

367-
// Check reachability of all live regions:
368-
// - the local regions that are live at this point,
369-
// - the placeholders, which are live at all points and don't need liveness to be
370-
// computed, and are thus absent from the liveness values.
371-
//
372-
// As mentioned above, we don't need to check for free regions, if the issuing
373-
// region outlived a free region via outlives constraints, we wouldn't need to
374-
// compute its loan's scope.
375-
for live_region in
376-
liveness.live_regions_at(location).chain(self.placeholders.iter().copied())
377-
{
378-
let live_region_scc = sccs.scc(live_region);
379-
380-
// If a single live region is reachable from the issuing region, then the loan
381-
// is still live at this point. We can stop checking other live regions at this
382-
// location, and go to the next location.
383-
if self.reachability.contains(live_region_scc) {
381+
// Check whether the issuing region can reach local regions that are live at this
382+
// point.
383+
for reachable_region in self.reachability.iter() {
384+
if self.regioncx.liveness_constraints.contains(reachable_region, location) {
384385
issuing_region_can_reach_live_regions = true;
385386
break;
386387
}
@@ -431,7 +432,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
431432
self.visited.clear();
432433
self.reachability.clear();
433434
assert!(self.visit_stack.is_empty(), "visit stack should be empty");
434-
assert!(self.reachability_stack.is_empty(), "reachablity stack should be empty");
435+
assert!(self.reachability_stack.is_empty(), "reachability stack should be empty");
435436
}
436437
}
437438

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ pub struct RegionInferenceContext<'tcx> {
6161
pub(crate) liveness_constraints: LivenessValues<RegionVid>,
6262

6363
/// The outlives constraints computed by the type-check.
64-
constraints: Frozen<OutlivesConstraintSet<'tcx>>,
64+
pub(crate) constraints: Frozen<OutlivesConstraintSet<'tcx>>,
6565

6666
/// The constraint-set, but in graph form, making it easy to traverse
6767
/// the constraints adjacent to a particular region. Used to construct
6868
/// the SCC (see `constraint_sccs`) and for error reporting.
69-
constraint_graph: Frozen<NormalConstraintGraph>,
69+
pub(crate) constraint_graph: Frozen<NormalConstraintGraph>,
7070

7171
/// The SCC computed from `constraints` and the constraint
7272
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to

compiler/rustc_borrowck/src/region_infer/values.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,6 @@ impl<N: Idx> LivenessValues<N> {
176176
pub(crate) fn region_value_str(&self, r: N) -> String {
177177
region_value_str(self.get_elements(r).map(RegionElement::Location))
178178
}
179-
180-
pub(crate) fn live_regions_at(&self, location: Location) -> impl Iterator<Item = N> + '_ {
181-
let point = self.elements.point_from_location(location);
182-
self.points.rows().filter(move |row| self.points.contains(*row, point))
183-
}
184179
}
185180

186181
/// Maps from `ty::PlaceholderRegion` values that are used in the rest of

0 commit comments

Comments
 (0)