Skip to content

Commit

Permalink
dump scc graphviz too
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Jul 4, 2018
1 parent 3472813 commit 05d4880
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 16 deletions.
5 changes: 5 additions & 0 deletions src/librustc_data_structures/graph/scc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ impl<N: Idx, S: Idx> Sccs<N, S> {
self.scc_data.len()
}

/// Returns the number of SCCs in the graph.
pub fn all_sccs(&self) -> impl Iterator<Item = S> {
(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]
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_mir/borrow_check/nll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down
89 changes: 82 additions & 7 deletions src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConstraintSccIndex, _> = 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> {
Expand Down Expand Up @@ -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<ConstraintSccIndex, Vec<RegionVid>>,
}

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<dot::LabelText<'this>> {
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<ConstraintSccIndex> = 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
}
}
32 changes: 24 additions & 8 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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<ConstraintSccIndex>,
) {
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<ConstraintSccIndex>,
) {
let constraints_scc = self.constraints_scc.clone();

// Walk each SCC `B` such that `A: B`...
Expand All @@ -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);
Expand Down

0 comments on commit 05d4880

Please sign in to comment.