#[cfg(test)]
#[cfg(feature = "gpu")]
mod tests {
use crate::backend::{require_gpu, DispatchConfig, WgslBackend};
fn boundary_pairs() -> &'static [(u32, u32)] {
&[
(0, 0),
(0, 1),
(1, 0),
(1, 1),
(u32::MAX, 0),
(0, u32::MAX),
(u32::MAX, 1),
(1, u32::MAX),
(u32::MAX, u32::MAX),
(0x80000000, 0),
(0, 0x80000000),
(0x80000000, 0x80000000),
(0xFF, 0xFF),
(0xAAAAAAAA, 0x55555555),
(0xDEADBEEF, 0xCAFEBABE),
(0xF0F0F0F0, 0x0F0F0F0F),
]
}
#[test]
fn xor_then_popcount_matches_sequential() {
let backend = require_gpu().expect("vyre-conform test needs a GPU adapter");
let xor_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] ^ input.data[1u];
}
";
let popcount_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return countOneBits(input.data[0u]);
}
";
let composed_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return countOneBits(input.data[0u] ^ input.data[1u]);
}
";
let config = DispatchConfig::default();
for &(a, b) in boundary_pairs() {
let mut input = Vec::with_capacity(8);
input.extend_from_slice(&a.to_le_bytes());
input.extend_from_slice(&b.to_le_bytes());
let xor_shader = crate::backend::wrap_shader(xor_wgsl, &config);
let xor_result = backend
.dispatch(&xor_shader, &input, 4, config.clone())
.expect("xor dispatch");
let popcount_shader = crate::backend::wrap_shader(popcount_wgsl, &config);
let sequential_result = backend
.dispatch(&popcount_shader, &xor_result, 4, config.clone())
.expect("popcount dispatch");
let composed_shader = crate::backend::wrap_shader(composed_wgsl, &config);
let composed_result = backend
.dispatch(&composed_shader, &input, 4, config.clone())
.expect("composed dispatch");
assert_eq!(
composed_result, sequential_result,
"I2 violated: composed popcount(xor({a:#X}, {b:#X})) = {:?}, \
sequential = {:?}",
composed_result, sequential_result
);
}
}
#[test]
fn add_then_mask_matches_sequential() {
let backend = require_gpu().expect("vyre-conform test needs a GPU adapter");
let composed_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return (input.data[0u] + input.data[1u]) & 0xFFu;
}
";
let add_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] + input.data[1u];
}
";
let mask_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] & 0xFFu;
}
";
let config = DispatchConfig::default();
for &(a, b) in boundary_pairs() {
let mut input = Vec::with_capacity(8);
input.extend_from_slice(&a.to_le_bytes());
input.extend_from_slice(&b.to_le_bytes());
let add_shader = crate::backend::wrap_shader(add_wgsl, &config);
let add_result = backend
.dispatch(&add_shader, &input, 4, config.clone())
.expect("add dispatch");
let mask_shader = crate::backend::wrap_shader(mask_wgsl, &config);
let sequential = backend
.dispatch(&mask_shader, &add_result, 4, config.clone())
.expect("mask dispatch");
let composed_shader = crate::backend::wrap_shader(composed_wgsl, &config);
let composed = backend
.dispatch(&composed_shader, &input, 4, config.clone())
.expect("composed dispatch");
assert_eq!(
composed, sequential,
"I2 violated: composed (add+mask)({a:#X}, {b:#X}) = {composed:?}, sequential = {sequential:?}"
);
}
}
#[test]
fn and_then_shl_then_popcount_matches_sequential() {
let backend = require_gpu().expect("vyre-conform test needs a GPU adapter");
let and_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] & input.data[1u];
}
";
let shl_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] << 1u;
}
";
let popcount_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return countOneBits(input.data[0u]);
}
";
let composed_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return countOneBits((input.data[0u] & input.data[1u]) << 1u);
}
";
let config = DispatchConfig::default();
for &(a, b) in boundary_pairs() {
let mut input = Vec::with_capacity(8);
input.extend_from_slice(&a.to_le_bytes());
input.extend_from_slice(&b.to_le_bytes());
let and_shader = crate::backend::wrap_shader(and_wgsl, &config);
let and_result = backend
.dispatch(&and_shader, &input, 4, config.clone())
.expect("and dispatch");
let shl_shader = crate::backend::wrap_shader(shl_wgsl, &config);
let shl_result = backend
.dispatch(&shl_shader, &and_result, 4, config.clone())
.expect("shl dispatch");
let popcount_shader = crate::backend::wrap_shader(popcount_wgsl, &config);
let sequential = backend
.dispatch(&popcount_shader, &shl_result, 4, config.clone())
.expect("popcount dispatch");
let composed_shader = crate::backend::wrap_shader(composed_wgsl, &config);
let composed = backend
.dispatch(&composed_shader, &input, 4, config.clone())
.expect("composed dispatch");
assert_eq!(
composed, sequential,
"I2 violated: three-op and+shl+popcount({a:#X}, {b:#X}) = {composed:?}, sequential = {sequential:?}"
);
}
}
#[test]
fn sub_then_abs_then_clamp_matches_sequential() {
let backend = require_gpu().expect("vyre-conform test needs a GPU adapter");
let sub_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return input.data[0u] - input.data[1u];
}
";
let abs_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return u32(abs(i32(input.data[0u])));
}
";
let clamp_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return clamp(input.data[0u], 0u, 100u);
}
";
let composed_wgsl = r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
return clamp(u32(abs(i32(input.data[0u] - input.data[1u]))), 0u, 100u);
}
";
let config = DispatchConfig::default();
for &(a, b) in boundary_pairs() {
let mut input = Vec::with_capacity(8);
input.extend_from_slice(&a.to_le_bytes());
input.extend_from_slice(&b.to_le_bytes());
let sub_shader = crate::backend::wrap_shader(sub_wgsl, &config);
let sub_result = backend
.dispatch(&sub_shader, &input, 4, config.clone())
.expect("sub dispatch");
let abs_shader = crate::backend::wrap_shader(abs_wgsl, &config);
let abs_result = backend
.dispatch(&abs_shader, &sub_result, 4, config.clone())
.expect("abs dispatch");
let clamp_shader = crate::backend::wrap_shader(clamp_wgsl, &config);
let sequential = backend
.dispatch(&clamp_shader, &abs_result, 4, config.clone())
.expect("clamp dispatch");
let composed_shader = crate::backend::wrap_shader(composed_wgsl, &config);
let composed = backend
.dispatch(&composed_shader, &input, 4, config.clone())
.expect("composed dispatch");
assert_eq!(
composed, sequential,
"I2 violated: three-op sub+abs+clamp({a:#X}, {b:#X}) = {composed:?}, sequential = {sequential:?}"
);
}
}
}