This commit is contained in:
Pranav Gaddamadugu 2022-08-16 09:00:06 -07:00
parent a2795baed8
commit a39ab9f77f
7 changed files with 35 additions and 57 deletions

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! This module contains a Consumer trait for the AST. //! This module contains a Consumer trait for the AST.
//! Consumers are used to completely transform the AST without any opinion on the output. //! Consumers are used to completely transform the AST without any restrictions on the output.
use crate::*; use crate::*;

View File

@ -17,7 +17,7 @@
//! This module contains both a Reducer and Visitor design pattern. //! This module contains both a Reducer and Visitor design pattern.
//! These both iterate over the AST. //! These both iterate over the AST.
// todo @gluax: Move the files in this module into `leo-passes` in a future PR. // TODO: Move the files in this module into `leo-passes` in a future PR.
pub mod consumer; pub mod consumer;
pub use consumer::*; pub use consumer::*;

View File

@ -45,7 +45,6 @@ impl<'a> CodeGenerator<'a> {
} }
fn visit_identifier(&mut self, input: &'a Identifier) -> (String, String) { fn visit_identifier(&mut self, input: &'a Identifier) -> (String, String) {
println!("{:?}", input);
(self.variable_mapping.get(&input.name).unwrap().clone(), String::new()) (self.variable_mapping.get(&input.name).unwrap().clone(), String::new())
} }

View File

@ -18,7 +18,7 @@
//! See https://en.wikipedia.org/wiki/Static_single-assignment_form for more information. //! See https://en.wikipedia.org/wiki/Static_single-assignment_form for more information.
//! The pass also flattens `ConditionalStatement`s into a sequence of `AssignStatement`s. //! The pass also flattens `ConditionalStatement`s into a sequence of `AssignStatement`s.
//! The pass also rewrites `ReturnStatement`s into `AssignStatement`s and consolidates the returned values as a single `ReturnStatement` at the end of the function. //! The pass also rewrites `ReturnStatement`s into `AssignStatement`s and consolidates the returned values as a single `ReturnStatement` at the end of the function.
//! The pass also simplifies complex expressions into a sequence of `AssignStatement`s. For example, `(a + b) * c` is rewritten into `expr$1 = a + b; expr$2 = expr$1 * c`. //! The pass also simplifies complex expressions into a sequence of `AssignStatement`s. For example, `(a + b) * c` is rewritten into `$var$1 = a + b; $var$2 = $var$1 * c`.
//! //!
//! Consider the following Leo code. //! Consider the following Leo code.
//! ```leo //! ```leo
@ -71,8 +71,6 @@ impl<'a> Pass for StaticSingleAssigner<'a> {
let program = consumer.consume_program(ast.into_repr()); let program = consumer.consume_program(ast.into_repr());
handler.last_err()?; handler.last_err()?;
println!("AST AFTER SSA:\n{}", program);
Ok(Ast::new(program)) Ok(Ast::new(program))
} }
} }

View File

