#[must_use]
#[cfg(any(test, feature = "cpu-parity"))]
pub fn cooper_harvey_kennedy_idoms(
node_count: u32,
entry: u32,
edges: &[(u32, u32)],
) -> Vec<Option<u32>> {
let n = node_count as usize;
let entry = entry as usize;
if n == 0 {
return Vec::new();
}
if entry >= n {
return vec![None; n];
}
let words = ((n + 31) / 32).max(1);
let last_mask = if n % 32 == 0 {
u32::MAX
} else {
(1u32 << (n % 32)) - 1
};
let mut succ: Vec<Vec<usize>> = vec![Vec::new(); n];
let mut pred: Vec<Vec<usize>> = vec![Vec::new(); n];
for &(u, v) in edges {
let u = u as usize;
let v = v as usize;
if u < n && v < n {
succ[u].push(v);
pred[v].push(u);
}
}
let mut dom = vec![0u32; n * words];
for v in 0..n {
let row = v * words;
if v == entry {
dom[row + v / 32] |= 1u32 << (v % 32);
} else {
for w in 0..words {
dom[row + w] = u32::MAX;
}
if last_mask != u32::MAX {
dom[row + words - 1] = last_mask;
}
dom[row + v / 32] |= 1u32 << (v % 32);
}
}
let mut changed = true;
while changed {
changed = false;
for v in 0..n {
if v == entry {
continue;
}
let row = v * words;
let mut new = vec![u32::MAX; words];
if last_mask != u32::MAX {
new[words - 1] = last_mask;
}
for &p in &pred[v] {
let prow = p * words;
for w in 0..words {
new[w] &= dom[prow + w];
}
}
new[v / 32] |= 1u32 << (v % 32);
if &new[..] != &dom[row..row + words] {
dom[row..row + words].copy_from_slice(&new);
changed = true;
}
}
}
let mut reachable = vec![false; n];
let mut queue = vec![entry];
reachable[entry] = true;
while let Some(u) = queue.pop() {
for &v in &succ[u] {
if !reachable[v] {
reachable[v] = true;
queue.push(v);
}
}
}
let mut idom = vec![None; n];
idom[entry] = Some(entry as u32);
for v in 0..n {
if v == entry || !reachable[v] {
continue;
}
let row = v * words;
let mut strict = Vec::new();
for d in 0..n {
if d == v {
continue;
}
if dom[row + d / 32] & (1u32 << (d % 32)) != 0 {
strict.push(d);
}
}
for &d in &strict {
let mut is_idom = true;
for &c in &strict {
if c == d {
continue;
}
if dom[c * words + d / 32] & (1u32 << (d % 32)) != 0 {
is_idom = false;
break;
}
}
if is_idom {
idom[v] = Some(d as u32);
break;
}
}
}
idom
}