circomspect_program_structure/control_flow_graph/
basic_block.rs1use log::trace;
2use std::collections::HashSet;
3use std::fmt;
4
5use crate::ir::declarations::Declarations;
6use crate::ir::degree_meta::DegreeEnvironment;
7use crate::ir::value_meta::ValueEnvironment;
8use crate::ssa::traits::DirectedGraphNode;
9
10use crate::ir::variable_meta::{VariableMeta, VariableUses};
11use crate::ir::{Meta, Statement};
12
13type Index = usize;
14type IndexSet = HashSet<Index>;
15
16#[derive(Clone)]
17pub struct BasicBlock {
18 index: Index,
19 meta: Meta,
20 loop_depth: usize,
21 stmts: Vec<Statement>,
22 predecessors: IndexSet,
23 successors: IndexSet,
24}
25
26impl BasicBlock {
27 #[must_use]
28 pub fn new(meta: Meta, index: Index, loop_depth: usize) -> BasicBlock {
29 trace!("creating basic block {index}");
30 BasicBlock {
31 meta,
32 index,
33 loop_depth,
34 stmts: Vec::new(),
35 predecessors: IndexSet::new(),
36 successors: IndexSet::new(),
37 }
38 }
39
40 #[must_use]
41 pub fn from_raw_parts(
42 index: Index,
43 meta: Meta,
44 loop_depth: usize,
45 stmts: Vec<Statement>,
46 predecessors: IndexSet,
47 successors: IndexSet,
48 ) -> BasicBlock {
49 BasicBlock { index, meta, loop_depth, stmts, predecessors, successors }
50 }
51
52 #[must_use]
53 pub fn len(&self) -> usize {
54 self.stmts.len()
55 }
56
57 #[must_use]
58 pub fn is_empty(&self) -> bool {
59 self.len() == 0
60 }
61
62 #[must_use]
63 pub fn in_loop(&self) -> bool {
64 self.loop_depth > 0
65 }
66
67 #[must_use]
68 pub fn loop_depth(&self) -> usize {
69 self.loop_depth
70 }
71
72 pub fn iter(&self) -> impl Iterator<Item = &Statement> {
73 self.stmts.iter()
74 }
75
76 pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut Statement> {
77 self.stmts.iter_mut()
78 }
79 #[must_use]
80 pub fn index(&self) -> Index {
81 self.index
82 }
83
84 #[must_use]
85 pub fn meta(&self) -> &Meta {
86 &self.meta
87 }
88
89 #[must_use]
90 pub(crate) fn meta_mut(&mut self) -> &mut Meta {
91 &mut self.meta
92 }
93
94 #[must_use]
95 pub fn statements(&self) -> &Vec<Statement> {
96 &self.stmts
97 }
98
99 #[must_use]
100 pub(crate) fn statements_mut(&mut self) -> &mut Vec<Statement> {
101 &mut self.stmts
102 }
103
104 pub(crate) fn prepend_statement(&mut self, stmt: Statement) {
105 self.stmts.insert(0, stmt);
106 }
107
108 pub(crate) fn append_statement(&mut self, stmt: Statement) {
109 self.stmts.push(stmt);
110 }
111
112 #[must_use]
113 pub fn predecessors(&self) -> &IndexSet {
114 &self.predecessors
115 }
116
117 #[must_use]
118 pub fn successors(&self) -> &IndexSet {
119 &self.successors
120 }
121
122 pub(crate) fn add_predecessor(&mut self, predecessor: Index) {
123 trace!("adding predecessor {} to basic block {}", predecessor, self.index);
124 self.predecessors.insert(predecessor);
125 }
126
127 pub(crate) fn add_successor(&mut self, successor: Index) {
128 trace!("adding successor {} to basic block {}", successor, self.index);
129 self.successors.insert(successor);
130 }
131
132 pub fn propagate_degrees(&mut self, env: &mut DegreeEnvironment) -> bool {
133 trace!("propagating degree ranges for basic block {}", self.index());
134 let mut result = false;
135 for stmt in self.iter_mut() {
136 result = result || stmt.propagate_degrees(env);
137 }
138 result
139 }
140
141 pub fn propagate_values(&mut self, env: &mut ValueEnvironment) -> bool {
142 trace!("propagating values for basic block {}", self.index());
143 let mut result = false;
144 for stmt in self.iter_mut() {
145 result = result || stmt.propagate_values(env);
146 }
147 result
148 }
149
150 pub fn propagate_types(&mut self, vars: &Declarations) {
151 trace!("propagating variable types for basic block {}", self.index());
152 for stmt in self.iter_mut() {
153 stmt.propagate_types(vars);
154 }
155 }
156}
157
158impl DirectedGraphNode for BasicBlock {
159 fn index(&self) -> Index {
160 self.index
161 }
162 fn predecessors(&self) -> &IndexSet {
163 &self.predecessors
164 }
165 fn successors(&self) -> &IndexSet {
166 &self.successors
167 }
168}
169
170impl VariableMeta for BasicBlock {
171 fn cache_variable_use(&mut self) {
172 trace!("computing variable use for basic block {}", self.index());
173 for stmt in self.iter_mut() {
176 stmt.cache_variable_use();
177 }
178
179 let locals_read = self.iter().flat_map(|stmt| stmt.locals_read()).cloned().collect();
181
182 let locals_written = self.iter().flat_map(|stmt| stmt.locals_written()).cloned().collect();
184
185 let signals_read = self.iter().flat_map(|stmt| stmt.signals_read()).cloned().collect();
187
188 let signals_written =
190 self.iter().flat_map(|stmt| stmt.signals_written()).cloned().collect();
191
192 let components_read =
194 self.iter().flat_map(|stmt| stmt.components_read()).cloned().collect();
195
196 let components_written =
198 self.iter().flat_map(|stmt| stmt.components_written()).cloned().collect();
199
200 self.meta_mut()
201 .variable_knowledge_mut()
202 .set_locals_read(&locals_read)
203 .set_locals_written(&locals_written)
204 .set_signals_read(&signals_read)
205 .set_signals_written(&signals_written)
206 .set_components_read(&components_read)
207 .set_components_written(&components_written);
208 }
209
210 fn locals_read(&self) -> &VariableUses {
211 self.meta().variable_knowledge().locals_read()
212 }
213
214 fn locals_written(&self) -> &VariableUses {
215 self.meta().variable_knowledge().locals_written()
216 }
217
218 fn signals_read(&self) -> &VariableUses {
219 self.meta().variable_knowledge().signals_read()
220 }
221
222 fn signals_written(&self) -> &VariableUses {
223 self.meta().variable_knowledge().signals_written()
224 }
225
226 fn components_read(&self) -> &VariableUses {
227 self.meta().variable_knowledge().components_read()
228 }
229
230 fn components_written(&self) -> &VariableUses {
231 self.meta().variable_knowledge().components_written()
232 }
233}
234
235impl fmt::Debug for BasicBlock {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237 let lines = self.iter().map(|stmt| format!("{stmt:?}")).collect::<Vec<_>>();
238 let width = lines.iter().map(|line| line.len()).max().unwrap_or_default();
239 let border = format!("+{}+", (0..width + 2).map(|_| '-').collect::<String>());
240
241 writeln!(f, "{}", &border)?;
242 for line in lines {
243 writeln!(f, "| {line:width$} |")?;
244 }
245 writeln!(f, "{}", &border)
246 }
247}