diff options
| author | Rémy Rakic <remy.rakic+github@gmail.com> | 2025-01-09 15:33:38 +0000 |
|---|---|---|
| committer | Rémy Rakic <remy.rakic+github@gmail.com> | 2025-01-17 11:52:58 +0000 |
| commit | dee52a31789fb87e04b4762df5b84d52738b1adb (patch) | |
| tree | 16e14e2dfe4d89a1c092039544bc4a2315786f11 | |
| parent | 0114a9707e92306adc15111cfb1ea9d1ab0e8f05 (diff) | |
| download | rust-dee52a31789fb87e04b4762df5b84d52738b1adb.tar.gz rust-dee52a31789fb87e04b4762df5b84d52738b1adb.zip | |
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.
| -rw-r--r-- | compiler/rustc_borrowck/src/polonius/loan_liveness.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/polonius/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/polonius/typeck_constraints.rs | 22 |
3 files changed, 49 insertions, 25 deletions
diff --git a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs index 3fa2a66e3ba..768c12a97a6 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs @@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; use super::{LiveLoans, LocalizedOutlivesConstraintSet}; +use crate::constraints::OutlivesConstraint; use crate::dataflow::BorrowIndex; use crate::region_infer::values::LivenessValues; +use crate::type_check::Locations; use crate::{BorrowSet, PlaceConflictBias, places_conflict}; -/// With the full graph of constraints, we can compute loan reachability, stop at kills, and trace -/// loan liveness throughout the CFG. +/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by +/// 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>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, liveness: &LivenessValues, + outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>, borrow_set: &BorrowSet<'tcx>, localized_outlives_constraints: &LocalizedOutlivesConstraintSet, ) -> LiveLoans { @@ -29,7 +34,11 @@ pub(super) fn compute_loan_liveness<'tcx>( // edges when visualizing the constraint graph anyways. 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 stack = Vec::new(); @@ -125,11 +134,16 @@ pub(super) fn compute_loan_liveness<'tcx>( live_loans } -/// The localized constraint graph indexes the physical edges to compute a given node's successors -/// during traversal. +/// The localized constraint graph indexes the physical and logical edges to compute a given node's +/// successors during traversal. struct LocalizedConstraintGraph { /// The actual, physical, edges we have recorded for a given node. 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. @@ -141,7 +155,10 @@ struct LocalizedNode { impl LocalizedConstraintGraph { /// 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(); for constraint in &constraints.outlives { let source = LocalizedNode { region: constraint.source, point: constraint.from }; @@ -149,12 +166,30 @@ impl LocalizedConstraintGraph { 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. 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) } } diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 52a5f75d8a2..502c868194a 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -130,6 +130,7 @@ impl PoloniusContext { tcx, body, regioncx.liveness_constraints(), + regioncx.outlives_constraints(), borrow_set, &localized_outlives_constraints, ); diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index 8235b844886..1289b1899eb 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -22,23 +22,11 @@ pub(super) fn convert_typeck_constraints<'tcx>( for outlives_constraint in outlives_constraints { match outlives_constraint.locations { Locations::All(_) => { - // For now, turn logical constraints holding at all points into physical edges at - // every point in the graph. - // FIXME: encode this into *traversal* instead. - for (block, bb) in body.basic_blocks.iter_enumerated() { - let statement_count = bb.statements.len(); - 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, - }); - } - } + // We don't turn constraints holding at all points into physical edges at every + // point in the graph. They are encoded into *traversal* instead: a given node's + // successors will combine these logical edges with the regular, physical, localized + // edges. + continue; } Locations::Single(location) => { |
