1use super::postorder_filtered;
2use crate::index::MaybeNodeIndex;
3use crate::unmanaged::UnmanagedDenseMap;
4use crate::{Direction, LinkView, NodeIndex, PortGraph, PortIndex, PortView, SecondaryMap};
5use std::cmp::Ordering;
6
7pub fn dominators<Map>(
45 graph: &PortGraph,
46 entry: NodeIndex,
47 direction: Direction,
48) -> DominatorTree<Map>
49where
50 Map: SecondaryMap<NodeIndex, MaybeNodeIndex<u32>>,
51{
52 DominatorTree::new(graph, entry, direction, |_| true, |_, _| true)
53}
54
55pub fn dominators_filtered<Map>(
106 graph: &PortGraph,
107 entry: NodeIndex,
108 direction: Direction,
109 node_filter: impl FnMut(NodeIndex) -> bool,
110 port_filter: impl FnMut(NodeIndex, PortIndex) -> bool,
111) -> DominatorTree<Map>
112where
113 Map: SecondaryMap<NodeIndex, MaybeNodeIndex<u32>>,
114{
115 DominatorTree::new(graph, entry, direction, node_filter, port_filter)
116}
117
118pub struct DominatorTree<Map = UnmanagedDenseMap<NodeIndex, MaybeNodeIndex<u32>>> {
122 root: NodeIndex,
123 idom: Map,
125}
126
127impl<Map> DominatorTree<Map>
128where
129 Map: SecondaryMap<NodeIndex, MaybeNodeIndex<u32>>,
130{
131 fn new(
132 graph: &PortGraph,
133 entry: NodeIndex,
134 direction: Direction,
135 mut node_filter: impl FnMut(NodeIndex) -> bool,
136 mut port_filter: impl FnMut(NodeIndex, PortIndex) -> bool,
137 ) -> Self {
138 let mut node_to_index = UnmanagedDenseMap::with_capacity(graph.node_capacity());
141 let mut index_to_node = Vec::with_capacity(graph.node_capacity());
142
143 for (index, node) in postorder_filtered(
144 graph,
145 [entry],
146 direction,
147 &mut node_filter,
148 &mut port_filter,
149 )
150 .enumerate()
151 {
152 node_to_index[node] = index;
153 index_to_node.push(node);
154 }
155
156 let num_nodes = index_to_node.len();
159 let mut dominators = vec![usize::MAX; num_nodes];
160 *dominators.last_mut().unwrap() = num_nodes - 1;
161
162 let mut changed = true;
164 while changed {
165 changed = false;
166
167 for post_order_index in (0..num_nodes - 1).rev() {
168 let node = index_to_node[post_order_index];
169
170 let new_dominator = graph
175 .ports(node, direction.reverse())
176 .filter_map(|port| {
177 if !port_filter(node, port) {
178 return None;
179 }
180 let link = graph.port_link(port)?;
181 let pred = graph.port_node(link)?;
182 if !node_filter(pred) || !port_filter(pred, link) {
183 return None;
184 }
185 let pred_index = node_to_index[pred];
186 if dominators[pred_index] == usize::MAX {
187 return None;
189 }
190 Some(pred_index)
191 })
192 .reduce(|index1, index2| intersect(&dominators, index1, index2))
193 .expect("there must be at least one predecessor with known dominator");
194
195 if new_dominator != dominators[post_order_index] {
196 changed = true;
197 dominators[post_order_index] = new_dominator;
198 }
199 }
200 }
201
202 let mut idom = Map::with_capacity(graph.node_capacity());
204
205 for (index, dominator) in dominators.into_iter().take(num_nodes - 1).enumerate() {
206 debug_assert_ne!(dominator, usize::MAX);
207 idom.set(index_to_node[index], index_to_node[dominator].into());
208 }
209
210 Self { root: entry, idom }
211 }
212
213 #[inline]
214 pub fn root(&self) -> NodeIndex {
216 self.root
217 }
218
219 #[inline]
220 pub fn immediate_dominator(&self, node: NodeIndex) -> Option<NodeIndex> {
222 self.idom.get(node).to_option()
223 }
224}
225
226#[inline]
227fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
228 loop {
229 match finger1.cmp(&finger2) {
230 Ordering::Less => finger1 = dominators[finger1],
231 Ordering::Equal => return finger1,
232 Ordering::Greater => finger2 = dominators[finger2],
233 }
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use crate::{LinkMut, PortMut};
240
241 use super::*;
242
243 #[test]
244 fn test_dominators_small() {
245 let mut graph = PortGraph::with_capacity(5, 10);
249 let a = graph.add_node(0, 2);
250 let b = graph.add_node(1, 1);
251 let c = graph.add_node(2, 1);
252 let d = graph.add_node(1, 1);
253 let e = graph.add_node(1, 0);
254
255 graph.link_nodes(a, 0, b, 0).unwrap();
256 graph.link_nodes(a, 1, d, 0).unwrap();
257 graph.link_nodes(b, 0, c, 0).unwrap();
258 graph.link_nodes(d, 0, c, 1).unwrap();
259 graph.link_nodes(c, 0, e, 0).unwrap();
260
261 let tree: DominatorTree = dominators(&graph, a, Direction::Outgoing);
263 assert_eq!(tree.root(), a);
264 assert_eq!(tree.immediate_dominator(a), None);
265 assert_eq!(tree.immediate_dominator(b), Some(a));
266 assert_eq!(tree.immediate_dominator(c), Some(a));
267 assert_eq!(tree.immediate_dominator(d), Some(a));
268 assert_eq!(tree.immediate_dominator(e), Some(c));
269
270 let tree: DominatorTree = dominators(&graph, c, Direction::Incoming);
272 assert_eq!(tree.root(), c);
273 assert_eq!(tree.immediate_dominator(a), Some(c));
274 assert_eq!(tree.immediate_dominator(b), Some(c));
275 assert_eq!(tree.immediate_dominator(c), None);
276 assert_eq!(tree.immediate_dominator(d), Some(c));
277 assert_eq!(tree.immediate_dominator(e), None);
278 }
279
280 #[test]
281 fn test_dominators_filtered() {
282 let mut graph = PortGraph::with_capacity(5, 10);
286 let a = graph.add_node(0, 2);
287 let b = graph.add_node(1, 1);
288 let c = graph.add_node(2, 1);
289 let d = graph.add_node(2, 2);
290 let e = graph.add_node(2, 0);
291 let f = graph.add_node(0, 1);
292
293 graph.link_nodes(a, 0, b, 0).unwrap();
294 graph.link_nodes(a, 1, d, 0).unwrap();
295 graph.link_nodes(b, 0, c, 0).unwrap();
296 graph.link_nodes(d, 0, c, 1).unwrap();
297 graph.link_nodes(c, 0, e, 0).unwrap();
298 graph.link_nodes(d, 1, e, 1).unwrap();
299 graph.link_nodes(f, 0, d, 1).unwrap();
300
301 let tree: DominatorTree = dominators_filtered(
303 &graph,
304 a,
305 Direction::Outgoing,
306 |node| node != f,
307 |_, p| Some(p) != graph.input(e, 1),
308 );
309 assert_eq!(tree.root(), a);
310 assert_eq!(tree.immediate_dominator(a), None);
311 assert_eq!(tree.immediate_dominator(b), Some(a));
312 assert_eq!(tree.immediate_dominator(c), Some(a));
313 assert_eq!(tree.immediate_dominator(d), Some(a));
314 assert_eq!(tree.immediate_dominator(e), Some(c));
315 assert_eq!(tree.immediate_dominator(f), None);
316
317 let tree: DominatorTree = dominators(&graph, c, Direction::Incoming);
319 assert_eq!(tree.root(), c);
320 assert_eq!(tree.immediate_dominator(a), Some(c));
321 assert_eq!(tree.immediate_dominator(b), Some(c));
322 assert_eq!(tree.immediate_dominator(c), None);
323 assert_eq!(tree.immediate_dominator(d), Some(c));
324 assert_eq!(tree.immediate_dominator(e), None);
325 }
326
327 #[test]
328 fn test_dominators_complex() {
329 let mut graph = PortGraph::with_capacity(6, 18);
333 let entry = graph.add_node(0, 2);
334 let a = graph.add_node(1, 1);
335 let b = graph.add_node(1, 2);
336 let c = graph.add_node(2, 1);
337 let d = graph.add_node(3, 2);
338 let e = graph.add_node(2, 1);
339
340 graph.link_nodes(entry, 0, a, 0).unwrap();
341 graph.link_nodes(entry, 1, b, 0).unwrap();
342 graph.link_nodes(a, 0, c, 0).unwrap();
343 graph.link_nodes(b, 0, d, 0).unwrap();
344 graph.link_nodes(b, 1, e, 0).unwrap();
345 graph.link_nodes(c, 0, d, 1).unwrap();
346 graph.link_nodes(d, 0, c, 1).unwrap();
347 graph.link_nodes(d, 1, e, 1).unwrap();
348 graph.link_nodes(e, 0, d, 2).unwrap();
349
350 let dominators: DominatorTree = dominators(&graph, entry, Direction::Outgoing);
351
352 assert_eq!(dominators.root(), entry);
353 assert_eq!(dominators.immediate_dominator(entry), None);
354 assert_eq!(dominators.immediate_dominator(a), Some(entry));
355 assert_eq!(dominators.immediate_dominator(b), Some(entry));
356 assert_eq!(dominators.immediate_dominator(c), Some(entry));
357 assert_eq!(dominators.immediate_dominator(d), Some(entry));
358 assert_eq!(dominators.immediate_dominator(e), Some(entry));
359 }
360}