• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright © 2023 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3 
4 use crate::bitset::BitSet;
5 
6 use std::collections::HashMap;
7 use std::hash::Hash;
8 use std::ops::{Deref, DerefMut, Index, IndexMut};
9 use std::slice;
10 
11 pub struct CFGNode<N> {
12     node: N,
13     dom: usize,
14     dom_pre_idx: usize,
15     dom_post_idx: usize,
16     lph: usize,
17     pred: Vec<usize>,
18     succ: Vec<usize>,
19 }
20 
21 impl<N> Deref for CFGNode<N> {
22     type Target = N;
23 
deref(&self) -> &N24     fn deref(&self) -> &N {
25         &self.node
26     }
27 }
28 
29 impl<N> DerefMut for CFGNode<N> {
deref_mut(&mut self) -> &mut N30     fn deref_mut(&mut self) -> &mut N {
31         &mut self.node
32     }
33 }
34 
graph_post_dfs<N>( nodes: &Vec<CFGNode<N>>, id: usize, seen: &mut BitSet, post_idx: &mut Vec<usize>, count: &mut usize, )35 fn graph_post_dfs<N>(
36     nodes: &Vec<CFGNode<N>>,
37     id: usize,
38     seen: &mut BitSet,
39     post_idx: &mut Vec<usize>,
40     count: &mut usize,
41 ) {
42     if seen.get(id) {
43         return;
44     }
45     seen.insert(id);
46 
47     // Reverse the order of the successors so that any successors which are
48     // forward edges get descending indices.  This ensures that, in the reverse
49     // post order, successors (and their dominated children) come in-order.
50     // In particular, as long as fall-through edges are only ever used for
51     // forward edges and the fall-through edge comes first, we guarantee that
52     // the fallthrough block comes immediately after its predecessor.
53     for s in nodes[id].succ.iter().rev() {
54         graph_post_dfs(nodes, *s, seen, post_idx, count);
55     }
56 
57     post_idx[id] = *count;
58     *count += 1;
59 }
60 
rev_post_order_sort<N>(nodes: &mut Vec<CFGNode<N>>)61 fn rev_post_order_sort<N>(nodes: &mut Vec<CFGNode<N>>) {
62     let mut seen = BitSet::new();
63     let mut post_idx = Vec::new();
64     post_idx.resize(nodes.len(), usize::MAX);
65     let mut count = 0;
66 
67     graph_post_dfs(nodes, 0, &mut seen, &mut post_idx, &mut count);
68 
69     assert!(count <= nodes.len());
70 
71     let remap_idx = |i: usize| {
72         let pid = post_idx[i];
73         if pid == usize::MAX {
74             None
75         } else {
76             assert!(pid < count);
77             Some((count - 1) - pid)
78         }
79     };
80     assert!(remap_idx(0) == Some(0));
81 
82     // Re-map edges to use post-index numbering
83     for n in nodes.iter_mut() {
84         let remap_filter_idx = |i: &mut usize| {
85             if let Some(r) = remap_idx(*i) {
86                 *i = r;
87                 true
88             } else {
89                 false
90             }
91         };
92         n.pred.retain_mut(remap_filter_idx);
93         n.succ.retain_mut(remap_filter_idx);
94     }
95 
96     // We know a priori that each non-MAX post_idx is unique so we can sort the
97     // nodes by inserting them into a new array by index.
98     let mut sorted: Vec<CFGNode<N>> = Vec::with_capacity(count);
99     for (i, n) in nodes.drain(..).enumerate() {
100         if let Some(r) = remap_idx(i) {
101             unsafe { sorted.as_mut_ptr().add(r).write(n) };
102         }
103     }
104     unsafe { sorted.set_len(count) };
105 
106     std::mem::swap(nodes, &mut sorted);
107 }
108 
find_common_dom<N>( nodes: &Vec<CFGNode<N>>, mut a: usize, mut b: usize, ) -> usize109 fn find_common_dom<N>(
110     nodes: &Vec<CFGNode<N>>,
111     mut a: usize,
112     mut b: usize,
113 ) -> usize {
114     while a != b {
115         while a > b {
116             a = nodes[a].dom;
117         }
118         while b > a {
119             b = nodes[b].dom;
120         }
121     }
122     a
123 }
124 
dom_idx_dfs<N>( nodes: &mut Vec<CFGNode<N>>, dom_children: &Vec<Vec<usize>>, id: usize, count: &mut usize, )125 fn dom_idx_dfs<N>(
126     nodes: &mut Vec<CFGNode<N>>,
127     dom_children: &Vec<Vec<usize>>,
128     id: usize,
129     count: &mut usize,
130 ) {
131     nodes[id].dom_pre_idx = *count;
132     *count += 1;
133 
134     for c in dom_children[id].iter() {
135         dom_idx_dfs(nodes, dom_children, *c, count);
136     }
137 
138     nodes[id].dom_post_idx = *count;
139     *count += 1;
140 }
141 
calc_dominance<N>(nodes: &mut Vec<CFGNode<N>>)142 fn calc_dominance<N>(nodes: &mut Vec<CFGNode<N>>) {
143     nodes[0].dom = 0;
144     loop {
145         let mut changed = false;
146         for i in 1..nodes.len() {
147             let mut dom = nodes[i].pred[0];
148             for p in &nodes[i].pred[1..] {
149                 if nodes[*p].dom != usize::MAX {
150                     dom = find_common_dom(nodes, dom, *p);
151                 }
152             }
153             assert!(dom != usize::MAX);
154             if nodes[i].dom != dom {
155                 nodes[i].dom = dom;
156                 changed = true;
157             }
158         }
159 
160         if !changed {
161             break;
162         }
163     }
164 
165     let mut dom_children = Vec::new();
166     dom_children.resize(nodes.len(), Vec::new());
167 
168     for i in 1..nodes.len() {
169         let p = nodes[i].dom;
170         if p != i {
171             dom_children[p].push(i);
172         }
173     }
174 
175     let mut count = 0_usize;
176     dom_idx_dfs(nodes, &dom_children, 0, &mut count);
177     debug_assert!(count == nodes.len() * 2);
178 }
179 
loop_detect_dfs<N>( nodes: &Vec<CFGNode<N>>, id: usize, pre: &mut BitSet, post: &mut BitSet, loops: &mut BitSet, )180 fn loop_detect_dfs<N>(
181     nodes: &Vec<CFGNode<N>>,
182     id: usize,
183     pre: &mut BitSet,
184     post: &mut BitSet,
185     loops: &mut BitSet,
186 ) {
187     if pre.get(id) {
188         if !post.get(id) {
189             loops.insert(id);
190         }
191         return;
192     }
193 
194     pre.insert(id);
195 
196     for s in nodes[id].succ.iter() {
197         loop_detect_dfs(nodes, *s, pre, post, loops);
198     }
199 
200     post.insert(id);
201 }
202 
detect_loops<N>(nodes: &mut Vec<CFGNode<N>>) -> bool203 fn detect_loops<N>(nodes: &mut Vec<CFGNode<N>>) -> bool {
204     let mut dfs_pre = BitSet::new();
205     let mut dfs_post = BitSet::new();
206     let mut loops = BitSet::new();
207     loop_detect_dfs(nodes, 0, &mut dfs_pre, &mut dfs_post, &mut loops);
208 
209     let mut has_loop = false;
210     nodes[0].lph = usize::MAX;
211     for i in 1..nodes.len() {
212         if loops.get(i) {
213             // This is a loop header
214             nodes[i].lph = i;
215             has_loop = true;
216         } else {
217             // Otherwise, we have the same loop header as our dominator
218             let dom = nodes[i].dom;
219             let dom_lph = nodes[dom].lph;
220             nodes[i].lph = dom_lph;
221         }
222     }
223 
224     has_loop
225 }
226 
227 pub struct CFG<N> {
228     has_loop: bool,
229     nodes: Vec<CFGNode<N>>,
230 }
231 
232 impl<N> CFG<N> {
from_blocks_edges( nodes: impl IntoIterator<Item = N>, edges: impl IntoIterator<Item = (usize, usize)>, ) -> Self233     pub fn from_blocks_edges(
234         nodes: impl IntoIterator<Item = N>,
235         edges: impl IntoIterator<Item = (usize, usize)>,
236     ) -> Self {
237         let mut nodes = Vec::from_iter(nodes.into_iter().map(|n| CFGNode {
238             node: n,
239             dom: usize::MAX,
240             dom_pre_idx: usize::MAX,
241             dom_post_idx: 0,
242             lph: usize::MAX,
243             pred: Vec::new(),
244             succ: Vec::new(),
245         }));
246 
247         for (p, s) in edges {
248             nodes[s].pred.push(p);
249             nodes[p].succ.push(s);
250         }
251 
252         rev_post_order_sort(&mut nodes);
253         calc_dominance(&mut nodes);
254         let has_loop = detect_loops(&mut nodes);
255 
256         CFG {
257             has_loop: has_loop,
258             nodes: nodes,
259         }
260     }
261 
get(&self, idx: usize) -> Option<&N>262     pub fn get(&self, idx: usize) -> Option<&N> {
263         self.nodes.get(idx).map(|n| &n.node)
264     }
265 
get_mut(&mut self, idx: usize) -> Option<&mut N>266     pub fn get_mut(&mut self, idx: usize) -> Option<&mut N> {
267         self.nodes.get_mut(idx).map(|n| &mut n.node)
268     }
269 
iter(&self) -> slice::Iter<CFGNode<N>>270     pub fn iter(&self) -> slice::Iter<CFGNode<N>> {
271         self.nodes.iter()
272     }
273 
iter_mut(&mut self) -> slice::IterMut<CFGNode<N>>274     pub fn iter_mut(&mut self) -> slice::IterMut<CFGNode<N>> {
275         self.nodes.iter_mut()
276     }
277 
len(&self) -> usize278     pub fn len(&self) -> usize {
279         self.nodes.len()
280     }
281 
dom_dfs_pre_index(&self, idx: usize) -> usize282     pub fn dom_dfs_pre_index(&self, idx: usize) -> usize {
283         self.nodes[idx].dom_pre_idx
284     }
285 
dom_dfs_post_index(&self, idx: usize) -> usize286     pub fn dom_dfs_post_index(&self, idx: usize) -> usize {
287         self.nodes[idx].dom_post_idx
288     }
289 
dom_parent_index(&self, idx: usize) -> Option<usize>290     pub fn dom_parent_index(&self, idx: usize) -> Option<usize> {
291         if idx == 0 {
292             None
293         } else {
294             Some(self.nodes[idx].dom)
295         }
296     }
297 
dominates(&self, parent: usize, child: usize) -> bool298     pub fn dominates(&self, parent: usize, child: usize) -> bool {
299         // If a block is unreachable, then dom_pre_idx == usize::MAX and
300         // dom_post_idx == 0.  This allows us to trivially handle unreachable
301         // blocks here with zero extra work.
302         self.dom_dfs_pre_index(child) >= self.dom_dfs_pre_index(parent)
303             && self.dom_dfs_post_index(child) <= self.dom_dfs_post_index(parent)
304     }
305 
has_loop(&self) -> bool306     pub fn has_loop(&self) -> bool {
307         self.has_loop
308     }
309 
is_loop_header(&self, idx: usize) -> bool310     pub fn is_loop_header(&self, idx: usize) -> bool {
311         self.nodes[idx].lph == idx
312     }
313 
loop_header_index(&self, idx: usize) -> Option<usize>314     pub fn loop_header_index(&self, idx: usize) -> Option<usize> {
315         let lph = self.nodes[idx].lph;
316         if lph == usize::MAX {
317             None
318         } else {
319             debug_assert!(self.is_loop_header(lph));
320             Some(lph)
321         }
322     }
323 
succ_indices(&self, idx: usize) -> &[usize]324     pub fn succ_indices(&self, idx: usize) -> &[usize] {
325         &self.nodes[idx].succ[..]
326     }
327 
pred_indices(&self, idx: usize) -> &[usize]328     pub fn pred_indices(&self, idx: usize) -> &[usize] {
329         &self.nodes[idx].pred[..]
330     }
331 
drain(&mut self) -> impl Iterator<Item = N> + '_332     pub fn drain(&mut self) -> impl Iterator<Item = N> + '_ {
333         self.has_loop = false;
334         self.nodes.drain(..).map(|n| n.node)
335     }
336 }
337 
338 impl<N> Index<usize> for CFG<N> {
339     type Output = N;
340 
index(&self, idx: usize) -> &N341     fn index(&self, idx: usize) -> &N {
342         &self.nodes[idx].node
343     }
344 }
345 
346 impl<N> IndexMut<usize> for CFG<N> {
index_mut(&mut self, idx: usize) -> &mut N347     fn index_mut(&mut self, idx: usize) -> &mut N {
348         &mut self.nodes[idx].node
349     }
350 }
351 
352 impl<'a, N> IntoIterator for &'a CFG<N> {
353     type Item = &'a CFGNode<N>;
354     type IntoIter = slice::Iter<'a, CFGNode<N>>;
355 
into_iter(self) -> slice::Iter<'a, CFGNode<N>>356     fn into_iter(self) -> slice::Iter<'a, CFGNode<N>> {
357         self.iter()
358     }
359 }
360 
361 impl<'a, N> IntoIterator for &'a mut CFG<N> {
362     type Item = &'a mut CFGNode<N>;
363     type IntoIter = slice::IterMut<'a, CFGNode<N>>;
364 
into_iter(self) -> slice::IterMut<'a, CFGNode<N>>365     fn into_iter(self) -> slice::IterMut<'a, CFGNode<N>> {
366         self.iter_mut()
367     }
368 }
369 
370 pub struct CFGBuilder<K, N> {
371     nodes: Vec<N>,
372     edges: Vec<(K, K)>,
373     key_map: HashMap<K, usize>,
374 }
375 
376 impl<K, N> CFGBuilder<K, N> {
new() -> CFGBuilder<K, N>377     pub fn new() -> CFGBuilder<K, N> {
378         CFGBuilder {
379             nodes: Vec::new(),
380             edges: Vec::new(),
381             key_map: HashMap::new(),
382         }
383     }
384 }
385 
386 impl<K: Eq + Hash, N> CFGBuilder<K, N> {
add_node(&mut self, k: K, n: N)387     pub fn add_node(&mut self, k: K, n: N) {
388         self.key_map.insert(k, self.nodes.len());
389         self.nodes.push(n);
390     }
391 
add_edge(&mut self, s: K, p: K)392     pub fn add_edge(&mut self, s: K, p: K) {
393         self.edges.push((s, p));
394     }
395 
as_cfg(mut self) -> CFG<N>396     pub fn as_cfg(mut self) -> CFG<N> {
397         let edges = self.edges.drain(..).map(|(s, p)| {
398             let s = *self.key_map.get(&s).unwrap();
399             let p = *self.key_map.get(&p).unwrap();
400             (s, p)
401         });
402         CFG::from_blocks_edges(self.nodes, edges)
403     }
404 }
405 
406 impl<K, N> Default for CFGBuilder<K, N> {
default() -> Self407     fn default() -> Self {
408         CFGBuilder::new()
409     }
410 }
411