1use crate::{
5 graph::{iter::EdgesWalker, Edge, Edges, Node, Nodes},
6 map::{IntKeyMap, Map},
7 FrozenGraph,
8};
9use alloc::vec;
10use core::fmt::Debug;
11
12pub trait WithImmDom {
14 type Ty: Copy + Eq + Debug + 'static;
16
17 fn imm_dom(&self) -> Option<Self::Ty>;
19
20 fn set_imm_dom(&mut self, dom: Self::Ty);
22}
23
24fn calc_imm_dominators_impl<N, E, NI, EI, NM, EM>(
25 nodes: &mut Nodes<N, EI, NM>,
26 edges: &Edges<E, NI, EI, EM>,
27 node_index: NI,
28 entry_idx: NI,
29) where
30 N: WithImmDom<Ty = NI>,
31 NI: Copy + Eq + Debug + 'static,
32 EI: Copy + Eq + Debug + 'static,
33 NM: Map<Node<N, EI>, Key = NI>,
34 EM: IntKeyMap<Edge<E, NI, EI>, Key = EI>,
35{
36 let mut successors = nodes.walk_successors(node_index);
37
38 while let Some(successor_idx) = successors.walk_edges_next(edges) {
39 if successor_idx == entry_idx {
42 continue;
44 }
45
46 match nodes[successor_idx].weight().imm_dom() {
47 None => {
48 nodes[successor_idx].weight_mut().set_imm_dom(node_index);
51 calc_imm_dominators_impl(nodes, edges, successor_idx, entry_idx);
52 }
53 Some(dominator) => {
54 assert_ne!(dominator, node_index);
56
57 let mut left_idx = dominator;
64 let mut left_path = vec![dominator];
65 let mut right_idx = node_index;
66 let mut right_path = vec![node_index];
67 loop {
68 if let Some(left_dominator) = nodes[left_idx].weight_mut().imm_dom() {
72 if right_path.contains(&left_dominator) {
73 nodes[successor_idx]
74 .weight_mut()
75 .set_imm_dom(left_dominator);
76 break;
77 }
78 left_idx = left_dominator;
79 left_path.push(left_dominator);
80 }
81
82 if let Some(right_dominator) = nodes[right_idx].weight_mut().imm_dom() {
88 if right_dominator == successor_idx {
89 break;
91 } else if left_path.contains(&right_dominator) {
92 nodes[successor_idx]
93 .weight_mut()
94 .set_imm_dom(right_dominator);
95 break;
96 }
97 right_idx = right_dominator;
98 right_path.push(right_dominator);
99 }
100 }
101 }
102 }
103 }
104}
105
106pub fn calc_imm_dominators<N, E, NI, EI, NM, EM>(
110 graph: &mut FrozenGraph<N, E, NI, EI, NM, EM>,
111 entry_index: NI,
112) where
113 N: WithImmDom<Ty = NI>,
114 NI: Copy + Eq + Debug + 'static,
115 EI: Copy + Eq + Debug + 'static,
116 NM: Map<Node<N, EI>, Key = NI>,
117 EM: IntKeyMap<Edge<E, NI, EI>, Key = EI>,
118{
119 let (nodes, edges) = graph.as_nodes_mut_and_edges();
120 calc_imm_dominators_impl(nodes, edges, entry_index, entry_index)
121}
122
123#[cfg(all(test, feature = "slotmap"))]
124mod tests {
125 use super::*;
126 use crate::{aliases::SlotMapGraph, map::slotmap::NodeIndex};
127
128 struct TestNode(Option<NodeIndex>);
129
130 impl Default for TestNode {
131 fn default() -> Self {
132 TestNode(None)
133 }
134 }
135
136 impl WithImmDom for TestNode {
137 type Ty = NodeIndex;
138
139 fn imm_dom(&self) -> Option<Self::Ty> {
140 self.0
141 }
142
143 fn set_imm_dom(&mut self, dom: Self::Ty) {
144 self.0 = Some(dom);
145 }
146 }
147
148 #[test]
149 fn test_imm_dom_simple_diamond() {
150 let mut graph = SlotMapGraph::<TestNode, ()>::with_capacities(4, 4);
151 let entry_idx = graph.add_default_node();
152 let left_idx = graph.add_default_node();
153 let right_idx = graph.add_default_node();
154 let end_idx = graph.add_default_node();
155
156 graph.add_edge((), entry_idx, left_idx).unwrap();
157 graph.add_edge((), entry_idx, right_idx).unwrap();
158 graph.add_edge((), left_idx, end_idx).unwrap();
159 graph.add_edge((), right_idx, end_idx).unwrap();
160
161 calc_imm_dominators(&mut graph, entry_idx);
162
163 assert_eq!(graph.node_weight(entry_idx).unwrap().imm_dom(), None);
164 assert_eq!(
165 graph.node_weight(left_idx).unwrap().imm_dom(),
166 Some(entry_idx)
167 );
168 assert_eq!(
169 graph.node_weight(right_idx).unwrap().imm_dom(),
170 Some(entry_idx)
171 );
172 assert_eq!(
173 graph.node_weight(end_idx).unwrap().imm_dom(),
174 Some(entry_idx)
175 );
176 }
177
178 #[test]
179 fn test_imm_dom_simple_loop() {
180 let mut graph = SlotMapGraph::<TestNode, ()>::with_capacities(5, 5);
181 let entry_idx = graph.add_default_node();
182 let loop_entry_idx = graph.add_default_node();
183 let loop_body_idx = graph.add_default_node();
184 let loop_exit_idx = graph.add_default_node();
185 let end_idx = graph.add_default_node();
186
187 graph.add_edge((), entry_idx, loop_entry_idx).unwrap();
188 graph.add_edge((), loop_entry_idx, loop_body_idx).unwrap();
189 graph.add_edge((), loop_body_idx, loop_exit_idx).unwrap();
190 graph.add_edge((), loop_exit_idx, loop_entry_idx).unwrap();
191 graph.add_edge((), loop_entry_idx, end_idx).unwrap();
192
193 calc_imm_dominators(&mut graph, entry_idx);
194
195 assert_eq!(graph.node_weight(entry_idx).unwrap().imm_dom(), None);
196 assert_eq!(
197 graph.node_weight(loop_entry_idx).unwrap().imm_dom(),
198 Some(entry_idx)
199 );
200 assert_eq!(
201 graph.node_weight(loop_body_idx).unwrap().imm_dom(),
202 Some(loop_entry_idx)
203 );
204 assert_eq!(
205 graph.node_weight(loop_exit_idx).unwrap().imm_dom(),
206 Some(loop_body_idx)
207 );
208 assert_eq!(
209 graph.node_weight(end_idx).unwrap().imm_dom(),
210 Some(loop_entry_idx)
211 );
212 }
213
214 #[test]
215 fn test_imm_dom_nested_loop() {
216 let mut graph = SlotMapGraph::<TestNode, ()>::with_capacities(9, 10);
217 let entry_idx = graph.add_default_node();
218 let outer_loop_entry_idx = graph.add_default_node();
219 let outer_loop_start_idx = graph.add_default_node();
220 let inner_loop_entry_idx = graph.add_default_node();
221 let inner_loop_body_idx = graph.add_default_node();
222 let inner_loop_exit_idx = graph.add_default_node();
223 let outer_loop_end_idx = graph.add_default_node();
224 let outer_loop_exit_idx = graph.add_default_node();
225 let end_idx = graph.add_default_node();
226
227 graph.add_edge((), entry_idx, outer_loop_entry_idx).unwrap();
228 graph
229 .add_edge((), outer_loop_entry_idx, outer_loop_start_idx)
230 .unwrap();
231 graph.add_edge((), outer_loop_entry_idx, end_idx).unwrap();
232 graph
233 .add_edge((), outer_loop_start_idx, inner_loop_entry_idx)
234 .unwrap();
235 graph
236 .add_edge((), inner_loop_entry_idx, inner_loop_body_idx)
237 .unwrap();
238 graph
239 .add_edge((), inner_loop_entry_idx, outer_loop_end_idx)
240 .unwrap();
241 graph
242 .add_edge((), inner_loop_body_idx, inner_loop_exit_idx)
243 .unwrap();
244 graph
245 .add_edge((), inner_loop_exit_idx, inner_loop_entry_idx)
246 .unwrap();
247 graph
248 .add_edge((), outer_loop_end_idx, outer_loop_exit_idx)
249 .unwrap();
250 graph
251 .add_edge((), outer_loop_exit_idx, outer_loop_entry_idx)
252 .unwrap();
253
254 calc_imm_dominators(&mut graph, entry_idx);
255
256 assert_eq!(graph.node_weight(entry_idx).unwrap().imm_dom(), None);
257 assert_eq!(
258 graph.node_weight(outer_loop_entry_idx).unwrap().imm_dom(),
259 Some(entry_idx)
260 );
261 assert_eq!(
262 graph.node_weight(outer_loop_start_idx).unwrap().imm_dom(),
263 Some(outer_loop_entry_idx)
264 );
265 assert_eq!(
266 graph.node_weight(inner_loop_entry_idx).unwrap().imm_dom(),
267 Some(outer_loop_start_idx)
268 );
269 assert_eq!(
270 graph.node_weight(inner_loop_body_idx).unwrap().imm_dom(),
271 Some(inner_loop_entry_idx)
272 );
273 assert_eq!(
274 graph.node_weight(inner_loop_exit_idx).unwrap().imm_dom(),
275 Some(inner_loop_body_idx)
276 );
277 assert_eq!(
278 graph.node_weight(outer_loop_end_idx).unwrap().imm_dom(),
279 Some(inner_loop_entry_idx)
280 );
281 assert_eq!(
282 graph.node_weight(outer_loop_exit_idx).unwrap().imm_dom(),
283 Some(outer_loop_end_idx)
284 );
285 assert_eq!(
286 graph.node_weight(end_idx).unwrap().imm_dom(),
287 Some(outer_loop_entry_idx)
288 );
289 }
290}