weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
use super::*;

#[test]
fn fixed_point_batch_reuses_scratch_between_analyses() {
    let second_analysis_saw_existing_output_slot = std::cell::Cell::new(false);
    let phase = std::cell::Cell::new(0_u32);
    let dispatch = |_: &vyre::ir::Program,
                    inputs: &[&[u8]],
                    _: Option<[u32; 3]>,
                    outputs: &mut Vec<Vec<u8>>| {
        if inputs.len() < 6 {
            return crate::fixed_point_closure::fallback_bitset_equal_dispatch(inputs, outputs);
        }
        if phase.get() == 1 && outputs.len() == 1 {
            second_analysis_saw_existing_output_slot.set(true);
        }
        let frontier = u32::from_le_bytes(inputs[5][..4].try_into().unwrap());
        let next = frontier | 0b11;
        if outputs.is_empty() {
            outputs.push(Vec::new());
        }
        outputs[0].clear();
        outputs[0].extend_from_slice(&next.to_le_bytes());
        Ok(())
    };
    let graph = CsrGraph::new(
        2,
        &[0, 1, 1],
        &[1],
        &[vyre_primitives::predicate::edge_kind::CONTROL],
    );
    let mut batch = FixedPointBatch::new(&dispatch);
    let mut reaching_into = Vec::with_capacity(1);
    let reaching_into_ptr = reaching_into.as_ptr();

    let reaching = batch
        .reaching(graph, &[0b01], 4)
        .expect("batch reaching must converge");
    batch
        .reaching_into(graph, &[0b01], 4, &mut reaching_into)
        .expect("batch reaching_into must converge into caller storage");
    assert_eq!(reaching, vec![0b11]);
    assert_eq!(reaching_into, vec![0b11]);
    assert_eq!(
        reaching_into.as_ptr(),
        reaching_into_ptr,
        "reaching_into must reuse caller result allocation"
    );
    assert_eq!(batch.scratch().output_slot_count(), 1);

    phase.set(1);
    let mut live_into = Vec::with_capacity(1);
    let live_into_ptr = live_into.as_ptr();
    let live = batch
        .live(graph, &[0b10], 4)
        .expect("batch live must converge");
    batch
        .live_into(graph, &[0b10], 4, &mut live_into)
        .expect("batch live_into must converge into caller storage");
    assert_eq!(live, vec![0b11]);
    assert_eq!(live_into, vec![0b11]);
    assert_eq!(
        live_into.as_ptr(),
        live_into_ptr,
        "live_into must reuse caller result allocation"
    );
    let prepared = batch
        .prepare_reaching(graph)
        .expect("prepared graph should support execution planning");
    let plan = batch
        .execution_plan_for_prepared_graph(&prepared)
        .expect("fixed-point batch execution plan must fit host byte accounting");
    assert_eq!(plan.node_count, 2);
    assert_eq!(
        plan.execution_mode,
        crate::fixed_point_scratch::FrontierExecutionMode::Dense
    );
    assert!(second_analysis_saw_existing_output_slot.get());
}