sc_neurocore_engine/ir/
verify.rs1use std::collections::{HashMap, HashSet};
11
12use crate::ir::graph::*;
13
14#[derive(Debug, Clone)]
16pub struct VerifyError {
17 pub op_index: usize,
18 pub message: String,
19}
20
21impl std::fmt::Display for VerifyError {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 write!(f, "op[{}]: {}", self.op_index, self.message)
24 }
25}
26
27pub fn verify(graph: &ScGraph) -> Result<(), Vec<VerifyError>> {
30 let mut errors = Vec::new();
31 verify_ssa(graph, &mut errors);
32 verify_operand_defs(graph, &mut errors);
33 verify_no_cycles(graph, &mut errors);
34 if errors.is_empty() {
35 Ok(())
36 } else {
37 Err(errors)
38 }
39}
40
41fn verify_ssa(graph: &ScGraph, errors: &mut Vec<VerifyError>) {
43 let mut defined: HashMap<ValueId, usize> = HashMap::new();
44 for (idx, op) in graph.ops.iter().enumerate() {
45 let id = op.result_id();
46 if let Some(prev_idx) = defined.insert(id, idx) {
47 errors.push(VerifyError {
48 op_index: idx,
49 message: format!("{} is already defined by op[{}]", id, prev_idx),
50 });
51 }
52 }
53}
54
55fn verify_operand_defs(graph: &ScGraph, errors: &mut Vec<VerifyError>) {
57 let mut defined: HashSet<ValueId> = HashSet::new();
58 for (idx, op) in graph.ops.iter().enumerate() {
59 for operand in op.operands() {
60 if !defined.contains(&operand) {
61 errors.push(VerifyError {
62 op_index: idx,
63 message: format!(
64 "operand {} not defined before use in {}",
65 operand,
66 op.op_name()
67 ),
68 });
69 }
70 }
71 defined.insert(op.result_id());
72 }
73}
74
75fn verify_no_cycles(graph: &ScGraph, errors: &mut Vec<VerifyError>) {
80 let mut adj: HashMap<ValueId, Vec<ValueId>> = HashMap::new();
82 for op in &graph.ops {
83 adj.insert(op.result_id(), op.operands());
84 }
85
86 let mut visited: HashSet<ValueId> = HashSet::new();
87 let mut in_stack: HashSet<ValueId> = HashSet::new();
88
89 fn dfs(
90 node: ValueId,
91 adj: &HashMap<ValueId, Vec<ValueId>>,
92 visited: &mut HashSet<ValueId>,
93 in_stack: &mut HashSet<ValueId>,
94 ) -> bool {
95 if in_stack.contains(&node) {
96 return true; }
98 if visited.contains(&node) {
99 return false;
100 }
101 visited.insert(node);
102 in_stack.insert(node);
103 if let Some(deps) = adj.get(&node) {
104 for dep in deps {
105 if dfs(*dep, adj, visited, in_stack) {
106 return true;
107 }
108 }
109 }
110 in_stack.remove(&node);
111 false
112 }
113
114 for op in &graph.ops {
115 let id = op.result_id();
116 if dfs(id, &adj, &mut visited, &mut in_stack) {
117 errors.push(VerifyError {
118 op_index: 0,
119 message: format!("cycle detected involving {}", id),
120 });
121 break;
122 }
123 }
124}