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::Identifier(name) = assign.place {
86 let new_place = self.rename_identifier(name);
89
90 statements.push(self.simple_definition(new_place, value));
91 statements
92 } else {
93 let mut place = &mut assign.place;
98 loop {
99 match place {
100 Expression::ArrayAccess(array_access) => place = &mut array_access.array,
101 Expression::MemberAccess(member_access) => place = &mut member_access.inner,
102 Expression::TupleAccess(tuple_access) => place = &mut tuple_access.tuple,
103 expr @ Expression::Identifier(..) => {
104 let (new_expr, statements2) = self.consume_expression(std::mem::take(expr));
105 *expr = new_expr;
106 statements.extend(statements2);
107 assign.value = value;
108 statements.push(assign.into());
109 return statements;
110 }
111 _ => panic!("Type checking should have ensured this is not possible."),
112 }
113 }
114 }
115 }
116
117 fn consume_block(&mut self, block: Block) -> Self::Output {
119 block.statements.into_iter().flat_map(|statement| self.consume_statement(statement)).collect()
120 }
121
122 fn consume_conditional(&mut self, conditional: ConditionalStatement) -> Self::Output {
130 let (condition, mut statements) = self.consume_expression_and_define(conditional.condition);
132
133 self.push();
135
136 let then = Block {
138 span: conditional.then.span,
139 id: conditional.then.id,
140 statements: self.consume_block(conditional.then),
141 };
142
143 let if_table = self.pop();
145
146 self.push();
148
149 let otherwise = conditional.otherwise.map(|otherwise| Box::new(Statement::Block(match *otherwise {
151 Statement::Block(block) => Block {
152 span: block.span,
153 id: block.id,
154 statements: self.consume_block(block),
155 },
156 Statement::Conditional(conditional) => Block {
157 span: conditional.span,
158 id: conditional.id,
159 statements: self.consume_conditional(conditional),
160 },
161 _ => panic!("Type checking guarantees that the otherwise-block of a conditional statement is a block or another conditional statement."),
162 })));
163
164 let else_table = self.pop();
166
167 statements.push(ConditionalStatement { condition: condition.clone(), then, otherwise, ..conditional }.into());
169
170 let if_write_set: IndexSet<&Symbol> = IndexSet::from_iter(if_table.local_names());
172 let else_write_set: IndexSet<&Symbol> = IndexSet::from_iter(else_table.local_names());
173 let write_set = if_write_set.union(&else_write_set);
174
175 for symbol in write_set {
177 if self.rename_table.lookup(**symbol).is_some() {
179 let create_phi_argument = |table: &RenameTable, symbol: Symbol| -> Expression {
181 let name =
182 *table.lookup(symbol).unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program."));
183 let id = *table
184 .lookup_id(&name)
185 .unwrap_or_else(|| panic!("Symbol {name} should exist in the rename table."));
186 Identifier { name, span: Default::default(), id }.into()
187 };
188
189 let new_name = self.state.assigner.unique_symbol(symbol, "$");
191
192 let if_true = create_phi_argument(&if_table, **symbol);
194 let if_false = create_phi_argument(&else_table, **symbol);
195
196 let id = self.state.node_builder.next_id();
198 let Some(type_) = self.state.type_table.get(&if_true.id()) else {
200 panic!("Type checking guarantees that all expressions have a type.");
201 };
202 self.state.type_table.insert(id, type_);
203
204 let (value, stmts) = self.consume_ternary(TernaryExpression {
206 condition: condition.clone(),
207 if_true,
208 if_false,
209 span: Default::default(),
210 id,
211 });
212
213 statements.extend(stmts);
214
215 let id = *self.rename_table.lookup_id(symbol).unwrap_or_else(|| {
217 panic!("The ID for the symbol `{}` should already exist in the rename table.", symbol)
218 });
219
220 self.rename_table.update(**symbol, new_name, id);
222
223 let identifier = Identifier { name: new_name, span: Default::default(), id };
225 let assignment = self.simple_definition(identifier, value);
226
227 statements.push(assignment);
229 }
230 }
231
232 statements
233 }
234
235 fn consume_const(&mut self, _: ConstDeclaration) -> Self::Output {
236 Default::default()
238 }
239
240 fn consume_definition(&mut self, definition: DefinitionStatement) -> Self::Output {
242 let mut statements = Vec::new();
243
244 match definition.place {
245 DefinitionPlace::Single(identifier) => {
246 let (value, statements2) = self.consume_expression(definition.value);
248 statements = statements2;
249 let new_identifier = if self.rename_defs { self.rename_identifier(identifier) } else { identifier };
250 statements.push(self.simple_definition(new_identifier, value));
252 }
253 DefinitionPlace::Multiple(identifiers) => {
254 let new_identifiers: Vec<Identifier> = if self.rename_defs {
255 identifiers
256 .into_iter()
257 .map(
258 |identifier| if self.rename_defs { self.rename_identifier(identifier) } else { identifier },
259 )
260 .collect()
261 } else {
262 identifiers
263 };
264
265 let place = DefinitionPlace::Multiple(new_identifiers);
270
271 let value = if let Expression::Call(mut call) = definition.value {
272 for argument in call.arguments.iter_mut() {
273 let (new_argument, new_statements) = self.consume_expression(std::mem::take(argument));
274 *argument = new_argument;
275 statements.extend(new_statements);
276 }
277 Expression::Call(call)
278 } else {
279 let (value, new_statements) = self.consume_expression(definition.value);
280 statements.extend(new_statements);
281 value
282 };
283
284 let definition = DefinitionStatement { place, type_: None, value, ..definition }.into();
286
287 statements.push(definition);
288 }
289 }
290
291 statements
292 }
293
294 fn consume_expression_statement(&mut self, mut input: ExpressionStatement) -> Self::Output {
296 let (expr, mut statements) = self.consume_expression(input.expression);
297 input.expression = expr;
298 statements.push(input.into());
299 statements
300 }
301
302 fn consume_iteration(&mut self, _input: IterationStatement) -> Self::Output {
303 panic!("`IterationStatement`s should not be in the AST at this phase of compilation.");
304 }
305
306 fn consume_return(&mut self, mut input: ReturnStatement) -> Self::Output {
309 if let Expression::Tuple(tuple_expr) = &mut input.expression {
310 let mut statements = Vec::new();
312 for element in tuple_expr.elements.iter_mut() {
313 let (new_element, new_statements) = self.consume_expression_and_define(std::mem::take(element));
314 *element = new_element;
315 statements.extend(new_statements);
316 }
317 statements.push(input.into());
318 statements
319 } else {
320 let (expression, mut statements) = self.consume_expression_and_define(input.expression);
321 input.expression = expression;
322 statements.push(input.into());
323 statements
324 }
325 }
326}