#![cfg(test)]
use vyre::DispatchConfig;
use vyre::VyreBackend;
use vyre_driver_cuda::{CudaBackend, CudaBackendRegistration};
use vyre_primitives::predicate::edge_kind;
use weir::fixed_point_resident::{
FixedPointResidentFrontierScratch, FixedPointResidentGraph, FixedPointResidentPlan,
};
use weir::oracle::graph::points_to_subset_closure as reference_subset_closure;
use weir::oracle::graph::points_to_subset_closure_borrowed_via as subset_closure_via;
use weir::points_to::prepare_points_to_subset_plan;
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_points_to_subset_closure_chain() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 2, 3, 3];
let edge_targets = vec![1u32, 2, 3];
let edge_kind_mask = vec![edge_kind::ASSIGNMENT; 3];
let seed_bits = vec![0b0001u32];
let reference =
reference_subset_closure(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = subset_closure_via(
&dispatch,
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, reference, "chain subset closure divergence");
assert_eq!(gpu, vec![0b1111u32]);
}
#[test]
fn cuda_points_to_diamond() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![edge_kind::MEM_LOAD; 4];
let seed_bits = vec![0b0001u32];
let reference =
reference_subset_closure(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = subset_closure_via(
&dispatch,
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, reference);
assert_eq!(gpu, vec![0b1111u32]);
}
#[test]
fn cuda_points_to_filtered_kind_mask_blocks_propagation() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 1];
let edge_targets = vec![1u32];
let edge_kind_mask = vec![edge_kind::CONTROL];
let seed_bits = vec![0b01u32];
let reference =
reference_subset_closure(2, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = subset_closure_via(
&dispatch,
2,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, reference);
assert_eq!(gpu, vec![0b01u32]);
}
#[test]
fn cuda_points_to_self_loop_terminates() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 1];
let edge_targets = vec![0u32];
let edge_kind_mask = vec![edge_kind::ALIAS];
let seed_bits = vec![0b01u32];
let reference =
reference_subset_closure(2, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = subset_closure_via(
&dispatch,
2,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
50,
)
.expect("dispatch");
assert_eq!(gpu, reference);
}
#[test]
fn cuda_points_to_multiple_edge_kinds_all_in_mask() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 4];
let edge_kind_mask = vec![
edge_kind::ASSIGNMENT,
edge_kind::MEM_STORE,
edge_kind::MUT_REF,
edge_kind::PHI,
];
let seed_bits = vec![0b00001u32];
let reference =
reference_subset_closure(5, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = subset_closure_via(
&dispatch,
5,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, reference);
assert_eq!(gpu, vec![0b11111u32]);
}
#[test]
fn cuda_points_to_resident_graph_parity() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![edge_kind::MEM_LOAD; 4];
let seed_bits = vec![0b0001u32];
let reference =
reference_subset_closure(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let plan = prepare_points_to_subset_plan(4, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("points-to plan must prepare for resident CUDA parity");
let config = DispatchConfig::default();
let pipeline = backend
.compile_native(plan.program(), &config)
.expect("CUDA native compile must succeed for resident points-to parity")
.expect("CUDA backend registration must return a native compiled pipeline for resident points-to parity");
let resident = FixedPointResidentGraph::upload(&backend, plan.graph())
.expect("CUDA backend must upload points-to graph as resident resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let gpu = resident
.points_to_subset_resident_frontier(
&backend,
&*pipeline,
&seed_bits,
16,
&config,
&mut scratch,
)
.expect("resident CUDA points-to dispatch must converge");
assert_eq!(gpu, reference);
assert_eq!(gpu, vec![0b1111u32]);
resident
.free(&backend)
.expect("resident points-to graph resources must free cleanly");
}
#[test]
fn cuda_points_to_resident_frontier_reuse_parity() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![edge_kind::MEM_LOAD; 4];
let first_seed = vec![0b0001u32];
let second_seed = vec![0b0010u32];
let first_reference = reference_subset_closure(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&first_seed,
);
let second_reference = reference_subset_closure(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&second_seed,
);
let plan = prepare_points_to_subset_plan(4, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("points-to plan must prepare for resident CUDA frontier reuse parity");
let config = DispatchConfig::default();
let pipeline = backend
.compile_native(plan.program(), &config)
.expect("CUDA native compile must succeed for resident points-to frontier reuse parity")
.expect("CUDA backend registration must return a native compiled pipeline for resident points-to frontier reuse parity");
let resident_plan = FixedPointResidentPlan::new(&backend, plan.graph(), pipeline)
.expect("CUDA backend must upload points-to resident plan resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let mut resident_frontier = FixedPointResidentFrontierScratch::default();
let first_gpu = resident_plan
.points_to_subset_reusing_frontier(
&backend,
&first_seed,
16,
&config,
&mut scratch,
&mut resident_frontier,
)
.expect("first resident CUDA points-to frontier reuse run must converge");
let second_gpu = resident_plan
.points_to_subset_reusing_frontier(
&backend,
&second_seed,
16,
&config,
&mut scratch,
&mut resident_frontier,
)
.expect("second resident CUDA points-to frontier reuse run must converge");
assert!(resident_frontier.is_allocated());
assert_eq!(resident_frontier.byte_len(), 4);
assert_eq!(first_gpu, first_reference);
assert_eq!(second_gpu, second_reference);
assert_eq!(first_gpu, vec![0b1111u32]);
assert_eq!(second_gpu, vec![0b1010u32]);
resident_plan
.free_with_frontier(&backend, &mut resident_frontier)
.expect("resident points-to plan and frontier resources must free cleanly");
}
#[test]
fn cuda_points_to_resident_sequence_window_uses_final_convergence_readback_only() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let edge_offsets = vec![0u32, 1, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 4];
let edge_kind_mask = vec![edge_kind::MEM_LOAD; 4];
let seed_bits = vec![0b00001u32];
let reference =
reference_subset_closure(5, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let plan = prepare_points_to_subset_plan(5, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("points-to plan must prepare for fixed-window resident CUDA parity");
let resident = FixedPointResidentGraph::upload(&backend, plan.graph())
.expect("CUDA backend must upload fixed-window points-to graph resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let mut resident_frontier = FixedPointResidentFrontierScratch::default();
backend.reset_telemetry();
let gpu = weir::points_to::subset_closure_resident_plan_with_reusable_frontier_scratch_sequence_window(
&backend,
plan.program(),
&resident,
&seed_bits,
16,
&mut scratch,
&mut resident_frontier,
)
.expect("fixed-window resident CUDA points-to dispatch must converge");
let telemetry = backend.telemetry_snapshot();
assert_eq!(gpu, reference);
assert_eq!(gpu, vec![0b11111u32]);
assert_eq!(
telemetry.readback_bytes, 8,
"Fix: fixed-window points-to resident solve must read only final and previous one-word frontiers, not poll every iteration."
);
assert!(
telemetry.sync_points < 16,
"Fix: fixed-window points-to resident solve must not synchronize once per fixed-point iteration; observed {} sync points.",
telemetry.sync_points
);
assert!(
telemetry.param_upload_bytes < telemetry.kernel_launches.saturating_mul(4),
"Fix: sequence-window points-to resident solve must hoist repeated fixed-point launch parameter uploads; observed {} parameter bytes across {} launches.",
telemetry.param_upload_bytes,
telemetry.kernel_launches
);
resident_frontier
.clear(&backend)
.expect("fixed-window resident points-to frontier resources must free cleanly");
resident
.free(&backend)
.expect("fixed-window resident points-to graph resources must free cleanly");
}