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