mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 19:22:01 +03:00
Update compiler pipelines
This commit is contained in:
parent
2fe6892645
commit
661a7cd508
@ -17,8 +17,8 @@
|
||||
//! The compiler for Leo programs.
|
||||
//!
|
||||
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
|
||||
use leo_ast::Program;
|
||||
pub use leo_ast::{Ast, InputAst};
|
||||
use leo_ast::{NodeBuilder, Program};
|
||||
use leo_errors::{emitter::Handler, CompilerError, Result};
|
||||
pub use leo_passes::SymbolTable;
|
||||
use leo_passes::*;
|
||||
@ -48,6 +48,10 @@ pub struct Compiler<'a> {
|
||||
pub input_ast: Option<InputAst>,
|
||||
/// Options configuring compilation.
|
||||
compiler_options: CompilerOptions,
|
||||
/// The `NodeCounter` used to generate sequentially increasing `NodeID`s.
|
||||
node_builder: NodeBuilder,
|
||||
/// The `Assigner` is used to construct (unique) assignment statements.
|
||||
assigner: Assigner,
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
@ -60,6 +64,8 @@ impl<'a> Compiler<'a> {
|
||||
output_directory: PathBuf,
|
||||
compiler_options: Option<CompilerOptions>,
|
||||
) -> Self {
|
||||
let node_builder = NodeBuilder::default();
|
||||
let assigner = Assigner::default();
|
||||
Self {
|
||||
handler,
|
||||
main_file_path,
|
||||
@ -69,6 +75,8 @@ impl<'a> Compiler<'a> {
|
||||
ast: Ast::new(Program::default()),
|
||||
input_ast: None,
|
||||
compiler_options: compiler_options.unwrap_or_default(),
|
||||
node_builder,
|
||||
assigner,
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +100,7 @@ impl<'a> Compiler<'a> {
|
||||
let prg_sf = with_session_globals(|s| s.source_map.new_source(program_string, name));
|
||||
|
||||
// Use the parser to construct the abstract syntax tree (ast).
|
||||
self.ast = leo_parser::parse_ast(self.handler, &prg_sf.src, prg_sf.start_pos)?;
|
||||
self.ast = leo_parser::parse_ast(self.handler, &self.node_builder, &prg_sf.src, prg_sf.start_pos)?;
|
||||
|
||||
// If the program is imported, then check that the name of its program scope matches the file name.
|
||||
// Note that parsing enforces that there is exactly one program scope in a file.
|
||||
@ -132,7 +140,8 @@ impl<'a> Compiler<'a> {
|
||||
.map_err(|e| CompilerError::file_read_error(&input_file_path, e))?;
|
||||
|
||||
// Parse and serialize it.
|
||||
let input_ast = leo_parser::parse_input(self.handler, &input_sf.src, input_sf.start_pos)?;
|
||||
let input_ast =
|
||||
leo_parser::parse_input(self.handler, &self.node_builder, &input_sf.src, input_sf.start_pos)?;
|
||||
if self.compiler_options.output.initial_ast {
|
||||
// Write the input AST snapshot post parsing.
|
||||
if self.compiler_options.output.spans_enabled {
|
||||
@ -166,7 +175,8 @@ impl<'a> Compiler<'a> {
|
||||
|
||||
/// Runs the loop unrolling pass.
|
||||
pub fn loop_unrolling_pass(&mut self, symbol_table: SymbolTable) -> Result<SymbolTable> {
|
||||
let (ast, symbol_table) = Unroller::do_pass((std::mem::take(&mut self.ast), self.handler, symbol_table))?;
|
||||
let (ast, symbol_table) =
|
||||
Unroller::do_pass((std::mem::take(&mut self.ast), self.handler, &self.node_builder, symbol_table))?;
|
||||
self.ast = ast;
|
||||
|
||||
if self.compiler_options.output.unrolled_ast {
|
||||
@ -177,45 +187,50 @@ impl<'a> Compiler<'a> {
|
||||
}
|
||||
|
||||
/// Runs the static single assignment pass.
|
||||
pub fn static_single_assignment_pass(&mut self, symbol_table: &SymbolTable) -> Result<Assigner> {
|
||||
let (ast, assigner) = StaticSingleAssigner::do_pass((std::mem::take(&mut self.ast), symbol_table))?;
|
||||
self.ast = ast;
|
||||
pub fn static_single_assignment_pass(&mut self, symbol_table: &SymbolTable) -> Result<()> {
|
||||
self.ast = StaticSingleAssigner::do_pass((
|
||||
std::mem::take(&mut self.ast),
|
||||
&self.node_builder,
|
||||
&self.assigner,
|
||||
symbol_table,
|
||||
))?;
|
||||
|
||||
if self.compiler_options.output.ssa_ast {
|
||||
self.write_ast_to_json("ssa_ast.json")?;
|
||||
}
|
||||
|
||||
Ok(assigner)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the flattening pass.
|
||||
pub fn flattening_pass(&mut self, symbol_table: &SymbolTable, assigner: Assigner) -> Result<Assigner> {
|
||||
let (ast, assigner) = Flattener::do_pass((std::mem::take(&mut self.ast), symbol_table, assigner))?;
|
||||
self.ast = ast;
|
||||
pub fn flattening_pass(&mut self, symbol_table: &SymbolTable) -> Result<()> {
|
||||
self.ast =
|
||||
Flattener::do_pass((std::mem::take(&mut self.ast), symbol_table, &self.node_builder, &self.assigner))?;
|
||||
|
||||
if self.compiler_options.output.flattened_ast {
|
||||
self.write_ast_to_json("flattened_ast.json")?;
|
||||
}
|
||||
|
||||
Ok(assigner)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the function inlining pass.
|
||||
pub fn function_inlining_pass(&mut self, call_graph: &CallGraph, assigner: Assigner) -> Result<Assigner> {
|
||||
let (ast, assigner) = FunctionInliner::do_pass((std::mem::take(&mut self.ast), call_graph, assigner))?;
|
||||
pub fn function_inlining_pass(&mut self, call_graph: &CallGraph) -> Result<()> {
|
||||
let ast =
|
||||
FunctionInliner::do_pass((std::mem::take(&mut self.ast), &self.node_builder, call_graph, &self.assigner))?;
|
||||
self.ast = ast;
|
||||
|
||||
if self.compiler_options.output.inlined_ast {
|
||||
self.write_ast_to_json("inlined_ast.json")?;
|
||||
}
|
||||
|
||||
Ok(assigner)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the dead code elimination pass.
|
||||
pub fn dead_code_elimination_pass(&mut self) -> Result<()> {
|
||||
if self.compiler_options.build.dce_enabled {
|
||||
self.ast = DeadCodeEliminator::do_pass(std::mem::take(&mut self.ast))?;
|
||||
self.ast = DeadCodeEliminator::do_pass((std::mem::take(&mut self.ast), &self.node_builder))?;
|
||||
}
|
||||
|
||||
if self.compiler_options.output.dce_ast {
|
||||
@ -243,12 +258,11 @@ impl<'a> Compiler<'a> {
|
||||
// TODO: Make this pass optional.
|
||||
let st = self.loop_unrolling_pass(st)?;
|
||||
|
||||
// TODO: Make this pass optional.
|
||||
let assigner = self.static_single_assignment_pass(&st)?;
|
||||
self.static_single_assignment_pass(&st)?;
|
||||
|
||||
let assigner = self.flattening_pass(&st, assigner)?;
|
||||
self.flattening_pass(&st)?;
|
||||
|
||||
let _ = self.function_inlining_pass(&call_graph, assigner)?;
|
||||
self.function_inlining_pass(&call_graph)?;
|
||||
|
||||
self.dead_code_elimination_pass()?;
|
||||
|
||||
|
@ -148,7 +148,7 @@ pub fn parse_program<'a>(
|
||||
let name = cwd.map_or_else(|| FileName::Custom("compiler-test".into()), FileName::Real);
|
||||
compiler.parse_program_from_string(program_string, name)?;
|
||||
|
||||
CheckUniqueNodeIds::new().run(&mut compiler.ast)?;
|
||||
CheckUniqueNodeIds::new().visit_program(&compiler.ast.ast);
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ pub struct FunctionInliner<'a> {
|
||||
pub(crate) assignment_renamer: AssignmentRenamer<'a>,
|
||||
/// A map of reconstructed functions in the current program scope.
|
||||
pub(crate) reconstructed_functions: IndexMap<Symbol, Function>,
|
||||
/// Whether or not we are currently inlining a function.
|
||||
pub(crate) inlining: bool,
|
||||
}
|
||||
|
||||
impl<'a> FunctionInliner<'a> {
|
||||
@ -42,7 +40,6 @@ impl<'a> FunctionInliner<'a> {
|
||||
call_graph,
|
||||
assignment_renamer: AssignmentRenamer::new(assigner),
|
||||
reconstructed_functions: Default::default(),
|
||||
inlining: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ use leo_ast::{
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
NodeID,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
use leo_ast::Struct;
|
||||
use leo_ast::{NodeBuilder, Struct};
|
||||
use leo_compiler::{Compiler, CompilerOptions, InputAst, OutputOptions};
|
||||
use leo_package::{
|
||||
build::BuildDirectory,
|
||||
@ -103,6 +103,9 @@ impl Command for Build {
|
||||
// Initialize error handler
|
||||
let handler = Handler::default();
|
||||
|
||||
// Initialize a node counter.
|
||||
let node_builder = NodeBuilder::default();
|
||||
|
||||
// Fetch paths to all .leo files in the source directory.
|
||||
let source_files = SourceDirectory::files(&package_path)?;
|
||||
|
||||
@ -158,7 +161,7 @@ impl Command for Build {
|
||||
.map_err(|e| CompilerError::file_read_error(&input_file_path, e))?;
|
||||
|
||||
// TODO: This is a hack to notify the user that something is wrong with the input file. Redesign.
|
||||
leo_parser::parse_input(&handler, &input_sf.src, input_sf.start_pos)
|
||||
leo_parser::parse_input(&handler, &node_builder, &input_sf.src, input_sf.start_pos)
|
||||
.map_err(|_e| println!("Warning: Failed to parse input file"))
|
||||
.ok()
|
||||
} else {
|
||||
|
@ -216,9 +216,9 @@ impl Sample {
|
||||
let (symbol_table, _struct_graph, _call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.flattening_pass(&symbol_table, assigner);
|
||||
let out = compiler.flattening_pass(&symbol_table);
|
||||
let time = start.elapsed();
|
||||
out.expect("failed to run flattener pass");
|
||||
time
|
||||
@ -231,10 +231,10 @@ impl Sample {
|
||||
let (symbol_table, _struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
|
||||
compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
compiler.flattening_pass(&symbol_table).expect("failed to run flattener pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.function_inlining_pass(&call_graph, assigner);
|
||||
let out = compiler.function_inlining_pass(&call_graph);
|
||||
let time = start.elapsed();
|
||||
out.expect("failed to run inliner pass");
|
||||
time
|
||||
@ -247,9 +247,9 @@ impl Sample {
|
||||
let (symbol_table, _struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
|
||||
let _ = compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run inliner pass");
|
||||
compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
compiler.flattening_pass(&symbol_table).expect("failed to run flattener pass");
|
||||
compiler.function_inlining_pass(&call_graph).expect("failed to run inliner pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.dead_code_elimination_pass();
|
||||
let time = start.elapsed();
|
||||
@ -264,9 +264,9 @@ impl Sample {
|
||||
let (symbol_table, struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
|
||||
let _ = compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run inliner pass");
|
||||
compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
compiler.flattening_pass(&symbol_table).expect("failed to run flattener pass");
|
||||
compiler.function_inlining_pass(&call_graph).expect("failed to run inliner pass");
|
||||
compiler.dead_code_elimination_pass().expect("failed to run dce pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.code_generation_pass(&symbol_table, &struct_graph, &call_graph);
|
||||
@ -285,9 +285,9 @@ impl Sample {
|
||||
let (symbol_table, struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattening pass");
|
||||
compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run function inlining pass");
|
||||
compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
|
||||
compiler.flattening_pass(&symbol_table).expect("failed to run flattening pass");
|
||||
compiler.function_inlining_pass(&call_graph).expect("failed to run function inlining pass");
|
||||
compiler.dead_code_elimination_pass().expect("failed to run dce pass");
|
||||
compiler
|
||||
.code_generation_pass(&symbol_table, &struct_graph, &call_graph)
|
||||
|
Loading…
Reference in New Issue
Block a user