leo_passes/static_single_assignment/
statement.rs1use super::SsaFormingVisitor;
18use crate::RenameTable;
19
20use leo_ast::{
21 AssertStatement,
22 AssertVariant,
23 AssignStatement,
24 Block,
25 ConditionalStatement,
26 ConstDeclaration,
27 DefinitionPlace,
28 DefinitionStatement,
29 Expression,
30 ExpressionConsumer,
31 ExpressionStatement,
32 Identifier,
33 IterationStatement,
34 Node,
35 ReturnStatement,
36 Statement,
37 StatementConsumer,
38 TernaryExpression,
39};
40use leo_span::Symbol;
41
42use indexmap::IndexSet;
43
44impl StatementConsumer for SsaFormingVisitor<'_> {
45 type Output = Vec<Statement>;
46
47 fn consume_assert(&mut self, input: AssertStatement) -> Self::Output {
49 let (variant, mut statements) = match input.variant {
50 AssertVariant::Assert(expr) => {
51 let (expr, statements) = self.consume_expression_and_define(expr);
52 (AssertVariant::Assert(expr), statements)
53 }
54 AssertVariant::AssertEq(left, right) => {
55 let (left, mut statements) = self.consume_expression_and_define(left);
57 let (right, right_statements) = self.consume_expression_and_define(right);
59 statements.extend(right_statements);
61
62 (AssertVariant::AssertEq(left, right), statements)
63 }
64 AssertVariant::AssertNeq(left, right) => {
65 let (left, mut statements) = self.consume_expression_and_define(left);
67 let (right, right_statements) = self.consume_expression_and_define(right);
69 statements.extend(right_statements);
71
72 (AssertVariant::AssertNeq(left, right), statements)
73 }
74 };
75
76 statements.push(AssertStatement { variant, ..input }.into());
78
79 statements
80 }
81
82 fn consume_assign(&mut self, mut assign: AssignStatement) -> Self::Output {
84 let (value, mut statements) = self.consume_expression(assign.value);
85 if let Expression::Path(path) = assign.place {
86 let new_place = self.rename_identifier(path.identifier());
90
91 statements.push(self.simple_definition(new_place, value));
92 statements
93 } else {
94 let mut place = &mut assign.place;
99 loop {
100 match place {
101 Expression::ArrayAccess(array_access) => place = &mut array_access.array,
102 Expression::MemberAccess(member_access) => place = &mut member_access.inner,
103 Expression::TupleAccess(tuple_access) => place = &mut tuple_access.tuple,
104 expr @ Expression::Path(..) => {
105 let (new_expr, statements2) = self.consume_expression(std::mem::take(expr));
106 *expr = new_expr;
107 statements.extend(statements2);
108 assign.value = value;
109 statements.push(assign.into());
110 return statements;
111 }
112 _ => panic!("Type checking should have ensured this is not possible."),
113 }
114 }
115 }
116 }
117
118 fn consume_block(&mut self, block: Block) -> Self::Output {
120 block.statements.into_iter().flat_map(|statement| self.consume_statement(statement)).collect()
121 }
122
123 fn consume_conditional(&mut self, conditional: ConditionalStatement) -> Self::Output {
131 let (condition, mut statements) = self.consume_expression_and_define(conditional.condition);
133
134 self.push();
136
137 let then = Block {
139 span: conditional.then.span,
140 id: conditional.then.id,
141 statements: self.consume_block(conditional.then),
142 };
143
144 let if_table = self.pop();
146
147 self.push();
149
150 let otherwise = conditional.otherwise.map(|otherwise| Box::new(Statement::Block(match *otherwise {
152 Statement::Block(block) => Block {
153 span: block.span,
154 id: block.id,
155 statements: self.consume_block(block),
156 },
157 Statement::Conditional(conditional) => Block {
158 span: conditional.span,
159 id: conditional.id,
160 statements: self.consume_conditional(conditional),
161 },
162 _ => panic!("Type checking guarantees that the otherwise-block of a conditional statement is a block or another conditional statement."),
163 })));
164
165 let else_table = self.pop();
167
168 statements.push(ConditionalStatement { condition: condition.clone(), then, otherwise, ..conditional }.into());
170
171 let if_write_set: IndexSet<&Symbol> = IndexSet::from_iter(if_table.local_names());
173 let else_write_set: IndexSet<&Symbol> = IndexSet::from_iter(else_table.local_names());
174 let write_set = if_write_set.union(&else_write_set);
175
176 for symbol in write_set {
178 if self.rename_table.lookup(**symbol).is_some() {
180 let create_phi_argument = |table: &RenameTable, symbol: Symbol| -> Expression {
182 let name =
183 *table.lookup(symbol).unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program."));
184 let id = *table
185 .lookup_id(&name)
186 .unwrap_or_else(|| panic!("Symbol {name} should exist in the rename table."));
187 Identifier { name, span: Default::default(), id }.into()
188 };
189
190 let new_name = self.state.assigner.unique_symbol(symbol, "$");
192
193 let if_true = create_phi_argument(&if_table, **symbol);
195 let if_false = create_phi_argument(&else_table, **symbol);
196
197 let id = self.state.node_builder.next_id();
199 let Some(type_) = self.state.type_table.get(&if_true.id()) else {
201 panic!("Type checking guarantees that all expressions have a type.");
202 };
203 self.state.type_table.insert(id, type_);
204
205 let (value, stmts) = self.consume_ternary(TernaryExpression {
207 condition: condition.clone(),
208 if_true,
209 if_false,
210 span: Default::default(),
211 id,
212 });
213
214 statements.extend(stmts);
215
216 let id = *self.rename_table.lookup_id(symbol).unwrap_or_else(|| {
218 panic!("The ID for the symbol `{symbol}` should already exist in the rename table.")
219 });
220
221 self.rename_table.update(**symbol, new_name, id);
223
224 let identifier = Identifier { name: new_name, span: Default::default(), id };
226 let assignment = self.simple_definition(identifier, value);
227
228 statements.push(assignment);
230 }
231 }
232
233 statements
234 }
235
236 fn consume_const(&mut self, _: ConstDeclaration) -> Self::Output {
237 Default::default()
239 }
240
241 fn consume_definition(&mut self, definition: DefinitionStatement) -> Self::Output {
243 let mut statements = Vec::new();
244
245 match definition.place {
246 DefinitionPlace::Single(identifier) => {
247 let (value, statements2) = self.consume_expression(definition.value);
249 statements = statements2;
250 let new_identifier = if self.rename_defs { self.rename_identifier(identifier) } else { identifier };
251 statements.push(self.simple_definition(new_identifier, value));
253 }
254 DefinitionPlace::Multiple(identifiers) => {
255 let new_identifiers: Vec<Identifier> = if self.rename_defs {
256 identifiers
257 .into_iter()
258 .map(
259 |identifier| if self.rename_defs { self.rename_identifier(identifier) } else { identifier },
260 )
261 .collect()
262 } else {
263 identifiers
264 };
265
266 let place = DefinitionPlace::Multiple(new_identifiers);
271
272 let value = if let Expression::Call(mut call) = definition.value {
273 for argument in call.arguments.iter_mut() {
274 let (new_argument, new_statements) = self.consume_expression(std::mem::take(argument));
275 *argument = new_argument;
276 statements.extend(new_statements);
277 }
278 Expression::Call(call)
279 } else {
280 let (value, new_statements) = self.consume_expression(definition.value);
281 statements.extend(new_statements);
282 value
283 };
284
285 let definition = DefinitionStatement { place, type_: None, value, ..definition }.into();
287
288 statements.push(definition);
289 }
290 }
291
292 statements
293 }
294
295 fn consume_expression_statement(&mut self, mut input: ExpressionStatement) -> Self::Output {
297 let (expr, mut statements) = self.consume_expression(input.expression);
298 input.expression = expr;
299 statements.push(input.into());
300 statements
301 }
302
303 fn consume_iteration(&mut self, _input: IterationStatement) -> Self::Output {
304 panic!("`IterationStatement`s should not be in the AST at this phase of compilation.");
305 }
306
307 fn consume_return(&mut self, mut input: ReturnStatement) -> Self::Output {
310 if let Expression::Tuple(tuple_expr) = &mut input.expression {
311 let mut statements = Vec::new();
313 for element in tuple_expr.elements.iter_mut() {
314 let (new_element, new_statements) = self.consume_expression_and_define(std::mem::take(element));
315 *element = new_element;
316 statements.extend(new_statements);
317 }
318 statements.push(input.into());
319 statements
320 } else {
321 let (expression, mut statements) = self.consume_expression_and_define(input.expression);
322 input.expression = expression;
323 statements.push(input.into());
324 statements
325 }
326 }
327}