Remove greedy inlining

This commit is contained in:
d0cd 2023-02-10 09:47:42 -08:00
parent 79bf13ff8e
commit d2381767e9
3 changed files with 51 additions and 40 deletions

View File

@ -19,7 +19,7 @@ use leo_errors::{
emitter::{Buffer, Emitter, Handler},
LeoError, LeoWarning,
};
use leo_passes::{CodeGenerator, Pass};
use leo_passes::{Assigner, CodeGenerator, Pass};
use leo_span::source_map::FileName;
use leo_test_framework::Test;
@ -101,6 +101,7 @@ pub fn new_compiler(handler: &Handler, main_file_path: PathBuf) -> Compiler<'_>
unrolled_ast: true,
ssa_ast: true,
flattened_ast: true,
inlined_ast: true,
}),
)
}
@ -184,11 +185,18 @@ pub fn temp_dir() -> PathBuf {
pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {
let st = parsed.symbol_table_pass()?;
let (st, struct_graph, call_graph) = parsed.type_checker_pass(st)?;
let st = parsed.loop_unrolling_pass(st)?;
let assigner = parsed.static_single_assignment_pass(&st)?;
parsed.flattening_pass(&st, assigner)?;
let (st, struct_graph, call_graph) = parsed.type_checker_pass(st)?;
let st = parsed.loop_unrolling_pass(st)?;
let assigner = Assigner::default();
let assigner = parsed.static_single_assignment_pass(&st, assigner)?;
let assigner = parsed.flattening_pass(&st, assigner)?;
let _ = parsed.function_inlining_pass(&st, &call_graph, assigner)?;
// Compile Leo program to bytecode.
let bytecode = CodeGenerator::do_pass((&parsed.ast, &st, &struct_graph, &call_graph))?;

View File

@ -214,7 +214,7 @@ mod test {
#[test]
fn test_unconnected_graph() {
let mut graph = DiGraph::<u32>::new(IndexSet::from([1, 2, 3, 4, 5]));
let graph = DiGraph::<u32>::new(IndexSet::from([1, 2, 3, 4, 5]));
check_post_order(&graph, &[1, 2, 3, 4, 5]);
}

View File

@ -16,10 +16,7 @@
use crate::{FunctionInliner, Replacer};
use leo_ast::{
CallExpression, Expression, ExpressionReconstructor, Identifier, ReturnStatement, Statement, StatementConsumer,
StatementReconstructor, UnitExpression,
};
use leo_ast::{CallExpression, Expression, ExpressionReconstructor, Identifier, ReturnStatement, Statement, StatementConsumer, StatementReconstructor, UnitExpression, Variant};
use indexmap::IndexMap;
use itertools::Itertools;
@ -35,41 +32,47 @@ impl ExpressionReconstructor for FunctionInliner<'_> {
};
// Lookup the reconstructed callee function.
// Since this pass processes functions in post-order, the callee function is guaranteed to exist in `self.reconstructed_function`
// Since this pass processes functions in post-order, the callee function is guaranteed to exist in `self.reconstructed_functions`
let callee = self.reconstructed_functions.get(&function_name).unwrap();
// Construct a mapping from input variables of the callee function to arguments passed to the callee.
let parameter_to_argument = callee
.input
.iter()
.map(|input| input.identifier())
.zip_eq(input.arguments.into_iter())
.collect::<IndexMap<_, _>>();
// Inline the callee function, if required, otherwise, return the call expression.
match callee.variant {
Variant::Transition | Variant::Standard => (Expression::Call(input), Default::default()),
Variant::Inline => {
// Construct a mapping from input variables of the callee function to arguments passed to the callee.
let parameter_to_argument = callee
.input
.iter()
.map(|input| input.identifier())
.zip_eq(input.arguments.into_iter())
.collect::<IndexMap<_, _>>();
// Duplicate the body of the callee and replace each input variable with the appropriate parameter.
let replace = |identifier: Identifier| match parameter_to_argument.get(&identifier) {
Some(expression) => expression.clone(),
None => Expression::Identifier(identifier),
};
let replaced_block = Replacer::new(replace).reconstruct_block(callee.block.clone()).0;
// Duplicate the body of the callee and replace each input variable with the appropriate parameter.
let replace = |identifier: Identifier| match parameter_to_argument.get(&identifier) {
Some(expression) => expression.clone(),
None => Expression::Identifier(identifier),
};
let replaced_block = Replacer::new(replace).reconstruct_block(callee.block.clone()).0;
// Ensure that each assignment in the `replaced_block` is a unique assignment statement.
let mut inlined_statements = self.static_single_assigner.consume_block(replaced_block);
// Ensure that each assignment in the `replaced_block` is a unique assignment statement.
let mut inlined_statements = self.static_single_assigner.consume_block(replaced_block);
// If the inlined block returns a value, then use the value in place of the call expression, otherwise, use the unit expression.
let result = match inlined_statements.last() {
Some(Statement::Return(_)) => {
// Note that this unwrap is safe since we know that the last statement is a return statement.
match inlined_statements.pop().unwrap() {
Statement::Return(ReturnStatement { expression, .. }) => expression,
_ => unreachable!("This branch checks that the last statement is a return statement."),
}
// If the inlined block returns a value, then use the value in place of the call expression, otherwise, use the unit expression.
let result = match inlined_statements.last() {
Some(Statement::Return(_)) => {
// Note that this unwrap is safe since we know that the last statement is a return statement.
match inlined_statements.pop().unwrap() {
Statement::Return(ReturnStatement { expression, .. }) => expression,
_ => unreachable!("This branch checks that the last statement is a return statement."),
}
}
_ => Expression::Unit(UnitExpression {
span: Default::default(),
}),
};
(result, inlined_statements)
}
_ => Expression::Unit(UnitExpression {
span: Default::default(),
}),
};
(result, inlined_statements)
}
}
}