From a7ee073f072eeeb4b2db464d8da5e025b5212c4c Mon Sep 17 00:00:00 2001 From: evan-schott <53463459+evan-schott@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:21:00 -0700 Subject: [PATCH] add constants to CPT and remove constant definitions from ST and AST --- .../src/loop_unrolling/unroll_program.rs | 52 +++++++++++++++++++ .../src/loop_unrolling/unroll_statement.rs | 50 ++++++++++++------ 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/compiler/passes/src/loop_unrolling/unroll_program.rs b/compiler/passes/src/loop_unrolling/unroll_program.rs index 34074e78a3..011aeedcbe 100644 --- a/compiler/passes/src/loop_unrolling/unroll_program.rs +++ b/compiler/passes/src/loop_unrolling/unroll_program.rs @@ -70,4 +70,56 @@ impl ProgramReconstructor for Unroller<'_> { reconstructed_function } + + fn reconstruct_const(&mut self, input: DefinitionStatement) -> DefinitionStatement { + // Reconstruct the RHS expression to allow for constant propagation + let reconstructed_value_expression = self.reconstruct_expression(input.value.clone()).0; + + // Helper function to add global constants to constant variable table + let insert_variable = |symbol: Symbol, value: &Expression| { + if let Literal(literal) = value { + if let Err(err) = self.constant_propagation_table.borrow_mut().insert_constant(symbol, literal.clone()) + { + self.handler.emit_err(err); + } + } else { + unreachable!("Type checking guarantees that the value of a constant is a literal."); + } + }; + + // No matter if doing multiple definitions in one line or not, insert all global constants into the constant propagation table + match &input.place { + Expression::Identifier(identifier) => { + insert_variable(identifier.name, &reconstructed_value_expression); + } + Expression::Tuple(tuple_expression) => { + let tuple_values: &Vec = match &reconstructed_value_expression { + Expression::Tuple(tuple_value_expression) => &tuple_value_expression.elements, + _ => unreachable!( + "Definition statement that defines tuple of variables must be assigned to tuple of values" + ), + }; + + for (i, element) in tuple_expression.elements.iter().enumerate() { + let identifier = match element { + Expression::Identifier(identifier) => identifier, + _ => unreachable!("All elements of a definition tuple must be identifiers"), + }; + insert_variable(identifier.name, &tuple_values[i].clone()); + } + } + _ => unreachable!( + "Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple." + ), + } + + DefinitionStatement { + declaration_type: input.declaration_type, + place: input.place, + type_: input.type_, + value: reconstructed_value_expression, + span: input.span, + id: input.id, + } + } } diff --git a/compiler/passes/src/loop_unrolling/unroll_statement.rs b/compiler/passes/src/loop_unrolling/unroll_statement.rs index 6160eea091..ff69cb9017 100644 --- a/compiler/passes/src/loop_unrolling/unroll_statement.rs +++ b/compiler/passes/src/loop_unrolling/unroll_statement.rs @@ -40,23 +40,25 @@ impl StatementReconstructor for Unroller<'_> { } fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) { + // Helper function to add variables to symbol table + let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| { + if let Err(err) = + self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration }) + { + self.handler.emit_err(err); + } + }; + + let declaration = + if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut }; + // If we are unrolling a loop, then we need to repopulate the symbol table. - if self.is_unrolling { - let declaration = - if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut }; - - let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| { - if let Err(err) = - self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration }) - { - self.handler.emit_err(err); - } - }; - - // Insert the variables in the into the symbol table. + // If we are not unrolling a loop, the we need to remove constants from the symbol table. + // We always need to add constant variables to the constant variable table. + if declaration == VariableType::Mut && self.is_unrolling { match &input.place { Expression::Identifier(identifier) => { - insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration) + insert_variable(identifier.name, input.type_.clone(), input.span, declaration); } Expression::Tuple(tuple_expression) => { let tuple_type = match input.type_ { @@ -65,20 +67,34 @@ impl StatementReconstructor for Unroller<'_> { "Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple." ), }; - tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| { + tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, _type_)| { let identifier = match expression { Expression::Identifier(identifier) => identifier, _ => unreachable!("Type checking guarantees that if the lhs is a tuple, all of its elements are identifiers.") }; - insert_variable(identifier.name, type_.clone(), identifier.span, declaration) + insert_variable(identifier.name, input.type_.clone(), input.span, declaration); }); } _ => unreachable!( "Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple." ), } + } else if declaration == VariableType::Const { + return (Statement::Definition(self.reconstruct_const(input.clone())), true); } - (Statement::Definition(input), Default::default()) + + // Reconstruct the expression and return + ( + Statement::Definition(DefinitionStatement { + declaration_type: input.declaration_type, + place: input.place, + type_: input.type_, + value: self.reconstruct_expression(input.value).0, + span: input.span, + id: input.id, + }), + false, + ) } fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {