pub fn block_ordering_pass(func: &mut Function) {
    if func.blocks.len() < 2 {
        return;
    }
    fn visit_postorder(
        func: &Function,
        visited: &mut HashSet<Word>,
        postorder: &mut Vec<Word>,
        current: Word,
    ) {
        if !visited.insert(current) {
            return;
        }
        let current_block = func
            .blocks
            .iter()
            .find(|b| b.label_id().unwrap() == current)
            .unwrap();
        let mut edges = outgoing_edges(current_block);
        // HACK(eddyb) treat `OpSelectionMerge` as an edge, in case it points
        // to an otherwise-unreachable block.
        if let Some(before_last_idx) = current_block.instructions.len().checked_sub(2) {
            if let Some(before_last) = current_block.instructions.get(before_last_idx) {
                if before_last.class.opcode == Op::SelectionMerge {
                    edges.push(before_last.operands[0].unwrap_id_ref());
                }
            }
        }
        // Reverse the order, so reverse-postorder keeps things tidy
        for &outgoing in edges.iter().rev() {
            visit_postorder(func, visited, postorder, outgoing);
        }
        postorder.push(current);
    }

    let mut visited = HashSet::new();
    let mut postorder = Vec::new();

    let entry_label = func.blocks[0].label_id().unwrap();
    visit_postorder(func, &mut visited, &mut postorder, entry_label);

    let mut old_blocks = replace(&mut func.blocks, Vec::new());
    // Order blocks according to reverse postorder
    for &block in postorder.iter().rev() {
        let index = old_blocks
            .iter()
            .position(|b| b.label_id().unwrap() == block)
            .unwrap();
        func.blocks.push(old_blocks.remove(index));
    }
    // Note: if old_blocks isn't empty here, that means there were unreachable blocks that were deleted.
    assert_eq!(func.blocks[0].label_id().unwrap(), entry_label);
}
/// spir-v requires basic blocks to be ordered so that if A dominates B, A appears before B (except
/// in the case of backedges). Reverse post-order is a good ordering that satisfies this condition
/// (with an "already visited set" that blocks going deeper, which solves both the fact that it's a
/// DAG, not a tree, as well as backedges).
spir-v requires basic blocks to be ordered so that if A dominates B, A appears before B (except
in the case of backedges). Reverse post-order is a good ordering that satisfies this condition
(with an "already visited set" that blocks going deeper, which solves both the fact that it's a
DAG, not a tree, as well as backedges).
spir - v requires basic blocks to be ordered so that if A dominates B A appears before B ( except in the case of backedges ) . Reverse post - order is a good ordering that satisfies this condition ( with an " already visited set " that blocks going deeper which solves both the fact that it ' s a DAG not a tree as well as backedges ) .
pub fn block_ordering_pass(func: &mut Function) {
    if func.blocks.len() < 2 {
        return;
    }
    fn visit_postorder(
        func: &Function,
        visited: &mut HashSet<Word>,
        postorder: &mut Vec<Word>,
        current: Word,
    ) {
        if !visited.insert(current) {
            return;
        }
        let current_block = func
            .blocks
            .iter()
            .find(|b| b.label_id().unwrap() == current)
            .unwrap();
        let mut edges = outgoing_edges(current_block);
        // HACK(eddyb) treat `OpSelectionMerge` as an edge, in case it points
        // to an otherwise-unreachable block.
        if let Some(before_last_idx) = current_block.instructions.len().checked_sub(2) {
            if let Some(before_last) = current_block.instructions.get(before_last_idx) {
                if before_last.class.opcode == Op::SelectionMerge {
                    edges.push(before_last.operands[0].unwrap_id_ref());
                }
            }
        }
        // Reverse the order, so reverse-postorder keeps things tidy
        for &outgoing in edges.iter().rev() {
            visit_postorder(func, visited, postorder, outgoing);
        }
        postorder.push(current);
    }
    let mut visited = HashSet::new();
    let mut postorder = Vec::new();
    let entry_label = func.blocks[0].label_id().unwrap();
    visit_postorder(func, &mut visited, &mut postorder, entry_label);
    let mut old_blocks = replace(&mut func.blocks, Vec::new());
    // Order blocks according to reverse postorder
    for &block in postorder.iter().rev() {
        let index = old_blocks
            .iter()
            .position(|b| b.label_id().unwrap() == block)
            .unwrap();
        func.blocks.push(old_blocks.remove(index));
    }
    // Note: if old_blocks isn't empty here, that means there were unreachable blocks that were deleted.
    assert_eq!(func.blocks[0].label_id().unwrap(), entry_label);
}
pub fn block_ordering_pass ( func : & mut Function ) { if func . blocks . len ( ) < 2 { return ; } fn visit_postorder ( func : & Function , visited : & mut HashSet < Word > , postorder : & mut Vec < Word > , current : Word , ) { if ! visited . insert ( current ) { return ; } let current_block = func . blocks . iter ( ) . find ( | b | b . label_id ( ) . unwrap ( ) == current ) . unwrap ( ) ; let mut edges = outgoing_edges ( current_block ) ; // HACK(eddyb) treat `OpSelectionMerge` as an edge, in case it points // to an otherwise-unreachable block. if let Some ( before_last_idx ) = current_block . instructions . len ( ) . checked_sub ( 2 ) { if let Some ( before_last ) = current_block . instructions . get ( before_last_idx ) { if before_last . class . opcode == Op :: SelectionMerge { edges . push ( before_last . operands [ 0 ] . unwrap_id_ref ( ) ) ; } } } // Reverse the order, so reverse-postorder keeps things tidy for & outgoing in edges . iter ( ) . rev ( ) { visit_postorder ( func , visited , postorder , outgoing ) ; } postorder . push ( current ) ; } let mut visited = HashSet :: new ( ) ; let mut postorder = Vec :: new ( ) ; let entry_label = func . blocks [ 0 ] . label_id ( ) . unwrap ( ) ; visit_postorder ( func , & mut visited , & mut postorder , entry_label ) ; let mut old_blocks = replace ( & mut func . blocks , Vec :: new ( ) ) ; // Order blocks according to reverse postorder for & block in postorder . iter ( ) . rev ( ) { let index = old_blocks . iter ( ) . position ( | b | b . label_id ( ) . unwrap ( ) == block ) . unwrap ( ) ; func . blocks . push ( old_blocks . remove ( index ) ) ; } // Note: if old_blocks isn't empty here, that means there were unreachable blocks that were deleted. assert_eq ! ( func blocks [ 0 ] label_id ( ) unwrap ( ) entry_label ) ; }
spir-v requires basic blocks to be ordered so that if A dominates B, A appears before B (except
in the case of backedges).
spir - v requires basic blocks to be ordered so that if A dominates B A appears before B ( except in the case of backedges ) .
func
&mut Function
func
&mut Function