use crate::spirv_module::Block;
use crate::spirv_module::Operand;
use spirv::{Op, Word};
use std::collections::{HashMap, HashSet};
pub(in crate::passes) fn block_successors(block: &Block) -> Vec<Word> {
fn id_ref(operand: &Operand) -> Option<Word> {
match operand {
Operand::IdRef(id) => Some(*id),
_ => None,
}
}
let Some(inst) = block.instructions.last() else {
return Vec::new();
};
match inst.class.opcode {
Op::Branch => inst.operands.first().and_then(id_ref).into_iter().collect(),
Op::BranchConditional => inst
.operands
.iter()
.skip(1)
.take(2)
.filter_map(id_ref)
.collect(),
Op::Switch => {
let mut out = Vec::new();
if let Some(default) = inst.operands.get(1).and_then(id_ref) {
out.push(default);
}
let mut idx = 3;
while idx < inst.operands.len() {
if let Some(target) = inst.operands.get(idx).and_then(id_ref) {
out.push(target);
}
idx += 2;
}
out.sort_unstable();
out.dedup();
out
}
_ => Vec::new(),
}
}
pub(in crate::passes) fn block_successors_by_label(blocks: &[Block]) -> HashMap<Word, Vec<Word>> {
blocks
.iter()
.filter_map(|block| Some((block.label.as_ref()?.result_id?, block_successors(block))))
.collect()
}
pub(in crate::passes) fn label_dominates(
dominators: &HashMap<Word, HashSet<Word>>,
dominator: Word,
label: Word,
) -> bool {
dominators
.get(&label)
.is_some_and(|labels| labels.contains(&dominator))
}