diff --git a/src/compiler/rust/cfg.rs b/src/compiler/rust/cfg.rs index d8a82da92aa..abdd596c860 100644 --- a/src/compiler/rust/cfg.rs +++ b/src/compiler/rust/cfg.rs @@ -238,27 +238,41 @@ fn find_back_edges(nodes: &[CFGNode]) -> Vec<(usize, usize)> { be_dfs.back_edges } -/// Computes the set of nodes that reach the given node without going through -/// stop -fn reaches_dfs( - nodes: &Vec>, - id: usize, +struct ReachesDFS<'a, N> { + nodes: &'a [CFGNode], stop: usize, - reaches: &mut BitSet, -) { - if id == stop || reaches.contains(id) { - return; - } + reaches: BitSet, +} - reaches.insert(id); +impl<'a, N> DepthFirstSearch for ReachesDFS<'a, N> { + type ChildIter = Cloned>; - // Since we're trying to find the set of things that reach the start node, - // not the set of things reachable from the start node, walk predecessors. - for &s in nodes[id].pred.iter() { - reaches_dfs(nodes, s, stop, reaches); + fn pre(&mut self, id: usize) -> Self::ChildIter { + if id == self.stop || self.reaches.contains(id) { + return (&[]).iter().cloned(); + } + + self.reaches.insert(id); + + // Since we're trying to find the set of things that reach the start + // node, not the set of things reachable from the start node, walk + // predecessors. + self.nodes[id].pred.iter().cloned() } } +/// Computes the set of nodes that reach the given edge without going through +/// the edge +fn reaches(nodes: &Vec>, edge: (usize, usize)) -> BitSet { + let mut r_dfs = ReachesDFS { + nodes, + stop: edge.1, + reaches: Default::default(), + }; + dfs(&mut r_dfs, edge.0); + r_dfs.reaches +} + fn detect_loops(nodes: &mut Vec>) -> bool { let back_edges = find_back_edges(nodes); if back_edges.is_empty() { @@ -276,11 +290,7 @@ fn detect_loops(nodes: &mut Vec>) -> bool { // Stash the loop headers while we're here loops.insert(h); - // re-use dfs_pre for our reaches set - let mut reaches = BitSet::new(); - reaches_dfs(nodes, c, h, &mut reaches); - - for n in reaches.iter() { + for n in reaches(nodes, (c, h)).iter() { node_loops[n].insert(h); } }