use std::sync::Arc;
use vyre::ir::model::expr::Ident;
use vyre::ir::{BufferAccess, BufferDecl, DataType, Expr, Node, Program};
use vyre_primitives::graph::csr_forward_traverse::bitset_words;
pub(crate) const OP_ID: &str = "weir::may_alias";
#[must_use]
pub fn may_alias(
node_count: u32,
pts_p: &str,
pts_q: &str,
intersect_buf: &str,
out_scalar: &str,
) -> Program {
let words = bitset_words(node_count);
let t = Expr::InvocationId { axis: 0 };
let body = vec![
Node::let_bind(
"intersect",
Expr::bitand(Expr::load(pts_p, t.clone()), Expr::load(pts_q, t.clone())),
),
Node::store(intersect_buf, t.clone(), Expr::var("intersect")),
Node::if_then(
Expr::ne(Expr::var("intersect"), Expr::u32(0)),
vec![Node::let_bind(
"_",
Expr::atomic_or(out_scalar, Expr::u32(0), Expr::u32(1)),
)],
),
];
Program::wrapped(
vec![
BufferDecl::storage(pts_p, 0, BufferAccess::ReadOnly, DataType::U32).with_count(words),
BufferDecl::storage(pts_q, 1, BufferAccess::ReadOnly, DataType::U32).with_count(words),
BufferDecl::storage(intersect_buf, 2, BufferAccess::ReadWrite, DataType::U32)
.with_count(words),
BufferDecl::output(out_scalar, 3, DataType::U32).with_count(1),
],
[256, 1, 1],
vec![Node::Region {
generator: Ident::from(OP_ID),
source_region: None,
body: Arc::new(vec![Node::if_then(
Expr::lt(t.clone(), Expr::u32(words)),
body,
)]),
}],
)
}
inventory::submit! {
vyre_harness::OpEntry::new(
OP_ID,
|| may_alias(4, "a", "b", "scratch", "out"),
Some(|| {
let u32s = crate::dispatch_decode::pack_u32;
vec![vec![u32s(&[0b1100]), u32s(&[0b1010]), u32s(&[0])]]
}),
Some(|| {
let u32s = crate::dispatch_decode::pack_u32;
vec![vec![u32s(&[0b1000]), u32s(&[1])]]
}),
)
}
#[must_use]
#[cfg(any(test, feature = "cpu-parity"))]
#[deprecated(
note = "reference oracle only; production code must dispatch the Weir Program on a concrete GPU backend or use weir::oracle for parity evidence"
)]
pub(crate) fn cpu_ref(pts_p: &[u32], pts_q: &[u32]) -> u32 {
u32::from(
pts_p
.iter()
.zip(pts_q.iter())
.any(|(left, right)| left & right != 0),
)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MayAlias;
impl super::soundness::SoundnessTagged for MayAlias {
fn soundness(&self) -> super::soundness::Soundness {
super::soundness::Soundness::MayOver
}
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use super::*;
#[test]
fn overlapping_pts_alias() {
assert_eq!(cpu_ref(&[0b1010], &[0b0011]), 1);
}
#[test]
fn disjoint_pts_dont_alias() {
assert_eq!(cpu_ref(&[0b1010], &[0b0101]), 0);
}
#[test]
fn empty_pts_dont_alias() {
assert_eq!(cpu_ref(&[0], &[0xFFFF]), 0);
}
#[test]
fn identical_pts_alias() {
assert_eq!(cpu_ref(&[0xDEAD], &[0xDEAD]), 1);
}
}