weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
use crate::ifds_resident_types::{
    IfdsResidentDispatch, ResidentIfdsScratch, ResidentPreparedIfdsCsr,
};

/// Allocate reusable resident scratch buffers for IFDS solves.
pub fn allocate_resident_ifds_scratch<D>(
    dispatch: &D,
    prepared: &ResidentPreparedIfdsCsr<D::Resource>,
) -> Result<ResidentIfdsScratch<D::Resource>, String>
where
    D: IfdsResidentDispatch,
{
    allocate_resident_ifds_scratch_with_seed_capacity(dispatch, prepared, 1)
}

/// Allocate reusable resident scratch buffers for IFDS solves with an explicit
/// per-query seed fact staging capacity.
pub fn allocate_resident_ifds_scratch_with_seed_capacity<D>(
    dispatch: &D,
    prepared: &ResidentPreparedIfdsCsr<D::Resource>,
    max_seed_facts: usize,
) -> Result<ResidentIfdsScratch<D::Resource>, String>
where
    D: IfdsResidentDispatch,
{
    if max_seed_facts == 0 {
        return Err(
            "weir IFDS resident scratch seed capacity must be positive. Fix: allocate at least one staged seed fact or skip solving empty seed batches."
                .to_string(),
        );
    }
    let frontier_byte_len = prepared
        .words
        .checked_mul(std::mem::size_of::<u32>())
        .ok_or_else(|| {
            "weir IFDS resident scratch frontier byte length overflows usize. Fix: shard the IFDS problem before resident solving.".to_string()
        })?;
    let changed_byte_len = std::mem::size_of::<u32>();
    let retained_byte_len = frontier_byte_len
        .checked_add(changed_byte_len)
        .ok_or_else(|| {
            "weir IFDS resident scratch retained byte accounting overflows usize. Fix: shard the IFDS problem before resident solving.".to_string()
        })?;
    let frontier = dispatch
        .allocate_resident(frontier_byte_len)
        .map_err(|error| format!("weir IFDS resident allocate scratch frontier failed: {error}"))?;
    let changed = match dispatch.allocate_resident(changed_byte_len) {
        Ok(resource) => resource,
        Err(error) => {
            let _ = super::free_unique_resident_resources(dispatch, [("frontier", frontier)]);
            return Err(format!(
                "weir IFDS resident allocate scratch changed flag failed: {error}"
            ));
        }
    };
    Ok(ResidentIfdsScratch {
        words: prepared.words,
        max_seed_facts,
        frontier_byte_len,
        changed_byte_len,
        retained_byte_len,
        frontier,
        changed,
    })
}

/// Free reusable IFDS scratch buffers created by [`allocate_resident_ifds_scratch`].
pub fn free_resident_ifds_scratch<D>(
    dispatch: &D,
    scratch: ResidentIfdsScratch<D::Resource>,
) -> Result<(), String>
where
    D: IfdsResidentDispatch,
{
    let ResidentIfdsScratch {
        frontier, changed, ..
    } = scratch;
    super::free_unique_resident_resources(
        dispatch,
        [
            ("scratch frontier", frontier),
            ("scratch changed flag", changed),
        ],
    )
}