use super::ssa::SsaForm;
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::def_use";
pub fn try_def_use_chain(form: &SsaForm, def_version: u32) -> Result<Vec<u32>, String> {
let Some(recorded_uses) = form.def_use_chains.get(&def_version) else {
return Err(format!(
"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."
));
};
let mut uses = recorded_uses.clone();
uses.sort_unstable();
uses.dedup();
Ok(uses)
}
#[must_use]
#[cfg(any(test, feature = "legacy-infallible"))]
pub fn def_use_chain(form: &SsaForm, def_version: u32) -> Vec<u32> {
try_def_use_chain(form, def_version)
.expect("weir::def_use_chain received an unknown SSA definition version")
}
pub fn try_def_use_chain_bitset(
form: &SsaForm,
def_version: u32,
node_count: u32,
) -> Result<Vec<u32>, String> {
let uses = try_def_use_chain(form, def_version)?;
let words = crate::dispatch_decode::bitset_word_capacity("def_use", node_count)?;
let mut bits = vec![0u32; words];
for use_id in uses {
if use_id < node_count {
let w = crate::dispatch_decode::u32_to_usize(use_id / 32, "def_use bitset word")?;
let b = use_id % 32;
bits[w] |= 1u32 << b;
}
}
Ok(bits)
}
#[must_use]
#[cfg(any(test, feature = "legacy-infallible"))]
pub fn def_use_chain_bitset(form: &SsaForm, def_version: u32, node_count: u32) -> Vec<u32> {
try_def_use_chain_bitset(form, def_version, node_count)
.expect("weir::def_use_chain_bitset received an unknown SSA definition version")
}
#[must_use]
pub fn def_use_query(node_count: u32, def_use_buf: &str, query_set: &str, out: &str) -> Program {
let words = bitset_words(node_count);
vyre_harness::region::tag_program(OP_ID, bitset_and(def_use_buf, query_set, out, words))
}
#[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(def_use_buf: &[u32], query_set: &[u32]) -> Vec<u32> {
vyre_primitives::bitset::and::cpu_ref(def_use_buf, query_set)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DefUse;
impl DefUse {
#[must_use]
pub const fn op_id(&self) -> &'static str {
OP_ID
}
}
impl super::soundness::SoundnessTagged for DefUse {
fn soundness(&self) -> super::soundness::Soundness {
super::soundness::Soundness::Exact
}
}
inventory::submit! {
vyre_harness::OpEntry::new(
OP_ID,
|| def_use_query(4, "def_use", "query", "out"),
Some(|| {
let u32s = crate::dispatch_decode::pack_u32;
vec![vec![u32s(&[0b1110]), u32s(&[0b1010]), u32s(&[0])]]
}),
Some(|| {
let u32s = crate::dispatch_decode::pack_u32;
vec![vec![u32s(&[0b1010])]]
}),
)
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use super::*;
use std::collections::HashMap;
fn form_with(def_use: &[(u32, &[u32])]) -> SsaForm {
let mut chains = HashMap::new();
for (def, uses) in def_use {
chains.insert(*def, uses.to_vec());
}
SsaForm {
phi_nodes: HashMap::new(),
renamed_usages: HashMap::new(),
def_use_chains: chains,
}
}
#[test]
fn known_definition_returns_sorted_dedup_uses() {
let form = form_with(&[(7, &[5, 3, 5, 9, 3])]);
assert_eq!(def_use_chain(&form, 7), vec![3, 5, 9]);
}
#[test]
fn known_definition_with_no_uses_remains_empty() {
let form = form_with(&[(7, &[])]);
assert_eq!(
try_def_use_chain(&form, 7).expect("known empty definition"),
Vec::<u32>::new()
);
}
#[test]
fn unknown_definition_is_rejected_not_treated_as_empty() {
let form = form_with(&[(7, &[3, 5])]);
let error = try_def_use_chain(&form, 99).expect_err("unknown definition must fail");
assert!(
error.contains("unknown SSA definition version 99"),
"{error}"
);
}
#[test]
fn bitset_packs_use_ids() {
let form = form_with(&[(7, &[1, 33, 65])]);
let bits = def_use_chain_bitset(&form, 7, 96);
assert_eq!(bits, vec![1u32 << 1, 1u32 << 1, 1u32 << 1]);
}
#[test]
fn bitset_skips_uses_beyond_node_count() {
let form = form_with(&[(7, &[3, 200])]);
let bits = def_use_chain_bitset(&form, 7, 64);
assert_eq!(bits, vec![1u32 << 3, 0]);
}
#[test]
fn empty_form_rejects_unknown_definition() {
let form = form_with(&[]);
let err = try_def_use_chain_bitset(&form, 7, 64)
.expect_err("unknown definition in empty form must fail loudly");
assert!(
err.contains("unknown SSA definition version 7"),
"unexpected diagnostic: {err}"
);
}
#[test]
fn def_use_query_cpu_ref_intersects_query() {
assert_eq!(cpu_ref(&[0b1110], &[0b1010]), vec![0b1010]);
}
}