weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! Parity test: GPU bitset_and query primitives match reference oracles.
//!
//! Eight weir primitives share the same shape  -  a CSR-bitset AND
//! over `(data_in, query_set) → out` per word. They differ only in
//! their `OP_ID`, soundness tag, and the semantic interpretation of
//! `data_in`. This test dispatches each Program against the same
//! input pair and compares against each module's `cpu_ref`.

#![cfg(test)]

use vyre::ir::Program;
use vyre::DispatchConfig;
use vyre_driver_cuda::CudaBackend;

fn run_dispatch(
    backend: &CudaBackend,
    program: &Program,
    inputs: &[Vec<u8>],
    grid_x: u32,
) -> Vec<Vec<u8>> {
    let mut config = DispatchConfig::default();
    config.grid_override = Some([grid_x, 1, 1]);
    backend
        .dispatch(program, inputs, &config)
        .expect("dispatch")
}

fn live_dispatcher() -> CudaBackend {
    CudaBackend::acquire()
        .expect("CudaBackend::acquire failed on a host that must have an NVIDIA GPU.")
}

fn u32_bytes(words: &[u32]) -> Vec<u8> {
    vyre_primitives::wire::pack_u32_slice(&words)
}

fn bytes_u32(bytes: &[u8]) -> Vec<u32> {
    vyre_primitives::wire::decode_u32_le_bytes_all(bytes)
}

fn dispatch_and(
    backend: &CudaBackend,
    program: &Program,
    a: &[u32],
    b: &[u32],
    words: u32,
) -> Vec<u32> {
    let inputs: Vec<Vec<u8>> = vec![u32_bytes(a), u32_bytes(b), vec![0u8; (words as usize) * 4]];
    let outputs = run_dispatch(backend, program, &inputs, 1);
    let out = bytes_u32(&outputs[0]);
    out[..words as usize].to_vec()
}

fn assert_parity_and<F, G>(label: &str, build: F, cpu: G, a: &[u32], b: &[u32], words: u32)
where
    F: Fn() -> Program,
    G: Fn(&[u32], &[u32]) -> Vec<u32>,
{
    let backend = live_dispatcher();
    let program = build();
    let gpu = dispatch_and(&backend, &program, a, b, words);
    let cpu_out = cpu(a, b);
    assert_eq!(gpu, cpu_out[..words as usize], "{label}: divergence");
}

#[test]
fn cuda_post_dominates_parity() {
    assert_parity_and(
        "post_dominates",
        || weir::post_dominates::post_dominates(64, "pdom", "target", "out"),
        weir::oracle::bitset::post_dominates,
        &[0xFF00, 0x00FF],
        &[0x0FF0, 0x0F0F],
        2,
    );
}

#[test]
fn cuda_scc_query_parity() {
    assert_parity_and(
        "scc_query",
        || weir::scc_query::scc_query(64, "same", "query", "out"),
        weir::oracle::bitset::scc_query,
        &[0xFF00, 0xF00F],
        &[0x0FF0, 0x0F0F],
        2,
    );
}

#[test]
fn cuda_reaching_def_parity() {
    assert_parity_and(
        "reaching_def",
        || weir::reaching_def::reaching_def(64, "reaching", "uses", "out"),
        weir::oracle::bitset::reaching_def,
        &[0xF0F0, 0x0F0F],
        &[0x0FF0, 0xF0F0],
        2,
    );
}

#[test]
fn cuda_escapes_parity() {
    assert_parity_and(
        "escapes",
        || weir::escapes::escapes(64, "pts", "escape", "out"),
        weir::oracle::bitset::escapes,
        &[0x0FF0, 0x00FF],
        &[0xFF00, 0xF00F],
        2,
    );
}

#[test]
fn cuda_def_use_query_parity() {
    assert_parity_and(
        "def_use_query",
        || weir::def_use::def_use_query(64, "du", "query", "out"),
        weir::oracle::bitset::def_use,
        &[0xAAAA, 0x5555],
        &[0xFFFF, 0xFFFF],
        2,
    );
}

#[test]
fn cuda_must_init_parity() {
    assert_parity_and(
        "must_init",
        || weir::must_init::must_init(64, "defs", "uses", "out"),
        weir::oracle::bitset::must_init,
        &[0x0007, 0x0],
        &[0x0002, 0x0],
        2,
    );
}

#[test]
fn cuda_live_at_parity() {
    assert_parity_and(
        "live_at",
        || weir::live_at::live_at(64, "live_in", "query", "out"),
        weir::oracle::bitset::live_at,
        &[0xCAFE, 0xBABE],
        &[0xFF00, 0x00FF],
        2,
    );
}

#[test]
fn cuda_value_set_parity() {
    assert_parity_and(
        "value_set",
        || weir::value_set::value_set(64, "const_in", "query", "out"),
        weir::oracle::bitset::value_set,
        &[0xDEAD, 0xBEEF],
        &[0xF0F0, 0x0F0F],
        2,
    );
}