weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! Parity test: GPU callgraph_build matches reference oracle.

#![cfg(test)]

use vyre::DispatchConfig;
use vyre_driver_cuda::CudaBackend;
use weir::callgraph::callgraph_build_borrowed_via;
use weir::oracle::graph::callgraph_build as callgraph_build_cpu;

fn run_dispatch(
    backend: &CudaBackend,
) -> impl Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String> + '_ {
    move |program, inputs, grid_override| {
        let mut config = DispatchConfig::default();
        config.grid_override = grid_override;
        backend
            .dispatch_borrowed(program, inputs, &config)
            .map_err(|err| err.to_string())
    }
}

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

#[test]
fn cuda_callgraph_direct_only() {
    let backend = live_dispatcher();
    let dispatch = run_dispatch(&backend);
    let direct = vec![0b1010u32];
    let indirect = vec![0u32];
    let pts = vec![0u32];
    let cpu = callgraph_build_cpu(&direct, &indirect, &pts, 4);
    let gpu =
        callgraph_build_borrowed_via(&dispatch, &direct, &indirect, &pts, 4).expect("dispatch");
    assert_eq!(gpu, cpu);
    assert_eq!(gpu, vec![0b1010u32]);
}

#[test]
fn cuda_callgraph_indirect_with_pts() {
    let backend = live_dispatcher();
    let dispatch = run_dispatch(&backend);
    // indirect = {site 1, site 3}, pts_closure = {site 1, site 2}.
    // indirect & pts = {site 1}.
    let direct = vec![0b0000u32];
    let indirect = vec![0b1010u32];
    let pts = vec![0b0110u32];
    let cpu = callgraph_build_cpu(&direct, &indirect, &pts, 4);
    let gpu =
        callgraph_build_borrowed_via(&dispatch, &direct, &indirect, &pts, 4).expect("dispatch");
    assert_eq!(gpu, cpu);
    assert_eq!(gpu, vec![0b0010u32]);
}

#[test]
fn cuda_callgraph_combines_direct_and_indirect() {
    let backend = live_dispatcher();
    let dispatch = run_dispatch(&backend);
    let direct = vec![0b1100u32];
    let indirect = vec![0b1010u32];
    let pts = vec![0b0110u32];
    let cpu = callgraph_build_cpu(&direct, &indirect, &pts, 4);
    let gpu =
        callgraph_build_borrowed_via(&dispatch, &direct, &indirect, &pts, 4).expect("dispatch");
    assert_eq!(gpu, cpu);
    // direct | (indirect & pts) = 0b1100 | 0b0010 = 0b1110.
    assert_eq!(gpu, vec![0b1110u32]);
}

#[test]
fn cuda_callgraph_multi_word() {
    let backend = live_dispatcher();
    let dispatch = run_dispatch(&backend);
    let direct = vec![0xFF00u32, 0x000F];
    let indirect = vec![0xF0F0u32, 0xFFFF];
    let pts = vec![0x0FF0u32, 0xF0F0];
    let cpu = callgraph_build_cpu(&direct, &indirect, &pts, 64);
    let gpu =
        callgraph_build_borrowed_via(&dispatch, &direct, &indirect, &pts, 64).expect("dispatch");
    assert_eq!(gpu, cpu);
}

#[test]
fn cuda_callgraph_empty_pts_drops_indirect() {
    let backend = live_dispatcher();
    let dispatch = run_dispatch(&backend);
    let direct = vec![0b0001u32];
    let indirect = vec![0b1110u32];
    let pts = vec![0u32];
    let cpu = callgraph_build_cpu(&direct, &indirect, &pts, 4);
    let gpu =
        callgraph_build_borrowed_via(&dispatch, &direct, &indirect, &pts, 4).expect("dispatch");
    assert_eq!(gpu, cpu);
    assert_eq!(gpu, vec![0b0001u32]);
}