nak: Add a dominance check to CFG

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand
2023-08-24 13:47:27 -05:00
committed by Marge Bot
parent bef6c1095e
commit 2f9565e725
+52
View File
@@ -13,6 +13,8 @@ use std::slice;
pub struct CFGNode<N> {
node: N,
dom: usize,
dom_pre_idx: usize,
dom_post_idx: usize,
lph: usize,
pred: Vec<usize>,
succ: Vec<usize>,
@@ -124,6 +126,23 @@ fn find_common_dom<N>(
a
}
fn dom_idx_dfs<N>(
nodes: &mut Vec<CFGNode<N>>,
dom_children: &Vec<Vec<usize>>,
id: usize,
count: &mut usize,
) {
nodes[id].dom_pre_idx = *count;
*count += 1;
for c in dom_children[id].iter() {
dom_idx_dfs(nodes, dom_children, *c, count);
}
nodes[id].dom_post_idx = *count;
*count += 1;
}
fn calc_dominance<N>(nodes: &mut Vec<CFGNode<N>>) {
nodes[0].dom = 0;
loop {
@@ -146,6 +165,20 @@ fn calc_dominance<N>(nodes: &mut Vec<CFGNode<N>>) {
break;
}
}
let mut dom_children = Vec::new();
dom_children.resize(nodes.len(), Vec::new());
for i in 1..nodes.len() {
let p = nodes[i].dom;
if p != i {
dom_children[p].push(i);
}
}
let mut count = 0_usize;
dom_idx_dfs(nodes, &dom_children, 0, &mut count);
debug_assert!(count == nodes.len() * 2);
}
fn loop_detect_dfs<N>(
@@ -208,6 +241,8 @@ impl<N> CFG<N> {
let mut nodes = Vec::from_iter(nodes.into_iter().map(|n| CFGNode {
node: n,
dom: usize::MAX,
dom_pre_idx: usize::MAX,
dom_post_idx: 0,
lph: usize::MAX,
pred: Vec::new(),
succ: Vec::new(),
@@ -248,6 +283,14 @@ impl<N> CFG<N> {
self.nodes.len()
}
pub fn dom_dfs_pre_index(&self, idx: usize) -> usize {
self.nodes[idx].dom_pre_idx
}
pub fn dom_dfs_post_index(&self, idx: usize) -> usize {
self.nodes[idx].dom_post_idx
}
pub fn dom_parent_index(&self, idx: usize) -> Option<usize> {
if idx == 0 {
None
@@ -256,6 +299,15 @@ impl<N> CFG<N> {
}
}
pub fn dominates(&self, parent: usize, child: usize) -> bool {
/* If a block is unreachable, then dom_pre_idx == usize::MAX and
* dom_post_idx == 0. This allows us to trivially handle unreachable
* blocks here with zero extra work.
*/
self.dom_dfs_pre_index(child) >= self.dom_dfs_pre_index(parent)
&& self.dom_dfs_post_index(child) <= self.dom_dfs_post_index(parent)
}
pub fn has_loop(&self) -> bool {
self.has_loop
}