fn head_walk(&mut self,
                 node: G::Node)
                 -> HashSet<LoopId> {
        assert_eq!(self.state[node], NotYetStarted);
        self.state[node] = InProgress(None);

        // Walk our successors and collect the set of backedges they
        // reach.
        let mut set = HashSet::new();
        for successor in self.graph.successors(node) {
            match self.state[successor] {
                NotYetStarted => {
                    set.extend(self.head_walk(successor));
                }
                InProgress(opt_loop_id) => {
                    // Backedge. Successor is a loop-head.
                    if let Some(loop_id) = opt_loop_id {
                        set.insert(loop_id);
                    } else {
                        set.insert(self.promote_to_loop_head(successor));
                    }
                }
                FinishedHeadWalk => {
                    // Cross edge.
                }
                EnqueuedExitWalk => {
                    unreachable!()
                }
            }
        }

        self.state[node] = FinishedHeadWalk;

        // Assign a loop-id to this node. This will be the innermost
        // loop that we could reach.
        match self.innermost(&set) {
            Some(loop_id) => {
                self.loop_tree.set_loop_id(node, Some(loop_id));

                // Check if we are the loop head. In that case, we
                // should remove ourselves from the returned set,
                // since our parent in the spanning tree is not a
                // member of this loop.
                let loop_head = self.loop_tree.loop_head(loop_id);
                if node == loop_head {
                    set.remove(&loop_id);

                    // Now the next-innermost loop is the parent of this loop.
                    let parent_loop_id = self.innermost(&set);
                    self.loop_tree.set_parent(loop_id, parent_loop_id);
                }
            }
            None => {
                assert!(set.is_empty());
                assert!(self.loop_tree.loop_id(node).is_none()); // all none by default
            }
        }

        set
    }
/// First walk: identify loop heads and loop parents. This uses a
/// variant of Tarjan's SCC algorithm. Basically, we do a
/// depth-first search. Each time we encounter a backedge, the
/// target of that backedge is a loop-head, so we make a
/// corresponding loop, if we haven't done so already. We then track
/// the set of loops that `node` was able to reach via backedges.
/// The innermost such loop is the loop-id of `node`, and we then
/// return the set for use by the predecessor of `node`.
First walk: identify loop heads and loop parents. This uses a
variant of Tarjan's SCC algorithm. Basically, we do a
depth-first search. Each time we encounter a backedge, the
target of that backedge is a loop-head, so we make a
corresponding loop, if we haven't done so already. We then track
the set of loops that `node` was able to reach via backedges.
The innermost such loop is the loop-id of `node`, and we then
return the set for use by the predecessor of `node`.
First walk : identify loop heads and loop parents . This uses a variant of Tarjan ' s SCC algorithm . Basically we do a depth - first search . Each time we encounter a backedge the target of that backedge is a loop - head so we make a corresponding loop if we haven ' t done so already . We then track the set of loops that ` node ` was able to reach via backedges . The innermost such loop is the loop - id of ` node ` and we then return the set for use by the predecessor of ` node ` .
fn head_walk(&mut self,
                 node: G::Node)
                 -> HashSet<LoopId> {
        assert_eq!(self.state[node], NotYetStarted);
        self.state[node] = InProgress(None);
        // Walk our successors and collect the set of backedges they
        // reach.
        let mut set = HashSet::new();
        for successor in self.graph.successors(node) {
            match self.state[successor] {
                NotYetStarted => {
                    set.extend(self.head_walk(successor));
                }
                InProgress(opt_loop_id) => {
                    // Backedge. Successor is a loop-head.
                    if let Some(loop_id) = opt_loop_id {
                        set.insert(loop_id);
                    } else {
                        set.insert(self.promote_to_loop_head(successor));
                    }
                }
                FinishedHeadWalk => {
                    // Cross edge.
                }
                EnqueuedExitWalk => {
                    unreachable!()
                }
            }
        }
        self.state[node] = FinishedHeadWalk;
        // Assign a loop-id to this node. This will be the innermost
        // loop that we could reach.
        match self.innermost(&set) {
            Some(loop_id) => {
                self.loop_tree.set_loop_id(node, Some(loop_id));
                // Check if we are the loop head. In that case, we
                // should remove ourselves from the returned set,
                // since our parent in the spanning tree is not a
                // member of this loop.
                let loop_head = self.loop_tree.loop_head(loop_id);
                if node == loop_head {
                    set.remove(&loop_id);
                    // Now the next-innermost loop is the parent of this loop.
                    let parent_loop_id = self.innermost(&set);
                    self.loop_tree.set_parent(loop_id, parent_loop_id);
                }
            }
            None => {
                assert!(set.is_empty());
                assert!(self.loop_tree.loop_id(node).is_none()); // all none by default
            }
        }
        set
    }
fn head_walk ( & mut self , node : G :: Node ) -> HashSet < LoopId > { assert_eq ! ( self state [ node ] NotYetStarted ) ; self . state [ node ] = InProgress ( None ) ; // Walk our successors and collect the set of backedges they // reach. let mut set = HashSet :: new ( ) ; for successor in self . graph . successors ( node ) { match self . state [ successor ] { NotYetStarted => { set . extend ( self . head_walk ( successor ) ) ; } InProgress ( opt_loop_id ) => { // Backedge. Successor is a loop-head. if let Some ( loop_id ) = opt_loop_id { set . insert ( loop_id ) ; } else { set . insert ( self . promote_to_loop_head ( successor ) ) ; } } FinishedHeadWalk => { // Cross edge. } EnqueuedExitWalk => { unreachable ! ( ) } } } self . state [ node ] = FinishedHeadWalk ; // Assign a loop-id to this node. This will be the innermost // loop that we could reach. match self . innermost ( & set ) { Some ( loop_id ) => { self . loop_tree . set_loop_id ( node , Some ( loop_id ) ) ; // Check if we are the loop head. In that case, we // should remove ourselves from the returned set, // since our parent in the spanning tree is not a // member of this loop. let loop_head = self . loop_tree . loop_head ( loop_id ) ; if node == loop_head { set . remove ( & loop_id ) ; // Now the next-innermost loop is the parent of this loop. let parent_loop_id = self . innermost ( & set ) ; self . loop_tree . set_parent ( loop_id , parent_loop_id ) ; } } None => { assert ! ( set is_empty ( ) ) ; assert ! ( self loop_tree loop_id ( node ) is_none ( ) ) ; // all none by default } } set }
First walk: identify loop heads and loop parents.
First walk : identify loop heads and loop parents .
&mut self
node
G::Node
&mut self
node
G::Node