Skip to main content

weir/
reaching_def.rs

1//! `reaching_def`  -  reaching-definitions query packed as a bitset.
2//!
3//! Per use site `u`, return the set of definitions that reach `u`
4//! (i.e. there's a CFG path from def to use with no intervening def
5//! of the same variable). This is the bitset dataflow consumers read for
6//! the `uses_of($def)` predicate's complement direction.
7
8use vyre::ir::Program;
9use vyre_primitives::bitset::and::bitset_and;
10use vyre_primitives::graph::csr_forward_traverse::bitset_words;
11
12pub(crate) const OP_ID: &str = "weir::reaching_def";
13
14/// Build a reaching-def query Program.
15///
16/// Inputs:
17/// - `gen_kill_in`: per-node bitset of definitions reaching the
18///   entry of each node (host-supplied via classical
19///   reaching-defs analysis).
20/// - `use_set`:     per-node bitset of use sites being queried.
21/// - `out`:         per-node bitset; bit `n` set iff `n` is a use
22///   AND has a reaching def.
23#[must_use]
24pub fn reaching_def(node_count: u32, gen_kill_in: &str, use_set: &str, out: &str) -> Program {
25    let words = bitset_words(node_count);
26    vyre_harness::region::tag_program(OP_ID, bitset_and(gen_kill_in, use_set, out, words))
27}
28
29/// reference oracle.
30#[must_use]
31#[cfg(any(test, feature = "cpu-parity"))]
32#[deprecated(
33    note = "reference oracle only; production code must dispatch the Weir Program on a concrete GPU backend or use weir::oracle for parity evidence"
34)]
35pub(crate) fn cpu_ref(gen_kill_in: &[u32], use_set: &[u32]) -> Vec<u32> {
36    vyre_primitives::bitset::and::cpu_ref(gen_kill_in, use_set)
37}
38
39/// Soundness marker for [`reaching_def`].
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct ReachingDef;
42impl super::soundness::SoundnessTagged for ReachingDef {
43    fn soundness(&self) -> super::soundness::Soundness {
44        super::soundness::Soundness::Exact
45    }
46}
47
48inventory::submit! {
49    vyre_harness::OpEntry::new(
50        OP_ID,
51        || reaching_def(4, "reaching", "uses", "out"),
52        Some(|| {
53            let u32s = crate::dispatch_decode::pack_u32;
54            vec![vec![u32s(&[0b1111]), u32s(&[0b0010]), u32s(&[0])]]
55        }),
56        Some(|| {
57            let u32s = crate::dispatch_decode::pack_u32;
58            vec![vec![u32s(&[0b0010])]]
59        }),
60    )
61}
62
63#[cfg(test)]
64#[allow(deprecated)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn use_with_reaching_def_returns_one() {
70        assert_eq!(cpu_ref(&[0b1111], &[0b0010]), vec![0b0010]);
71    }
72
73    #[test]
74    fn use_without_reaching_def_returns_zero() {
75        assert_eq!(cpu_ref(&[0b0001], &[0b0010]), vec![0]);
76    }
77
78    #[test]
79    fn no_uses_returns_empty() {
80        assert_eq!(cpu_ref(&[0xFFFF], &[0]), vec![0]);
81    }
82
83    #[test]
84    fn idempotent_intersection() {
85        let a = cpu_ref(&[0xF0F0], &[0x0FF0]);
86        let b = cpu_ref(&[0xF0F0], &[0x0FF0]);
87        assert_eq!(a, b);
88    }
89}