Skip to content

Commit

Permalink
Optimize Trace.
Browse files Browse the repository at this point in the history
`Trace::FromOutlivesConstraint` contains an `OutlivesConstraint`, which
is 72 bytes. Lots of these are created but never used.

This commit splits `Trace::FromOutlivesConstraint` into three new
variants: `FromVanilla`, `FromStatic`, `FromMember`. Each of these
contains just enough data to construct an `OutlivesConstraint`, if
necessary. This reduces the size of `Trace` from 72 bytes to 16 bytes.
All this avoids some memory traffic.
  • Loading branch information
nnethercote committed Feb 26, 2025
1 parent bb5e137 commit 48a95d1
Showing 1 changed file with 51 additions and 36 deletions.
87 changes: 51 additions & 36 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,11 @@ enum RegionRelationCheckResult {
}

#[derive(Clone, PartialEq, Eq, Debug)]
enum Trace<'tcx> {
enum Trace<'a, 'tcx> {
StartRegion,
FromOutlivesConstraint(OutlivesConstraint<'tcx>),
FromVanilla(&'a OutlivesConstraint<'tcx>),
FromStatic(RegionVid),
FromMember(RegionVid, RegionVid, Span),
NotVisited,
}

Expand Down Expand Up @@ -1764,6 +1766,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
context[from_region] = Trace::StartRegion;

let fr_static = self.universal_regions().fr_static;

// Use a deque so that we do a breadth-first search. We will
// stop at the first match, which ought to be the shortest
// path (fewest constraints).
Expand All @@ -1783,13 +1787,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if target_test(r) {
let mut result = vec![];
let mut p = r;
// This loop is cold and runs at the end, which is why we delay
// `OutlivesConstraint` construction until now.
loop {
match context[p].clone() {
Trace::NotVisited => {
bug!("found unvisited region {:?} on path to {:?}", p, r)
match context[p] {
Trace::FromVanilla(c) => {
p = c.sup;
result.push(*c);
}

Trace::FromOutlivesConstraint(c) => {
Trace::FromStatic(sub) => {
let c = OutlivesConstraint {
sup: fr_static,
sub,
locations: Locations::All(DUMMY_SP),
span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: ty::VarianceDiagInfo::default(),
from_closure: false,
};
p = c.sup;
result.push(c);
}

Trace::FromMember(sup, sub, span) => {
let c = OutlivesConstraint {
sup,
sub,
locations: Locations::All(span),
span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
from_closure: false,
};
p = c.sup;
result.push(c);
}
Expand All @@ -1798,6 +1828,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
result.reverse();
return Some((result, r));
}

Trace::NotVisited => {
bug!("found unvisited region {:?} on path to {:?}", p, r)
}
}
}
}
Expand All @@ -1808,33 +1842,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {

// A constraint like `'r: 'x` can come from our constraint
// graph.
let fr_static = self.universal_regions().fr_static;

// Always inline this closure because it can be hot.
let mut handle_constraint = #[inline(always)]
|constraint: &OutlivesConstraint<'tcx>| {
debug_assert_eq!(constraint.sup, r);
let sub_region = constraint.sub;
if let Trace::NotVisited = context[sub_region] {
context[sub_region] = Trace::FromOutlivesConstraint(*constraint);
deque.push_back(sub_region);
let mut handle_trace = #[inline(always)]
|sub, trace| {
if let Trace::NotVisited = context[sub] {
context[sub] = trace;
deque.push_back(sub);
}
};

// If this is the `'static` region and the graph's direction is normal, then set up the
// Edges iterator to return all regions (#53178).
if r == fr_static && self.constraint_graph.is_normal() {
for next_static_idx in self.constraint_graph.outgoing_edges_static() {
let constraint = OutlivesConstraint {
sup: fr_static,
sub: next_static_idx,
locations: Locations::All(DUMMY_SP),
span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: ty::VarianceDiagInfo::default(),
from_closure: false,
};
handle_constraint(&constraint);
for sub in self.constraint_graph.outgoing_edges_static() {
handle_trace(sub, Trace::FromStatic(sub));
}
} else {
let edges = self.constraint_graph.outgoing_edges_vanilla(r, &self.constraints);
Expand All @@ -1844,25 +1866,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!("Ignoring illegal universe constraint: {constraint:?}");
continue;
}
handle_constraint(constraint);
debug_assert_eq!(constraint.sup, r);
handle_trace(constraint.sub, Trace::FromVanilla(constraint));
}
}

// Member constraints can also give rise to `'r: 'x` edges that
// were not part of the graph initially, so watch out for those.
// (But they are extremely rare; this loop is very cold.)
for constraint in self.applied_member_constraints(self.constraint_sccs.scc(r)) {
let sub = constraint.min_choice;
let p_c = &self.member_constraints[constraint.member_constraint_index];
let constraint = OutlivesConstraint {
sup: r,
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
span: p_c.definition_span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
from_closure: false,
};
handle_constraint(&constraint);
handle_trace(sub, Trace::FromMember(r, sub, p_c.definition_span));
}
}

Expand Down

0 comments on commit 48a95d1

Please sign in to comment.