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