From 05d4880b39f9efd46f8df62e89013c0c9cc88bcf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 4 Jul 2018 06:29:06 -0400 Subject: [PATCH] dump scc graphviz too --- src/librustc_data_structures/graph/scc/mod.rs | 5 ++ src/librustc_mir/borrow_check/nll/mod.rs | 9 +- .../borrow_check/nll/region_infer/graphviz.rs | 89 +++++++++++++++++-- .../borrow_check/nll/region_infer/mod.rs | 32 +++++-- 4 files changed, 119 insertions(+), 16 deletions(-) diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index b0f098b3d204f..e7a84e4779754 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -54,6 +54,11 @@ impl Sccs { self.scc_data.len() } + /// Returns the number of SCCs in the graph. + pub fn all_sccs(&self) -> impl Iterator { + (0 .. self.scc_data.len()).map(S::new) + } + /// Returns the SCC to which a node `r` belongs. pub fn scc(&self, r: N) -> S { self.scc_indices[r] diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 641d7ed342c24..acd9223e42545 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -295,9 +295,16 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( // Also dump the inference graph constraints as a graphviz file. let _: io::Result<()> = do catch { let mut file = - pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?; + pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, source)?; regioncx.dump_graphviz_raw_constraints(&mut file)?; }; + + // Also dump the inference graph constraints as a graphviz file. + let _: io::Result<()> = do catch { + let mut file = + pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, source)?; + regioncx.dump_graphviz_scc_constraints(&mut file)?; + }; } fn dump_annotation<'a, 'gcx, 'tcx>( diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index 2e41c8f8dd6a2..8e18be15737f0 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -12,22 +12,37 @@ //! libgraphviz traits, specialized to attaching borrowck analysis //! data to rendered labels. +use super::*; +use borrow_check::nll::constraints::OutlivesConstraint; use dot::{self, IntoCow}; use rustc_data_structures::indexed_vec::Idx; use std::borrow::Cow; use std::io::{self, Write}; -use super::*; -use borrow_check::nll::constraints::OutlivesConstraint; impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. - pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { dot::render(&RawConstraints { regioncx: self }, &mut w) } + + /// Write out the region constraint graph. + crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + let mut nodes_per_scc: IndexVec = self.constraints_scc + .all_sccs() + .map(|_| Vec::new()) + .collect(); + + for region in self.definitions.indices() { + let scc = self.constraints_scc.scc(region); + nodes_per_scc[scc].push(region); + } + + dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) + } } struct RawConstraints<'a, 'tcx: 'a> { - regioncx: &'a RegionInferenceContext<'tcx> + regioncx: &'a RegionInferenceContext<'tcx>, } impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { @@ -63,14 +78,74 @@ impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { (&self.regioncx.constraints.raw[..]).into_cow() } - // Render `a: b` as `a <- b`, indicating the flow + // Render `a: b` as `a -> b`, indicating the flow // of data during inference. fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid { - edge.sub + edge.sup } fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid { - edge.sup + edge.sub + } +} + +struct SccConstraints<'a, 'tcx: 'a> { + regioncx: &'a RegionInferenceContext<'tcx>, + nodes_per_scc: IndexVec>, +} + +impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn graph_id(&'this self) -> dot::Id<'this> { + dot::Id::new(format!("RegionInferenceContext")).unwrap() + } + fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { + dot::Id::new(format!("r{}", n.index())).unwrap() + } + fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option> { + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) + } + fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { + let nodes = &self.nodes_per_scc[*n]; + dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into_cow()) + } +} + +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { + let vids: Vec = self.regioncx.constraints_scc.all_sccs().collect(); + vids.into_cow() + } + fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { + let edges: Vec<_> = self.regioncx + .constraints_scc + .all_sccs() + .flat_map(|scc_a| { + self.regioncx + .constraints_scc + .successors(scc_a) + .iter() + .map(move |&scc_b| (scc_a, scc_b)) + }) + .collect(); + + edges.into_cow() + } + + // Render `a: b` as `a -> b`, indicating the flow + // of data during inference. + + fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.0 + } + + fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.1 } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 16c5e91938b50..1f1e8ed728675 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -9,8 +9,9 @@ // except according to those terms. use super::universal_regions::UniversalRegions; -use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSccIndex, ConstraintSet, - OutlivesConstraint}; +use borrow_check::nll::constraints::{ + ConstraintIndex, ConstraintSccIndex, ConstraintSet, OutlivesConstraint, +}; use borrow_check::nll::region_infer::values::ToElementIndex; use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; @@ -26,7 +27,8 @@ use rustc::mir::{ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common; use rustc_data_structures::graph::scc::Sccs; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; +use rustc_data_structures::indexed_vec::IndexVec; use std::rc::Rc; @@ -402,14 +404,28 @@ impl<'tcx> RegionInferenceContext<'tcx> { // SCC. For each SCC, we visit its successors and compute // their values, then we union all those values to get our // own. - for scc_index in (0..self.constraints_scc.num_sccs()).map(ConstraintSccIndex::new) { - self.propagate_constraints_scc(scc_index); + let visited = &mut IdxSetBuf::new_empty(self.constraints_scc.num_sccs()); + for scc_index in self.constraints_scc.all_sccs() { + self.propagate_constraints_scc_if_new(scc_index, visited); } } - fn propagate_constraints_scc(&mut self, scc_a: ConstraintSccIndex) { - debug!("propagate_constraints_scc(scc_a = {:?})", scc_a); + #[inline] + fn propagate_constraints_scc_if_new( + &mut self, + scc_a: ConstraintSccIndex, + visited: &mut IdxSet, + ) { + if visited.add(&scc_a) { + self.propagate_constraints_scc_new(scc_a, visited); + } + } + fn propagate_constraints_scc_new( + &mut self, + scc_a: ConstraintSccIndex, + visited: &mut IdxSet, + ) { let constraints_scc = self.constraints_scc.clone(); // Walk each SCC `B` such that `A: B`... @@ -420,7 +436,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); // ...compute the value of `B`... - self.propagate_constraints_scc(scc_b); + self.propagate_constraints_scc_if_new(scc_b, visited); // ...and add elements from `B` into `A`. self.scc_values.add_region(scc_a, scc_b);