1
Fork 0

Optimize Trace.

`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.
This commit is contained in:
Nicholas Nethercote 2025-02-27 10:03:33 +11:00
parent afc5e1fba5
commit 9a0513ad71

View file

@ -311,9 +311,11 @@ enum RegionRelationCheckResult {
}
#[derive(Clone, PartialEq, Eq, Debug)]
enum Trace<'tcx> {
enum Trace<'a, 'tcx> {
StartRegion,
FromOutlivesConstraint(OutlivesConstraint<'tcx>),
FromGraph(&'a OutlivesConstraint<'tcx>),
FromStatic(RegionVid),
FromMember(RegionVid, RegionVid, Span),
NotVisited,
}
@ -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).
@ -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::FromGraph(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);
}
@ -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)
}
}
}
}
@ -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_from_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_from_static() {
handle_trace(sub, Trace::FromStatic(sub));
}
} else {
let edges = self.constraint_graph.outgoing_edges_from_graph(r, &self.constraints);
@ -1844,7 +1866,8 @@ 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::FromGraph(constraint));
}
}
@ -1852,17 +1875,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// 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));
}
}