weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! `weir::reaching::reaching_defs_step`  -  Program construction
//! invariants.
//!
//! Op id: `weir::tests::df::reaching::construction`. Soundness:
//! `Exact`  -  the test asserts the exact buffer set, workgroup size,
//! and entry-region generator id of the returned Program. A
//! regression that drops a buffer or changes the generator marker
//! breaks this test immediately, before any downstream
//! GPU-dispatch test can mask the change.
//!
//! This is the lightweight construction-time gate. End-to-end
//! CPU+GPU parity over a 1000-input fuzz batch lives in a sibling
//! file once the dispatch substrate is wired.

use vyre::ir::BufferAccess;
use vyre_primitives::graph::program_graph::ProgramGraphShape;
use weir::reaching::reaching_defs_step;

#[test]
fn reaching_defs_step_emits_csr_forward_traverse_shape() {
    let shape = ProgramGraphShape::new(64, 64);
    let prog = reaching_defs_step(shape, "frontier_in", "frontier_out");

    let buffer_names: Vec<&str> = prog.buffers().iter().map(|b| b.name()).collect();
    // Exactly the buffers csr_forward_traverse emits  -  frontier_in
    // (read), frontier_out (write), plus the ProgramGraphShape's
    // CSR + tag inputs.
    assert!(
        buffer_names.contains(&"frontier_in"),
        "missing frontier_in buffer; got {:?}",
        buffer_names
    );
    assert!(
        buffer_names.contains(&"frontier_out"),
        "missing frontier_out buffer; got {:?}",
        buffer_names
    );

    let frontier_in = prog
        .buffers()
        .iter()
        .find(|b| b.name() == "frontier_in")
        .expect("frontier_in declared");
    assert_eq!(
        frontier_in.access,
        BufferAccess::ReadOnly,
        "frontier_in must be ReadOnly so the dispatcher binds host bytes; got {:?}",
        frontier_in.access
    );

    let frontier_out = prog
        .buffers()
        .iter()
        .find(|b| b.name() == "frontier_out")
        .expect("frontier_out declared");
    assert!(
        matches!(
            frontier_out.access,
            BufferAccess::ReadWrite | BufferAccess::WriteOnly
        ),
        "frontier_out must be writable; got {:?}",
        frontier_out.access
    );

    assert_ne!(
        prog.entry().len(),
        0,
        "reaching_defs_step must emit a non-empty entry vector"
    );
}

#[test]
fn reaching_defs_step_is_deterministic_on_identical_shapes() {
    let shape = ProgramGraphShape::new(64, 64);
    let a = reaching_defs_step(shape, "fin", "fout");
    let b = reaching_defs_step(shape, "fin", "fout");
    let buffers_a: Vec<(String, BufferAccess)> = a
        .buffers()
        .iter()
        .map(|b| (b.name().to_string(), b.access.clone()))
        .collect();
    let buffers_b: Vec<(String, BufferAccess)> = b
        .buffers()
        .iter()
        .map(|b| (b.name().to_string(), b.access.clone()))
        .collect();
    assert_eq!(
        buffers_a, buffers_b,
        "reaching_defs_step must be deterministic across equal shape+name calls"
    );
    assert_eq!(
        a.entry().len(),
        b.entry().len(),
        "entry length must match across equal calls"
    );
}

#[test]
fn reaching_defs_step_renames_frontier_buffers_per_call() {
    let shape = ProgramGraphShape::new(64, 64);
    let one = reaching_defs_step(shape, "fin_one", "fout_one");
    let two = reaching_defs_step(shape, "fin_two", "fout_two");
    let names_one: Vec<&str> = one.buffers().iter().map(|b| b.name()).collect();
    let names_two: Vec<&str> = two.buffers().iter().map(|b| b.name()).collect();

    assert!(names_one.contains(&"fin_one") && names_one.contains(&"fout_one"));
    assert!(!names_one.contains(&"fin_two"));
    assert!(names_two.contains(&"fin_two") && names_two.contains(&"fout_two"));
    assert!(!names_two.contains(&"fin_one"));
}