weirflow 0.1.0

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

#[test]
fn prepared_graph_reuses_reverse_csr_for_multiple_paths() {
    // Graph: 0 -> 1 -> 3 and 0 -> 2 -> 4.
    let attrs = dummy_attrs(5);
    let files = vec!["a.c".to_string()];
    let descs: Vec<String> = (0..5).map(|i| format!("stmt{i}")).collect();
    let edge_offsets = vec![0, 2, 3, 4, 4, 4];
    let edge_targets = vec![1u32, 2, 3, 4];
    let edge_kind_mask = vec![edge_kind::ASSIGNMENT; 4];
    let graph = prepare_witness_graph(
        &edge_offsets,
        &edge_targets,
        &edge_kind_mask,
        &attrs,
        &files,
        &descs,
        "c-c11",
    );
    let source_reach = vec![0b1_1111];
    let seed_a = PathSeed {
        source_file: "a.c".to_string(),
        source_node: 0,
        sink_file: "a.c".to_string(),
        sink_node: 3,
    };
    let seed_b = PathSeed {
        source_file: "a.c".to_string(),
        source_node: 0,
        sink_file: "a.c".to_string(),
        sink_node: 4,
    };

    let path_a = extract_path_prepared(&seed_a, &source_reach, &[], &graph)
        .expect("first prepared path must reconstruct");
    let path_b = extract_path_prepared(&seed_b, &source_reach, &[], &graph)
        .expect("second prepared path must reconstruct");

    assert_eq!(
        path_a
            .statements
            .iter()
            .map(|s| s.node_id)
            .collect::<Vec<_>>(),
        vec![0, 1, 3]
    );
    assert_eq!(
        path_b
            .statements
            .iter()
            .map(|s| s.node_id)
            .collect::<Vec<_>>(),
        vec![0, 2, 4]
    );
}

#[test]
fn prepared_batch_extracts_many_paths_without_rebuilding_reverse_csr() {
    let attrs = dummy_attrs(5);
    let files = vec!["a.c".to_string()];
    let descs: Vec<String> = (0..5).map(|i| format!("stmt{i}")).collect();
    let edge_offsets = vec![0, 2, 3, 4, 4, 4];
    let edge_targets = vec![1u32, 2, 3, 4];
    let edge_kind_mask = vec![edge_kind::ASSIGNMENT; 4];
    let graph = prepare_witness_graph(
        &edge_offsets,
        &edge_targets,
        &edge_kind_mask,
        &attrs,
        &files,
        &descs,
        "c-c11",
    );
    let source_reach = vec![0b1_1111];
    let seed_a = PathSeed {
        source_file: "a.c".to_string(),
        source_node: 0,
        sink_file: "a.c".to_string(),
        sink_node: 3,
    };
    let seed_b = PathSeed {
        source_file: "a.c".to_string(),
        source_node: 0,
        sink_file: "a.c".to_string(),
        sink_node: 4,
    };
    let requests = [
        PathExtractionRequest {
            seed: &seed_a,
            source_reach: &source_reach,
            sanitizer_mask: &[],
        },
        PathExtractionRequest {
            seed: &seed_b,
            source_reach: &source_reach,
            sanitizer_mask: &[],
        },
    ];

    let (paths, stats) = extract_paths_prepared(&requests, &graph)
        .expect("prepared witness batch must reserve result slots");

    assert_eq!(
        stats,
        PreparedWitnessBatchStats {
            requests: 2,
            successes: 2,
            errors: 0,
            prepared_graph_reuses: 2,
            prepared_node_count: 5,
            prepared_reverse_edges: 4,
        }
    );
    assert_eq!(graph.node_count(), 5);
    assert_eq!(graph.reverse_offset_count(), 6);
    assert_eq!(graph.reverse_edge_count(), 4);
    assert_eq!(
        paths[0]
            .as_ref()
            .expect("first path must reconstruct")
            .statements
            .iter()
            .map(|s| s.node_id)
            .collect::<Vec<_>>(),
        vec![0, 1, 3]
    );
    assert_eq!(
        paths[1]
            .as_ref()
            .expect("second path must reconstruct")
            .statements
            .iter()
            .map(|s| s.node_id)
            .collect::<Vec<_>>(),
        vec![0, 2, 4]
    );

    let mut reused_results = Vec::with_capacity(2);
    let repeat_stats = extract_paths_prepared_into(&requests, &graph, &mut reused_results)
        .expect("prepared witness batch into must reuse caller storage");
    assert_eq!(repeat_stats, stats);
    assert_eq!(reused_results, paths);
}