Skip to main content

vyre_debug/
dangling.rs

1use serde::{Deserialize, Serialize};
2use std::collections::{BTreeMap, BTreeSet};
3use vyre_lower::verify::{classify_operand, OperandClass};
4use vyre_lower::{KernelBody, KernelDescriptor};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct DanglingRef {
8    pub ref_id: u32,
9    pub produced_in_body_path: Vec<usize>,
10    pub producing_op_index: usize,
11    pub producing_op_kind: String,
12    pub referenced_in_body_path: Vec<usize>,
13    pub referencing_op_index: usize,
14    pub referencing_op_kind: String,
15    pub operand_position: usize,
16}
17
18pub fn find_dangling_refs(desc: &KernelDescriptor) -> Vec<DanglingRef> {
19    let mut id_origins = BTreeMap::new();
20
21    fn build_id_origins(
22        body: &KernelBody,
23        path: &mut Vec<usize>,
24        map: &mut BTreeMap<u32, (Vec<usize>, usize, String)>,
25    ) {
26        for (i, op) in body.ops.iter().enumerate() {
27            for r in op.result_ids() {
28                map.insert(r, (path.clone(), i, format!("{:?}", op.kind)));
29            }
30        }
31        for (idx, child) in body.child_bodies.iter().enumerate() {
32            path.push(idx);
33            build_id_origins(child, path, map);
34            path.pop();
35        }
36    }
37    build_id_origins(&desc.body, &mut vec![], &mut id_origins);
38
39    let mut refs = Vec::new();
40    check_body(
41        &desc.body,
42        &mut vec![],
43        &BTreeSet::new(),
44        &mut refs,
45        &id_origins,
46    );
47    refs
48}
49
50fn check_body(
51    body: &KernelBody,
52    path: &mut Vec<usize>,
53    inherited_results: &BTreeSet<u32>,
54    refs: &mut Vec<DanglingRef>,
55    id_origins: &BTreeMap<u32, (Vec<usize>, usize, String)>,
56) {
57    let mut produced: BTreeSet<u32> = BTreeSet::new();
58    for op in &body.ops {
59        for r in op.result_ids() {
60            produced.insert(r);
61        }
62    }
63
64    let mut produced_so_far: BTreeSet<u32> = BTreeSet::new();
65    let child_results: Vec<BTreeSet<u32>> =
66        body.child_bodies.iter().map(collect_body_results).collect();
67    let mut completed_child_results: BTreeSet<u32> = BTreeSet::new();
68    let mut child_scopes = vec![BTreeSet::new(); body.child_bodies.len()];
69
70    for (i, op) in body.ops.iter().enumerate() {
71        for (pos, &val) in op.operands.iter().enumerate() {
72            let cls = classify_operand(&op.kind, pos);
73            match cls {
74                OperandClass::ResultRef => {
75                    if !produced_so_far.contains(&val)
76                        && !produced.contains(&val)
77                        && !inherited_results.contains(&val)
78                        && !completed_child_results.contains(&val)
79                    {
80                        let (prod_path, prod_idx, prod_kind) =
81                            if let Some(orig) = id_origins.get(&val) {
82                                (orig.0.clone(), orig.1, orig.2.clone())
83                            } else {
84                                (vec![], 0, "Unknown".to_string())
85                            };
86
87                        refs.push(DanglingRef {
88                            ref_id: val,
89                            produced_in_body_path: prod_path,
90                            producing_op_index: prod_idx,
91                            producing_op_kind: prod_kind,
92                            referenced_in_body_path: path.clone(),
93                            referencing_op_index: i,
94                            referencing_op_kind: format!("{:?}", op.kind),
95                            operand_position: pos,
96                        });
97                    }
98                }
99                OperandClass::ChildBodyIdx => {
100                    if (val as usize) < body.child_bodies.len() {
101                        let child_scope = &mut child_scopes[val as usize];
102                        child_scope.extend(inherited_results.iter().copied());
103                        child_scope.extend(produced_so_far.iter().copied());
104                        child_scope.extend(completed_child_results.iter().copied());
105                    }
106                }
107                _ => {}
108            }
109        }
110
111        for r in op.result_ids() {
112            produced_so_far.insert(r);
113        }
114
115        for (pos, &val) in op.operands.iter().enumerate() {
116            if classify_operand(&op.kind, pos) == OperandClass::ChildBodyIdx {
117                if let Some(results) = child_results.get(val as usize) {
118                    completed_child_results.extend(results.iter().copied());
119                }
120            }
121        }
122    }
123
124    for (idx, child) in body.child_bodies.iter().enumerate() {
125        path.push(idx);
126        check_body(child, path, &child_scopes[idx], refs, id_origins);
127        path.pop();
128    }
129}
130
131fn collect_body_results(body: &KernelBody) -> BTreeSet<u32> {
132    let mut results = BTreeSet::new();
133    for op in &body.ops {
134        for result in op.result_ids() {
135            results.insert(result);
136        }
137    }
138    for child in &body.child_bodies {
139        results.extend(collect_body_results(child));
140    }
141    results
142}