1use super::ssa::SsaForm;
22use vyre::ir::Program;
23use vyre_primitives::bitset::and::bitset_and;
24use vyre_primitives::graph::csr_forward_traverse::bitset_words;
25
26pub(crate) const OP_ID: &str = "weir::def_use";
27
28pub fn try_def_use_chain(form: &SsaForm, def_version: u32) -> Result<Vec<u32>, String> {
35 let Some(recorded_uses) = form.def_use_chains.get(&def_version) else {
36 return Err(format!(
37 "unknown SSA definition version {def_version}. Fix: query only versions emitted by SsaForm::def_use_chains; an absent definition is not an empty use-set."
38 ));
39 };
40 let mut uses = recorded_uses.clone();
41 uses.sort_unstable();
42 uses.dedup();
43 Ok(uses)
44}
45
46#[must_use]
52#[cfg(any(test, feature = "legacy-infallible"))]
53pub fn def_use_chain(form: &SsaForm, def_version: u32) -> Vec<u32> {
54 try_def_use_chain(form, def_version)
55 .expect("weir::def_use_chain received an unknown SSA definition version")
56}
57
58pub fn try_def_use_chain_bitset(
62 form: &SsaForm,
63 def_version: u32,
64 node_count: u32,
65) -> Result<Vec<u32>, String> {
66 let uses = try_def_use_chain(form, def_version)?;
67 let words = crate::dispatch_decode::bitset_word_capacity("def_use", node_count)?;
68 let mut bits = vec![0u32; words];
69 for use_id in uses {
70 if use_id < node_count {
71 let w = crate::dispatch_decode::u32_to_usize(use_id / 32, "def_use bitset word")?;
72 let b = use_id % 32;
73 bits[w] |= 1u32 << b;
74 }
75 }
76 Ok(bits)
77}
78
79#[must_use]
84#[cfg(any(test, feature = "legacy-infallible"))]
85pub fn def_use_chain_bitset(form: &SsaForm, def_version: u32, node_count: u32) -> Vec<u32> {
86 try_def_use_chain_bitset(form, def_version, node_count)
87 .expect("weir::def_use_chain_bitset received an unknown SSA definition version")
88}
89
90#[must_use]
97pub fn def_use_query(node_count: u32, def_use_buf: &str, query_set: &str, out: &str) -> Program {
98 let words = bitset_words(node_count);
99 vyre_harness::region::tag_program(OP_ID, bitset_and(def_use_buf, query_set, out, words))
100}
101
102#[must_use]
104#[cfg(any(test, feature = "cpu-parity"))]
105#[deprecated(
106 note = "reference oracle only; production code must dispatch the Weir Program on a concrete GPU backend or use weir::oracle for parity evidence"
107)]
108pub(crate) fn cpu_ref(def_use_buf: &[u32], query_set: &[u32]) -> Vec<u32> {
109 vyre_primitives::bitset::and::cpu_ref(def_use_buf, query_set)
110}
111
112#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114pub struct DefUse;
115
116impl DefUse {
117 #[must_use]
119 pub const fn op_id(&self) -> &'static str {
120 OP_ID
121 }
122}
123
124impl super::soundness::SoundnessTagged for DefUse {
125 fn soundness(&self) -> super::soundness::Soundness {
126 super::soundness::Soundness::Exact
127 }
128}
129
130inventory::submit! {
131 vyre_harness::OpEntry::new(
132 OP_ID,
133 || def_use_query(4, "def_use", "query", "out"),
134 Some(|| {
135 let u32s = crate::dispatch_decode::pack_u32;
136 vec![vec![u32s(&[0b1110]), u32s(&[0b1010]), u32s(&[0])]]
137 }),
138 Some(|| {
139 let u32s = crate::dispatch_decode::pack_u32;
140 vec![vec![u32s(&[0b1010])]]
141 }),
142 )
143}
144
145#[cfg(test)]
146#[allow(deprecated)]
147mod tests {
148 use super::*;
149 use std::collections::HashMap;
150
151 fn form_with(def_use: &[(u32, &[u32])]) -> SsaForm {
152 let mut chains = HashMap::new();
153 for (def, uses) in def_use {
154 chains.insert(*def, uses.to_vec());
155 }
156 SsaForm {
157 phi_nodes: HashMap::new(),
158 renamed_usages: HashMap::new(),
159 def_use_chains: chains,
160 }
161 }
162
163 #[test]
164 fn known_definition_returns_sorted_dedup_uses() {
165 let form = form_with(&[(7, &[5, 3, 5, 9, 3])]);
166 assert_eq!(def_use_chain(&form, 7), vec![3, 5, 9]);
167 }
168
169 #[test]
170 fn known_definition_with_no_uses_remains_empty() {
171 let form = form_with(&[(7, &[])]);
172 assert_eq!(
173 try_def_use_chain(&form, 7).expect("known empty definition"),
174 Vec::<u32>::new()
175 );
176 }
177
178 #[test]
179 fn unknown_definition_is_rejected_not_treated_as_empty() {
180 let form = form_with(&[(7, &[3, 5])]);
181 let error = try_def_use_chain(&form, 99).expect_err("unknown definition must fail");
182 assert!(
183 error.contains("unknown SSA definition version 99"),
184 "{error}"
185 );
186 }
187
188 #[test]
189 fn bitset_packs_use_ids() {
190 let form = form_with(&[(7, &[1, 33, 65])]);
191 let bits = def_use_chain_bitset(&form, 7, 96);
192 assert_eq!(bits, vec![1u32 << 1, 1u32 << 1, 1u32 << 1]);
194 }
195
196 #[test]
197 fn bitset_skips_uses_beyond_node_count() {
198 let form = form_with(&[(7, &[3, 200])]);
199 let bits = def_use_chain_bitset(&form, 7, 64);
200 assert_eq!(bits, vec![1u32 << 3, 0]);
202 }
203
204 #[test]
205 fn empty_form_rejects_unknown_definition() {
206 let form = form_with(&[]);
207 let err = try_def_use_chain_bitset(&form, 7, 64)
208 .expect_err("unknown definition in empty form must fail loudly");
209 assert!(
210 err.contains("unknown SSA definition version 7"),
211 "unexpected diagnostic: {err}"
212 );
213 }
214
215 #[test]
216 fn def_use_query_cpu_ref_intersects_query() {
217 assert_eq!(cpu_ref(&[0b1110], &[0b1010]), vec![0b1010]);
218 }
219}