@ -144,7 +144,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
// In this case, we must consume the expression. // In this case, we must consume the expression.
true => self.consume_expression(arg.expression.unwrap()), true => self.consume_expression(arg.expression.unwrap()),
}; };
// Add the output to the additional output. // Accumulate any statements produced.
statements.append(&mut stmts); statements.append(&mut stmts);
// Return the new member. // Return the new member.
@ -244,8 +244,8 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
}) })
.collect(); .collect();
// Note that we do not construct new assignment statement for the tuple expression, since tuple expressions are not supported.
// TODO: Fix when tuple expressions are supported. // TODO: Fix when tuple expressions are supported.
// Note that we do not construct new assignment statement for the tuple expression, since tuple expressions are not supported.
( (
Expression::Tuple(TupleExpression { Expression::Tuple(TupleExpression {
elements, elements,

View File

@ -46,8 +46,26 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
let (_, last_return_expression) = returns.pop().unwrap(); let (_, last_return_expression) = returns.pop().unwrap();
// Produce a chain of ternary expressions and assignments for the set of early returns. // Produce a chain of ternary expressions and assignments for the set of early returns.
// TODO: Can this be simplified?
let mut stmts = Vec::with_capacity(returns.len()); let mut stmts = Vec::with_capacity(returns.len());
// Helper to construct and store ternary assignments. e.g `$ret$0 = $var$0 ? $var$1 : $var$2`
let mut construct_ternary_assignment = |guard: Expression, if_true: Expression, if_false: Expression| {
let place = Expression::Identifier(Identifier {
name: self.unique_symbol("$ret"),
span: Default::default(),
});
stmts.push(Self::simple_assign_statement(
place.clone(),
Expression::Ternary(TernaryExpression {
condition: Box::new(guard),
if_true: Box::new(if_true),
if_false: Box::new(if_false),
span: Default::default(),
}),
));
place
};
let expression = returns let expression = returns
.into_iter() .into_iter()
.rev() .rev()
@ -64,19 +82,7 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
.into_iter() .into_iter()
.zip_eq(acc_tuple.elements.into_iter()) .zip_eq(acc_tuple.elements.into_iter())
.map(|(if_true, if_false)| { .map(|(if_true, if_false)| {
// Create an assignment statement for the element expression in the tuple. construct_ternary_assignment(guard.clone(), if_true, if_false)
let place = Expression::Identifier(Identifier {
name: self.unique_symbol("$ret"),
span: Default::default(),
});
let value = Expression::Ternary(TernaryExpression {
condition: Box::new(guard.clone()),
if_true: Box::new(if_true),
if_false: Box::new(if_false),
span: Default::default(),
});
stmts.push(Self::simple_assign_statement(place.clone(), value));
place
}) })
.collect(), .collect(),
span: Default::default(), span: Default::default(),
@ -84,26 +90,12 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
} }
// Otherwise, fold the return expressions into a single ternary expression. // Otherwise, fold the return expressions into a single ternary expression.
// Note that `expr` and `acc` are correspond to the `if` and `else` cases of the ternary expression respectively. // Note that `expr` and `acc` are correspond to the `if` and `else` cases of the ternary expression respectively.
(expr, acc) => { (expr, acc) => construct_ternary_assignment(guard, expr, acc),
let place = Expression::Identifier(Identifier {
name: self.unique_symbol("$ret"),
span: Default::default(),
});
let value = Expression::Ternary(TernaryExpression {
condition: Box::new(guard),
if_true: Box::new(expr),
if_false: Box::new(acc),
span: Default::default(),
});
stmts.push(Self::simple_assign_statement(place.clone(), value));
place
}
}, },
}); });
println!("1"); // Add all of the accumulated statements to the end of the block.
statements.extend(stmts); statements.extend(stmts);
println!("2");
// Add the `ReturnStatement` to the end of the block. // Add the `ReturnStatement` to the end of the block.
statements.push(Statement::Return(ReturnStatement { statements.push(Statement::Return(ReturnStatement {
@ -137,7 +129,7 @@ impl ProgramConsumer for StaticSingleAssigner<'_> {
name: input.name, name: input.name,
network: input.network, network: input.network,
expected_input: input.expected_input, expected_input: input.expected_input,
// TODO: Do inputs need to be processed? // TODO: Do inputs need to be processed? They are not processed in the existing compiler.
imports: input.imports, imports: input.imports,
functions: input functions: input
.functions .functions

View File

@ -59,8 +59,11 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
/// Consumes the `DefinitionStatement` into an `AssignStatement`, renaming the left-hand-side as appropriate. /// Consumes the `DefinitionStatement` into an `AssignStatement`, renaming the left-hand-side as appropriate.
fn consume_definition(&mut self, definition: DefinitionStatement) -> Self::Output { fn consume_definition(&mut self, definition: DefinitionStatement) -> Self::Output {
// First consume the right-hand-side of the definition.
let (value, mut statements) = self.consume_expression(definition.value); let (value, mut statements) = self.consume_expression(definition.value);
// Then assign a new unique name to the left-hand-side of the definition.
// Note that this order is necessary to ensure that the right-hand-side uses the correct name when consuming a complex assignment.
self.is_lhs = true; self.is_lhs = true;
let identifier = match self.consume_identifier(definition.variable_name).0 { let identifier = match self.consume_identifier(definition.variable_name).0 {
Expression::Identifier(identifier) => identifier, Expression::Identifier(identifier) => identifier,
@ -99,11 +102,6 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
fn consume_conditional(&mut self, conditional: ConditionalStatement) -> Self::Output { fn consume_conditional(&mut self, conditional: ConditionalStatement) -> Self::Output {
// Simplify the condition and add it into the rename table. // Simplify the condition and add it into the rename table.
let (condition, mut statements) = self.consume_expression(conditional.condition); let (condition, mut statements) = self.consume_expression(conditional.condition);
// TODO: Is this needed?
println!("Condition:\n{:?}\n", condition);
println!("Statements:\n{:?}\n", statements);
println!("Rename Table:\n{:?}\n", self.rename_table);
// self.rename_table.update(symbol, symbol);
// Instantiate a `RenameTable` for the then-block. // Instantiate a `RenameTable` for the then-block.
self.push(); self.push();
@ -132,18 +130,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
span: condition.span(), span: condition.span(),
})); }));
statements.extend(match *statement { statements.extend(self.consume_statement(*statement));
// TODO: Check that the statement below still holds.
// The `ConditionalStatement` must be consumed as a `Block` statement to ensure that appropriate statements are produced.
Statement::Conditional(stmt) => self.consume_block(Block {
statements: vec![Statement::Conditional(stmt)],
span: Default::default(),
}),
Statement::Block(stmt) => self.consume_block(stmt),
_ => unreachable!(
"`ConditionalStatement`s next statement must be a `ConditionalStatement` or a `Block`."
),
});
// Remove the negated condition from the condition stack. // Remove the negated condition from the condition stack.
self.condition_stack.pop(); self.condition_stack.pop();
@ -192,7 +179,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
// Update the `RenameTable` with the new name of the variable. // Update the `RenameTable` with the new name of the variable.
self.rename_table.update(*(*symbol), new_name); self.rename_table.update(*(*symbol), new_name);
// Store the generate phi functions. // Store the generated phi function.
statements.push(assignment); statements.push(assignment);
} }
} }
@ -200,10 +187,12 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
statements statements
} }
// TODO: Error message
fn consume_iteration(&mut self, _input: IterationStatement) -> Self::Output { fn consume_iteration(&mut self, _input: IterationStatement) -> Self::Output {
unreachable!("`IterationStatement`s should not be in the AST at this phase of compilation."); unreachable!("`IterationStatement`s should not be in the AST at this phase of compilation.");
} }
// TODO: Where do we handle console statements.
fn consume_console(&mut self, input: ConsoleStatement) -> Self::Output { fn consume_console(&mut self, input: ConsoleStatement) -> Self::Output {
vec![Statement::Console(input)] vec![Statement::Console(input)]
} }