Skip to main content

vyre_debug/
descriptor_diff.rs

1use std::collections::{BTreeMap, HashSet};
2use vyre_foundation::ir::Program;
3use vyre_lower::KernelDescriptor;
4
5#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
6pub struct DescriptorDiff {
7    pub bindings_dropped: Vec<u32>,
8    pub bindings_added: Vec<u32>,
9    #[serde(
10        serialize_with = "crate::path_map_serde::serialize_i64",
11        deserialize_with = "crate::path_map_serde::deserialize_i64"
12    )]
13    pub op_count_delta: BTreeMap<Vec<usize>, i64>,
14    pub root_shape_changed: bool,
15}
16
17pub fn diff_descriptors(before: &KernelDescriptor, after: &KernelDescriptor) -> DescriptorDiff {
18    let before_bindings: HashSet<u32> = before.bindings.slots.iter().map(|s| s.slot).collect();
19    let after_bindings: HashSet<u32> = after.bindings.slots.iter().map(|s| s.slot).collect();
20
21    let mut dropped: Vec<u32> = before_bindings
22        .difference(&after_bindings)
23        .copied()
24        .collect();
25    dropped.sort_unstable();
26    let mut added: Vec<u32> = after_bindings
27        .difference(&before_bindings)
28        .copied()
29        .collect();
30    added.sort_unstable();
31
32    let mut before_counts = BTreeMap::new();
33    let mut after_counts = BTreeMap::new();
34
35    fn walk_counts(
36        body: &vyre_lower::KernelBody,
37        path: Vec<usize>,
38        map: &mut BTreeMap<Vec<usize>, usize>,
39    ) {
40        map.insert(path.clone(), body.ops.len());
41        for (i, child) in body.child_bodies.iter().enumerate() {
42            let mut p = path.clone();
43            p.push(i);
44            walk_counts(child, p, map);
45        }
46    }
47
48    walk_counts(&before.body, vec![], &mut before_counts);
49    walk_counts(&after.body, vec![], &mut after_counts);
50
51    let mut op_count_delta = BTreeMap::new();
52    for (path, before_count) in &before_counts {
53        let after_count = after_counts.get(path).copied().unwrap_or(0);
54        if *before_count != after_count {
55            op_count_delta.insert(path.clone(), (after_count as i64) - (*before_count as i64));
56        }
57    }
58    for (path, after_count) in &after_counts {
59        if !before_counts.contains_key(path) {
60            op_count_delta.insert(path.clone(), *after_count as i64);
61        }
62    }
63
64    let mut root_shape_changed = false;
65    if before.body.ops.len() != after.body.ops.len() {
66        root_shape_changed = true;
67    } else {
68        for (a, b) in before.body.ops.iter().zip(after.body.ops.iter()) {
69            if std::mem::discriminant(&a.kind) != std::mem::discriminant(&b.kind) {
70                root_shape_changed = true;
71                break;
72            }
73        }
74    }
75
76    DescriptorDiff {
77        bindings_dropped: dropped,
78        bindings_added: added,
79        op_count_delta,
80        root_shape_changed,
81    }
82}
83
84#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
85pub struct RewriteBisectResult {
86    pub first_failing_rewrite: Option<String>,
87    pub verify_errors: Vec<String>,
88    pub rewrite_history: Vec<(String, DescriptorDiff)>,
89}
90
91pub fn bisect_rewrites(program: &Program) -> Result<RewriteBisectResult, String> {
92    let lower_result = vyre_lower::lower(program).map_err(|e| format!("{:?}", e))?;
93
94    // We only care about the descriptor, we will extract it or maybe lower_for_emit.
95    // Wait, lower(program) returns KernelDescriptor?
96    // Let me check vyre_lower::lower or lower_for_emit. We'll use vyre_lower::lower.
97    let mut current = lower_result;
98
99    if let Err(errs) = vyre_lower::verify::verify(&current) {
100        return Ok(RewriteBisectResult {
101            first_failing_rewrite: Some("initial".to_string()),
102            verify_errors: errs.iter().map(|e| format!("{:?}", e)).collect(),
103            rewrite_history: vec![],
104        });
105    }
106
107    let mut first_failing_rewrite = None;
108    let mut verify_errors = Vec::new();
109    let mut rewrite_history = Vec::new();
110
111    let steps: Vec<(&str, fn(&KernelDescriptor) -> KernelDescriptor)> = vec![
112        ("strength_reduce", vyre_lower::rewrites::strength_reduce),
113        (
114            "shared_mem_promote",
115            vyre_lower::rewrites::shared_mem_promote,
116        ),
117        ("bank_conflict_pad", vyre_lower::rewrites::bank_conflict_pad),
118        (
119            "const_buffer_promote",
120            vyre_lower::rewrites::const_buffer_promote,
121        ),
122        (
123            "descriptor_const_fold",
124            vyre_lower::rewrites::descriptor_const_fold,
125        ),
126        ("identity_elim", vyre_lower::rewrites::identity_elim),
127        ("branch_collapse", vyre_lower::rewrites::branch_collapse),
128        ("loop_unroll", vyre_lower::rewrites::loop_unroll),
129        ("licm", vyre_lower::rewrites::licm),
130        ("load_forwarding", vyre_lower::rewrites::load_forwarding),
131        ("descriptor_dce#1", vyre_lower::rewrites::descriptor_dce),
132        ("dead_store", vyre_lower::rewrites::dead_store),
133        ("descriptor_dce#2", vyre_lower::rewrites::descriptor_dce),
134        ("canonicalize", vyre_lower::rewrites::canonicalize),
135        ("descriptor_cse", vyre_lower::rewrites::descriptor_cse),
136        (
137            "drop_unused_bindings",
138            vyre_lower::rewrites::drop_unused_bindings,
139        ),
140        (
141            "drop_unused_literals",
142            vyre_lower::rewrites::drop_unused_literals,
143        ),
144        (
145            "drop_unused_child_bodies",
146            vyre_lower::rewrites::drop_unused_child_bodies,
147        ),
148    ];
149
150    for (name, func) in steps {
151        let next = func(&current);
152        let diff = diff_descriptors(&current, &next);
153        rewrite_history.push((name.to_string(), diff));
154
155        if let Err(errs) = vyre_lower::verify::verify(&next) {
156            first_failing_rewrite = Some(name.to_string());
157            verify_errors = errs.iter().map(|e| format!("{:?}", e)).collect();
158            break;
159        }
160
161        current = next;
162    }
163
164    Ok(RewriteBisectResult {
165        first_failing_rewrite,
166        verify_errors,
167        rewrite_history,
168    })
169}