diff --git a/src/compiler/rust/cfg.rs b/src/compiler/rust/cfg.rs index 5a80256f350..80380d545aa 100644 --- a/src/compiler/rust/cfg.rs +++ b/src/compiler/rust/cfg.rs @@ -2,8 +2,10 @@ // SPDX-License-Identifier: MIT use crate::bitset::BitSet; +use crate::depth_first_search::{dfs, DepthFirstSearch}; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; +use std::iter::{Cloned, Rev}; use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::slice; @@ -32,49 +34,61 @@ impl DerefMut for CFGNode { } } -fn graph_post_dfs( - nodes: &[CFGNode], - id: usize, - seen: &mut BitSet, - post_idx: &mut Vec, - count: &mut usize, -) { - if seen.contains(id) { - return; - } - seen.insert(id); +struct PostOrderSort { + post_idx: Vec, + count: usize, +} - // Reverse the order of the successors so that any successors which are - // forward edges get descending indices. This ensures that, in the reverse - // post order, successors (and their dominated children) come in-order. - // In particular, as long as fall-through edges are only ever used for - // forward edges and the fall-through edge comes first, we guarantee that - // the fallthrough block comes immediately after its predecessor. - for s in nodes[id].succ.iter().rev() { - graph_post_dfs(nodes, *s, seen, post_idx, count); +struct PostOrderSortDFS<'a, N> { + nodes: &'a [CFGNode], + sort: PostOrderSort, +} + +impl<'a, N> DepthFirstSearch for PostOrderSortDFS<'a, N> { + type ChildIter = Cloned>>; + + fn pre(&mut self, id: usize) -> Self::ChildIter { + // Reverse the order of the successors so that any successors which are + // forward edges get descending indices. This ensures that, in the + // reverse post order, successors (and their dominated children) come + // in-order. In particular, as long as fall-through edges are only ever + // used for forward edges and the fall-through edge comes first, we + // guarantee that the fallthrough block comes immediately after its + // predecessor. + self.nodes[id].succ.iter().rev().cloned() } - post_idx[id] = *count; - *count += 1; + fn post(&mut self, id: usize) { + self.sort.post_idx[id] = self.sort.count; + self.sort.count += 1; + } +} + +impl PostOrderSort { + fn new(nodes: &[CFGNode]) -> Self { + let mut post_idx: Vec = Vec::new(); + post_idx.resize(nodes.len(), usize::MAX); + + let mut sort_dfs = PostOrderSortDFS { + nodes, + sort: PostOrderSort { post_idx, count: 0 }, + }; + dfs(&mut sort_dfs, 0); + + sort_dfs.sort + } } fn rev_post_order_sort(nodes: &mut Vec>) { - let mut seen = BitSet::new(); - let mut post_idx = Vec::new(); - post_idx.resize(nodes.len(), usize::MAX); - let mut count = 0; - - graph_post_dfs(nodes, 0, &mut seen, &mut post_idx, &mut count); - - assert!(count <= nodes.len()); + let sort = PostOrderSort::new(nodes); let remap_idx = |i: usize| { - let pid = post_idx[i]; + let pid = sort.post_idx[i]; if pid == usize::MAX { None } else { - assert!(pid < count); - Some((count - 1) - pid) + assert!(pid < sort.count); + Some((sort.count - 1) - pid) } }; assert!(remap_idx(0) == Some(0)); @@ -95,13 +109,13 @@ fn rev_post_order_sort(nodes: &mut Vec>) { // We know a priori that each non-MAX post_idx is unique so we can sort the // nodes by inserting them into a new array by index. - let mut sorted: Vec> = Vec::with_capacity(count); + let mut sorted: Vec> = Vec::with_capacity(sort.count); for (i, n) in nodes.drain(..).enumerate() { if let Some(r) = remap_idx(i) { unsafe { sorted.as_mut_ptr().add(r).write(n) }; } } - unsafe { sorted.set_len(count) }; + unsafe { sorted.set_len(sort.count) }; std::mem::swap(nodes, &mut sorted); }