encode Locations::All
typeck constraints as logical edges
Instead of materializing `Locations::All` constraints as physical edges at all the points in the CFG, we record them as logical edges and only materialize them during traversal as successors for a given node. This fixes the slowness/hang in the `saturating-float-casts.rs` test.
This commit is contained in:
parent
0114a9707e
commit
dee52a3178
3 changed files with 49 additions and 25 deletions
|
@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_mir_dataflow::points::PointIndex;
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
|
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
|
||||||
|
use crate::constraints::OutlivesConstraint;
|
||||||
use crate::dataflow::BorrowIndex;
|
use crate::dataflow::BorrowIndex;
|
||||||
use crate::region_infer::values::LivenessValues;
|
use crate::region_infer::values::LivenessValues;
|
||||||
|
use crate::type_check::Locations;
|
||||||
use crate::{BorrowSet, PlaceConflictBias, places_conflict};
|
use crate::{BorrowSet, PlaceConflictBias, places_conflict};
|
||||||
|
|
||||||
/// With the full graph of constraints, we can compute loan reachability, stop at kills, and trace
|
/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by
|
||||||
/// loan liveness throughout the CFG.
|
/// traversing the full graph of constraints that combines:
|
||||||
|
/// - the localized constraints (the physical edges),
|
||||||
|
/// - with the constraints that hold at all points (the logical edges).
|
||||||
pub(super) fn compute_loan_liveness<'tcx>(
|
pub(super) fn compute_loan_liveness<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
liveness: &LivenessValues,
|
liveness: &LivenessValues,
|
||||||
|
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||||
) -> LiveLoans {
|
) -> LiveLoans {
|
||||||
|
@ -29,7 +34,11 @@ pub(super) fn compute_loan_liveness<'tcx>(
|
||||||
// edges when visualizing the constraint graph anyways.
|
// edges when visualizing the constraint graph anyways.
|
||||||
let kills = collect_kills(body, tcx, borrow_set);
|
let kills = collect_kills(body, tcx, borrow_set);
|
||||||
|
|
||||||
let graph = LocalizedConstraintGraph::new(&localized_outlives_constraints);
|
// Create the full graph with the physical edges we've localized earlier, and the logical edges
|
||||||
|
// of constraints that hold at all points.
|
||||||
|
let logical_constraints =
|
||||||
|
outlives_constraints.filter(|c| matches!(c.locations, Locations::All(_)));
|
||||||
|
let graph = LocalizedConstraintGraph::new(&localized_outlives_constraints, logical_constraints);
|
||||||
let mut visited = FxHashSet::default();
|
let mut visited = FxHashSet::default();
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
@ -125,11 +134,16 @@ pub(super) fn compute_loan_liveness<'tcx>(
|
||||||
live_loans
|
live_loans
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The localized constraint graph indexes the physical edges to compute a given node's successors
|
/// The localized constraint graph indexes the physical and logical edges to compute a given node's
|
||||||
/// during traversal.
|
/// successors during traversal.
|
||||||
struct LocalizedConstraintGraph {
|
struct LocalizedConstraintGraph {
|
||||||
/// The actual, physical, edges we have recorded for a given node.
|
/// The actual, physical, edges we have recorded for a given node.
|
||||||
edges: FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>,
|
edges: FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>,
|
||||||
|
|
||||||
|
/// The logical edges representing the outlives constraints that hold at all points in the CFG,
|
||||||
|
/// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
|
||||||
|
/// can be big, and we don't need to create such a physical edge for every point in the CFG.
|
||||||
|
logical_edges: FxHashMap<RegionVid, FxIndexSet<RegionVid>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
|
/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
|
||||||
|
@ -141,7 +155,10 @@ struct LocalizedNode {
|
||||||
|
|
||||||
impl LocalizedConstraintGraph {
|
impl LocalizedConstraintGraph {
|
||||||
/// Traverses the constraints and returns the indexed graph of edges per node.
|
/// Traverses the constraints and returns the indexed graph of edges per node.
|
||||||
fn new(constraints: &LocalizedOutlivesConstraintSet) -> Self {
|
fn new<'tcx>(
|
||||||
|
constraints: &LocalizedOutlivesConstraintSet,
|
||||||
|
logical_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||||
|
) -> Self {
|
||||||
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
||||||
for constraint in &constraints.outlives {
|
for constraint in &constraints.outlives {
|
||||||
let source = LocalizedNode { region: constraint.source, point: constraint.from };
|
let source = LocalizedNode { region: constraint.source, point: constraint.from };
|
||||||
|
@ -149,12 +166,30 @@ impl LocalizedConstraintGraph {
|
||||||
edges.entry(source).or_default().insert(target);
|
edges.entry(source).or_default().insert(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalizedConstraintGraph { edges }
|
let mut logical_edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
||||||
|
for constraint in logical_constraints {
|
||||||
|
logical_edges.entry(constraint.sup).or_default().insert(constraint.sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalizedConstraintGraph { edges, logical_edges }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the outgoing edges of a given node, not its transitive closure.
|
/// Returns the outgoing edges of a given node, not its transitive closure.
|
||||||
fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator<Item = LocalizedNode> + use<'_> {
|
fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator<Item = LocalizedNode> + use<'_> {
|
||||||
self.edges.get(&node).into_iter().flat_map(|targets| targets.iter().copied())
|
// The outgoing edges are:
|
||||||
|
// - the physical edges present at this node,
|
||||||
|
// - the materialized logical edges that exist virtually at all points for this node's
|
||||||
|
// region, localized at this point.
|
||||||
|
let physical_edges =
|
||||||
|
self.edges.get(&node).into_iter().flat_map(|targets| targets.iter().copied());
|
||||||
|
let materialized_edges =
|
||||||
|
self.logical_edges.get(&node.region).into_iter().flat_map(move |targets| {
|
||||||
|
targets
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(move |target| LocalizedNode { point: node.point, region: target })
|
||||||
|
});
|
||||||
|
physical_edges.chain(materialized_edges)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ impl PoloniusContext {
|
||||||
tcx,
|
tcx,
|
||||||
body,
|
body,
|
||||||
regioncx.liveness_constraints(),
|
regioncx.liveness_constraints(),
|
||||||
|
regioncx.outlives_constraints(),
|
||||||
borrow_set,
|
borrow_set,
|
||||||
&localized_outlives_constraints,
|
&localized_outlives_constraints,
|
||||||
);
|
);
|
||||||
|
|
|
@ -22,23 +22,11 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
||||||
for outlives_constraint in outlives_constraints {
|
for outlives_constraint in outlives_constraints {
|
||||||
match outlives_constraint.locations {
|
match outlives_constraint.locations {
|
||||||
Locations::All(_) => {
|
Locations::All(_) => {
|
||||||
// For now, turn logical constraints holding at all points into physical edges at
|
// We don't turn constraints holding at all points into physical edges at every
|
||||||
// every point in the graph.
|
// point in the graph. They are encoded into *traversal* instead: a given node's
|
||||||
// FIXME: encode this into *traversal* instead.
|
// successors will combine these logical edges with the regular, physical, localized
|
||||||
for (block, bb) in body.basic_blocks.iter_enumerated() {
|
// edges.
|
||||||
let statement_count = bb.statements.len();
|
continue;
|
||||||
for statement_index in 0..=statement_count {
|
|
||||||
let current_location = Location { block, statement_index };
|
|
||||||
let current_point = liveness.point_from_location(current_location);
|
|
||||||
|
|
||||||
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
|
||||||
source: outlives_constraint.sup,
|
|
||||||
from: current_point,
|
|
||||||
target: outlives_constraint.sub,
|
|
||||||
to: current_point,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Locations::Single(location) => {
|
Locations::Single(location) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue