weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
use super::bitmask::try_set_bit;
use super::ExplodedDecodeError;
use vyre_primitives::graph::exploded::decode_node;

/// Convert reached exploded-supergraph node ids into a statement-id
/// reachability bitmask suitable for [`extract_path`].
///
/// `encoded_nodes` are packed `(proc, block, fact)` ids, such as the
/// values returned by the explicit CPU oracle or the encoded form of
/// a GPU fixpoint result. `block_to_statement` is flattened by
/// `proc_id * blocks_per_proc + block_id` and maps each basic block to
/// the statement node used by the proof CSR. `fact_filter` restricts
/// conversion to one IFDS fact when the caller is building a
/// per-source/per-fact witness mask.
pub fn exploded_reachability_to_statement_mask(
    encoded_nodes: &[u32],
    blocks_per_proc: u32,
    block_to_statement: &[u32],
    fact_filter: Option<u32>,
    statement_count: u32,
) -> Result<Vec<u32>, ExplodedDecodeError> {
    if blocks_per_proc == 0 {
        return Err(ExplodedDecodeError::InvalidShape);
    }
    let slot_count = u32::try_from(block_to_statement.len()).map_err(|_| {
        ExplodedDecodeError::BlockOutOfBounds {
            proc_id: u32::MAX,
            block_id: u32::MAX,
            slot: u32::MAX,
            slot_count: u32::MAX,
        }
    })?;
    let mut mask = vec![
        0u32;
        crate::dispatch_decode::bitset_word_capacity(
            "reachability witness statement mask",
            statement_count,
        )
        .map_err(|_| ExplodedDecodeError::InvalidShape)?
    ];
    for &node in encoded_nodes {
        let (proc_id, block_id, fact_id) = decode_node(node);
        if fact_filter.is_some_and(|wanted| wanted != fact_id) {
            continue;
        }
        let slot = proc_id
            .checked_mul(blocks_per_proc)
            .and_then(|base| base.checked_add(block_id))
            .ok_or(ExplodedDecodeError::BlockOutOfBounds {
                proc_id,
                block_id,
                slot: u32::MAX,
                slot_count,
            })?;
        let slot_index = crate::dispatch_decode::u32_to_usize(
            slot,
            "reachability witness block-to-statement slot",
        )
        .map_err(|_| ExplodedDecodeError::BlockOutOfBounds {
            proc_id,
            block_id,
            slot,
            slot_count,
        })?;
        let Some(&statement) = block_to_statement.get(slot_index) else {
            return Err(ExplodedDecodeError::BlockOutOfBounds {
                proc_id,
                block_id,
                slot,
                slot_count,
            });
        };
        if statement >= statement_count {
            return Err(ExplodedDecodeError::StatementOutOfBounds {
                statement,
                statement_count,
            });
        }
        try_set_bit(&mut mask, statement).map_err(|_| {
            ExplodedDecodeError::StatementOutOfBounds {
                statement,
                statement_count,
            }
        })?;
    }
    Ok(mask)
}