mirror of
https://github.com/AleoHQ/leo.git
synced 2024-09-21 20:18:09 +03:00
WIP function inlining
This commit is contained in:
parent
b3ef6f79c3
commit
c934bb35b3
37
compiler/passes/src/function_inlining/function_inliner.rs
Normal file
37
compiler/passes/src/function_inlining/function_inliner.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Assigner, CallGraph, SymbolTable};
|
||||
|
||||
pub struct FunctionInliner<'a> {
|
||||
/// The `SymbolTable` of the program.
|
||||
pub(crate) symbol_table: &'a SymbolTable,
|
||||
/// The call graph for the program.
|
||||
pub(crate) call_graph: &'a CallGraph,
|
||||
/// An struct used to construct (unique) variable names.
|
||||
pub(crate) assigner: Assigner,
|
||||
}
|
||||
|
||||
impl<'a> FunctionInliner<'a> {
|
||||
/// Initializes a new `FunctionInliner`.
|
||||
pub fn new(symbol_table: &'a SymbolTable, call_graph: &'a CallGraph, assigner: Assigner) -> Self {
|
||||
Self {
|
||||
symbol_table,
|
||||
call_graph,
|
||||
assigner,
|
||||
}
|
||||
}
|
||||
}
|
27
compiler/passes/src/function_inlining/inline_expression.rs
Normal file
27
compiler/passes/src/function_inlining/inline_expression.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::FunctionInliner;
|
||||
|
||||
use leo_ast::{CallExpression, Expression, ExpressionReconstructor, Statement};
|
||||
|
||||
impl ExpressionReconstructor for FunctionInliner<'_> {
|
||||
type AdditionalOutput = Vec<Statement>;
|
||||
|
||||
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
todo!()
|
||||
}
|
||||
}
|
59
compiler/passes/src/function_inlining/inline_program.rs
Normal file
59
compiler/passes/src/function_inlining/inline_program.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::FunctionInliner;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use leo_ast::{Finalize, Function, ProgramReconstructor, ProgramScope, StatementReconstructor};
|
||||
|
||||
impl ProgramReconstructor for FunctionInliner<'_> {
|
||||
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
|
||||
let mut reconstructed_functions = IndexMap::new();
|
||||
|
||||
// TODO: Reconstruct each of the functions in post-order and add them to the function map.
|
||||
// TODO: Once implemented, we do not need to reorder functions during code generation.
|
||||
|
||||
ProgramScope {
|
||||
program_id: input.program_id,
|
||||
structs: input.structs,
|
||||
mappings: input.mappings,
|
||||
functions: reconstructed_functions,
|
||||
span: input.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_function(&mut self, input: Function) -> Function {
|
||||
// TODO: Reconstruct the function in the correct order
|
||||
Function {
|
||||
annotations: input.annotations,
|
||||
variant: input.variant,
|
||||
identifier: input.identifier,
|
||||
input: input.input,
|
||||
output: input.output,
|
||||
output_type: input.output_type,
|
||||
block: self.reconstruct_block(input.block).0,
|
||||
finalize: input.finalize.map(|finalize| Finalize {
|
||||
identifier: finalize.identifier,
|
||||
input: finalize.input,
|
||||
output: finalize.output,
|
||||
output_type: finalize.output_type,
|
||||
block: self.reconstruct_block(finalize.block).0,
|
||||
span: finalize.span,
|
||||
}),
|
||||
span: input.span,
|
||||
}
|
||||
}
|
||||
}
|
55
compiler/passes/src/function_inlining/inline_statement.rs
Normal file
55
compiler/passes/src/function_inlining/inline_statement.rs
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::FunctionInliner;
|
||||
|
||||
use leo_ast::{Block, ConsoleStatement, DefinitionStatement, IterationStatement, Statement, StatementReconstructor};
|
||||
|
||||
impl StatementReconstructor for FunctionInliner<'_> {
|
||||
/// Reconstructs the statements inside a basic block, accumulating any statements produced by function inlining.
|
||||
fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
|
||||
let mut statements = Vec::with_capacity(block.statements.len());
|
||||
|
||||
for statement in block.statements {
|
||||
let (reconstructed_statement, additional_statements) = self.reconstruct_statement(statement);
|
||||
statements.extend(additional_statements);
|
||||
statements.push(reconstructed_statement);
|
||||
}
|
||||
|
||||
(
|
||||
Block {
|
||||
span: block.span,
|
||||
statements,
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parsing guarantees that console statements are not present in the program.
|
||||
fn reconstruct_console(&mut self, _: ConsoleStatement) -> (Statement, Self::AdditionalOutput) {
|
||||
unreachable!("`ConsoleStatement`s should not be in the AST at this phase of compilation.")
|
||||
}
|
||||
|
||||
/// Static single assignment replaces definition statements with assignment statements.
|
||||
fn reconstruct_definition(&mut self, _definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
|
||||
unreachable!("`DefinitionStatement`s should not exist in the AST at this phase of compilation.")
|
||||
}
|
||||
|
||||
/// Loop unrolling unrolls and removes iteration statements from the program.
|
||||
fn reconstruct_iteration(&mut self, _input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
|
||||
unreachable!("`IterationStatement`s should not be in the AST at this phase of compilation.");
|
||||
}
|
||||
}
|
86
compiler/passes/src/function_inlining/mod.rs
Normal file
86
compiler/passes/src/function_inlining/mod.rs
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! The Function Inlining pass traverses the AST and inlines function at their call site.
|
||||
//! See https://en.wikipedia.org/wiki/Inline_expansion for more information.
|
||||
//! The pass also reorders `Function`s in a reconstructed `ProgramScope` so that they are in a post-order of the call graph.
|
||||
//! In other words, a callee function will appear before a caller function in the order.
|
||||
//!
|
||||
//! Consider the following Leo code in SSA form.
|
||||
//! ```leo
|
||||
//! function main(flag: u8, value: u8) -> u8 {
|
||||
//! $var$0 = flag == 0u8;
|
||||
//! if ($var$0) {
|
||||
//! $var$1 = foo(value);
|
||||
//! value$2 = $var$1;
|
||||
//! return value$2;
|
||||
//! }
|
||||
//! value$3 = $var$0 ? value$2 : value;
|
||||
//! return value$3;
|
||||
//! }
|
||||
//!
|
||||
//! inline foo(x: u8) -> u8 {
|
||||
//! $var$4 = x * x;
|
||||
//! return $var$4;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The inlining pass produces the following code.
|
||||
//! ```leo
|
||||
//! inline foo(x: u8) -> u8 {
|
||||
//! $var$4 = x * x;
|
||||
//! return $var$4;
|
||||
//! }
|
||||
//!
|
||||
//! function main(flag: u8, value: u8) -> u8 {
|
||||
//! $var$0 = flag == 0u8;
|
||||
//! if ($var$0) {
|
||||
//! $var$4$5 = value * value;
|
||||
//! $var$1 = $var$4$5;
|
||||
//! value$2 = $var$1;
|
||||
//! return value$2;
|
||||
//! }
|
||||
//! value$3 = $var$0 ? value$2 : value;
|
||||
//! return value$3;
|
||||
//! }
|
||||
//! ```
|
||||
//! Note that the redundant assignments have no effect on the bytecode generated by the compiler.
|
||||
|
||||
mod inline_expression;
|
||||
|
||||
mod inline_statement;
|
||||
|
||||
mod inline_program;
|
||||
|
||||
pub mod function_inliner;
|
||||
pub use function_inliner::*;
|
||||
|
||||
use crate::{Assigner, CallGraph, Pass, SymbolTable};
|
||||
|
||||
use leo_ast::{Ast, ProgramReconstructor};
|
||||
use leo_errors::Result;
|
||||
|
||||
impl<'a> Pass for FunctionInliner<'a> {
|
||||
type Input = (Ast, &'a SymbolTable, &'a CallGraph, Assigner);
|
||||
type Output = Result<(Ast, Assigner)>;
|
||||
|
||||
fn do_pass((ast, st, call_graph, assigner): Self::Input) -> Self::Output {
|
||||
let mut reconstructor = FunctionInliner::new(st, call_graph, assigner);
|
||||
let program = reconstructor.reconstruct_program(ast.into_repr());
|
||||
|
||||
Ok((Ast::new(program), reconstructor.assigner))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user