weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! `scc_query`  -  strongly-connected-component membership query.
//!
//! Given the SCC label of every node (host-supplied via Tarjan or
//! the GPU SCC primitive), return the set of nodes belonging to the
//! same component as a query target. Used for cycle-detection rules
//! and recursion-aware static analysis.

use vyre::ir::Program;
use vyre_primitives::bitset::and::bitset_and;
use vyre_primitives::graph::csr_forward_traverse::bitset_words;

pub(crate) const OP_ID: &str = "weir::scc_query";

/// Build an SCC-membership Program.
///
/// Inputs:
/// - `same_scc_buf`: per-node bitset where bit `m` is set iff `m`
///   belongs to the SAME SCC as the query target
///   (host-built from the SCC label vector).
/// - `query_set`:    per-node bitset of nodes being queried.
/// - `out`:          per-node bitset; bit `n` set iff `n` is in
///   `query_set` AND in the same SCC as the target.
#[must_use]
pub fn scc_query(node_count: u32, same_scc_buf: &str, query_set: &str, out: &str) -> Program {
    let words = bitset_words(node_count);
    vyre_harness::region::tag_program(OP_ID, bitset_and(same_scc_buf, query_set, out, words))
}

/// reference oracle.
#[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(same_scc: &[u32], query_set: &[u32]) -> Vec<u32> {
    vyre_primitives::bitset::and::cpu_ref(same_scc, query_set)
}

/// Soundness marker for [`scc_query`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SccQuery;
impl super::soundness::SoundnessTagged for SccQuery {
    fn soundness(&self) -> super::soundness::Soundness {
        super::soundness::Soundness::Exact
    }
}

inventory::submit! {
    vyre_harness::OpEntry::new(
        OP_ID,
        || scc_query(4, "same", "query", "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])]]
        }),
    )
}

#[cfg(test)]
#[allow(deprecated)]
mod tests {
    use super::*;

    #[test]
    fn same_scc_query_intersects() {
        assert_eq!(cpu_ref(&[0b1100], &[0b1010]), vec![0b1000]);
    }

    #[test]
    fn no_match_yields_empty() {
        assert_eq!(cpu_ref(&[0b0011], &[0b1100]), vec![0]);
    }

    #[test]
    fn singleton_scc_self_match() {
        assert_eq!(cpu_ref(&[0b0001], &[0b0001]), vec![0b0001]);
    }

    #[test]
    fn distributes_per_word() {
        assert_eq!(
            cpu_ref(&[0xFF00, 0xF00F], &[0x0FF0, 0x0F0F]),
            vec![0x0F00, 0x000F]
        );
    }
}