#![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,
);
}