mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 13:56:58 +03:00
Add Destructuring pass to the compiler
This commit is contained in:
parent
da3f2c4db3
commit
504aee3444
@ -242,6 +242,23 @@ impl<'a> Compiler<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the destructuring pass.
|
||||
pub fn destructuring_pass(&mut self, symbol_table: &SymbolTable) -> Result<()> {
|
||||
self.ast = Destructurer::do_pass((
|
||||
std::mem::take(&mut self.ast),
|
||||
symbol_table,
|
||||
&self.type_table,
|
||||
&self.node_builder,
|
||||
&self.assigner,
|
||||
))?;
|
||||
|
||||
if self.compiler_options.output.destructured_ast {
|
||||
self.write_ast_to_json("destructured_ast.json")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the function inlining pass.
|
||||
pub fn function_inlining_pass(&mut self, call_graph: &CallGraph) -> Result<()> {
|
||||
let ast = FunctionInliner::do_pass((
|
||||
@ -295,6 +312,8 @@ impl<'a> Compiler<'a> {
|
||||
|
||||
self.flattening_pass(&st)?;
|
||||
|
||||
self.destructuring_pass(&st)?;
|
||||
|
||||
self.function_inlining_pass(&call_graph)?;
|
||||
|
||||
self.dead_code_elimination_pass()?;
|
||||
|
@ -52,6 +52,8 @@ pub struct OutputOptions {
|
||||
pub ssa_ast: bool,
|
||||
/// If enabled writes the AST after flattening.
|
||||
pub flattened_ast: bool,
|
||||
/// If enabled writes the AST after destructuring.
|
||||
pub destructured_ast: bool,
|
||||
/// If enabled writes the AST after inlining.
|
||||
pub inlined_ast: bool,
|
||||
/// If enabled writes the AST after dead code elimination.
|
||||
|
@ -66,6 +66,7 @@ struct CompileOutput {
|
||||
pub unrolled_ast: String,
|
||||
pub ssa_ast: String,
|
||||
pub flattened_ast: String,
|
||||
pub destructured_ast: String,
|
||||
pub inlined_ast: String,
|
||||
pub dce_ast: String,
|
||||
pub bytecode: String,
|
||||
@ -95,6 +96,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
|
||||
unrolled_ast: true,
|
||||
ssa_ast: true,
|
||||
flattened_ast: true,
|
||||
destructured_ast: true,
|
||||
inlined_ast: true,
|
||||
dce_ast: true,
|
||||
},
|
||||
@ -116,7 +118,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
|
||||
handler.extend_if_error(package.get_process().map_err(LeoError::Anyhow))?;
|
||||
|
||||
// Hash the ast files.
|
||||
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, inlined_ast, dce_ast) = hash_asts();
|
||||
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) = hash_asts();
|
||||
|
||||
// Hash the symbol tables.
|
||||
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();
|
||||
@ -134,6 +136,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
|
||||
unrolled_ast,
|
||||
ssa_ast,
|
||||
flattened_ast,
|
||||
destructured_ast,
|
||||
inlined_ast,
|
||||
dce_ast,
|
||||
bytecode: hash_content(&bytecode),
|
||||
|
@ -74,6 +74,7 @@ struct ExecuteOutput {
|
||||
pub unrolled_ast: String,
|
||||
pub ssa_ast: String,
|
||||
pub flattened_ast: String,
|
||||
pub destructured_ast: String,
|
||||
pub inlined_ast: String,
|
||||
pub dce_ast: String,
|
||||
pub bytecode: String,
|
||||
@ -109,6 +110,7 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
|
||||
unrolled_ast: true,
|
||||
ssa_ast: true,
|
||||
flattened_ast: true,
|
||||
destructured_ast: true,
|
||||
inlined_ast: true,
|
||||
dce_ast: true,
|
||||
},
|
||||
@ -200,7 +202,7 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
|
||||
}
|
||||
|
||||
// Hash the ast files.
|
||||
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, inlined_ast, dce_ast) = hash_asts();
|
||||
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) = hash_asts();
|
||||
|
||||
// Hash the symbol tables.
|
||||
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();
|
||||
@ -218,6 +220,7 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
|
||||
unrolled_ast,
|
||||
ssa_ast,
|
||||
flattened_ast,
|
||||
destructured_ast,
|
||||
inlined_ast,
|
||||
dce_ast,
|
||||
bytecode: hash_content(&bytecode),
|
||||
|
@ -45,15 +45,16 @@ pub type Network = Testnet3;
|
||||
#[allow(unused)]
|
||||
pub type Aleo = snarkvm::circuit::AleoV0;
|
||||
|
||||
pub fn hash_asts() -> (String, String, String, String, String, String) {
|
||||
pub fn hash_asts() -> (String, String, String, String, String, String, String) {
|
||||
let initial_ast = hash_file("/tmp/output/test.initial_ast.json");
|
||||
let unrolled_ast = hash_file("/tmp/output/test.unrolled_ast.json");
|
||||
let ssa_ast = hash_file("/tmp/output/test.ssa_ast.json");
|
||||
let flattened_ast = hash_file("/tmp/output/test.flattened_ast.json");
|
||||
let destructured_ast = hash_file("/tmp/output/test.destructured_ast.json");
|
||||
let inlined_ast = hash_file("/tmp/output/test.inlined_ast.json");
|
||||
let dce_ast = hash_file("/tmp/output/test.dce_ast.json");
|
||||
|
||||
(initial_ast, unrolled_ast, ssa_ast, flattened_ast, inlined_ast, dce_ast)
|
||||
(initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast)
|
||||
}
|
||||
|
||||
pub fn hash_symbol_tables() -> (String, String, String) {
|
||||
@ -236,6 +237,8 @@ pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, L
|
||||
|
||||
parsed.flattening_pass(&st)?;
|
||||
|
||||
parsed.destructuring_pass(&st)?;
|
||||
|
||||
parsed.function_inlining_pass(&call_graph)?;
|
||||
|
||||
parsed.dead_code_elimination_pass()?;
|
||||
|
@ -34,8 +34,6 @@ use leo_ast::{
|
||||
Type,
|
||||
};
|
||||
|
||||
// TODO: Clean up logic. To be done in a follow-up PR (feat/tuples)
|
||||
|
||||
impl ExpressionReconstructor for Flattener<'_> {
|
||||
type AdditionalOutput = Vec<Statement>;
|
||||
|
||||
|
@ -26,6 +26,9 @@ pub use common::*;
|
||||
pub mod dead_code_elimination;
|
||||
pub use dead_code_elimination::*;
|
||||
|
||||
pub mod destructuring;
|
||||
pub use destructuring::*;
|
||||
|
||||
pub mod flattening;
|
||||
pub use flattening::*;
|
||||
|
||||
|
@ -1060,28 +1060,28 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
/// Emits an error if the type or its constituent types is not valid.
|
||||
pub(crate) fn assert_type_is_valid(&self, type_: &Type, span: Span) -> bool {
|
||||
let mut is_defined = true;
|
||||
let mut is_valid = true;
|
||||
match type_ {
|
||||
// String types are temporarily disabled.
|
||||
Type::String => {
|
||||
is_defined = false;
|
||||
is_valid = false;
|
||||
self.emit_err(TypeCheckerError::strings_are_not_supported(span));
|
||||
}
|
||||
// Check that the named composite type has been defined.
|
||||
Type::Identifier(identifier) if self.symbol_table.borrow().lookup_struct(identifier.name).is_none() => {
|
||||
is_defined = false;
|
||||
is_valid = false;
|
||||
self.emit_err(TypeCheckerError::undefined_type(identifier.name, span));
|
||||
}
|
||||
// Check that the constituent types of the tuple are valid.
|
||||
Type::Tuple(tuple_type) => {
|
||||
for type_ in tuple_type.elements().iter() {
|
||||
is_defined &= self.assert_type_is_valid(type_, span)
|
||||
is_valid &= self.assert_type_is_valid(type_, span)
|
||||
}
|
||||
}
|
||||
// Check that the constituent types of mapping are valid.
|
||||
Type::Mapping(mapping_type) => {
|
||||
is_defined &= self.assert_type_is_valid(&mapping_type.key, span);
|
||||
is_defined &= self.assert_type_is_valid(&mapping_type.value, span);
|
||||
is_valid &= self.assert_type_is_valid(&mapping_type.key, span);
|
||||
is_valid &= self.assert_type_is_valid(&mapping_type.value, span);
|
||||
}
|
||||
// Check that the array element types are valid.
|
||||
Type::Array(array_type) => {
|
||||
@ -1093,11 +1093,15 @@ impl<'a> TypeChecker<'a> {
|
||||
self.emit_err(TypeCheckerError::array_too_large(length, Testnet3::MAX_ARRAY_ELEMENTS, span))
|
||||
}
|
||||
}
|
||||
is_defined &= self.assert_type_is_valid(array_type.element_type(), span)
|
||||
// Check that the array element type is not a tuple.
|
||||
if let Type::Tuple(_) = array_type.element_type() {
|
||||
self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span))
|
||||
}
|
||||
is_valid &= self.assert_type_is_valid(array_type.element_type(), span)
|
||||
}
|
||||
_ => {} // Do nothing.
|
||||
}
|
||||
is_defined
|
||||
is_valid
|
||||
}
|
||||
|
||||
/// Emits an error if the type is not a mapping.
|
||||
|
@ -698,4 +698,11 @@ create_messages!(
|
||||
msg: format!("An array cannot have more than {max} elements, found one with {size} elements"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
array_element_cannot_be_tuple {
|
||||
args: (),
|
||||
msg: format!("An array cannot have a tuple as an element type"),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -53,6 +53,7 @@ impl From<BuildOptions> for CompilerOptions {
|
||||
unrolled_ast: options.enable_unrolled_ast_snapshot,
|
||||
ssa_ast: options.enable_ssa_ast_snapshot,
|
||||
flattened_ast: options.enable_flattened_ast_snapshot,
|
||||
destructured_ast: options.enable_destructured_ast_snapshot,
|
||||
inlined_ast: options.enable_inlined_ast_snapshot,
|
||||
dce_ast: options.enable_dce_ast_snapshot,
|
||||
},
|
||||
@ -63,6 +64,7 @@ impl From<BuildOptions> for CompilerOptions {
|
||||
out_options.output.unrolled_ast = true;
|
||||
out_options.output.ssa_ast = true;
|
||||
out_options.output.flattened_ast = true;
|
||||
out_options.output.destructured_ast = true;
|
||||
out_options.output.inlined_ast = true;
|
||||
out_options.output.dce_ast = true;
|
||||
}
|
||||
|
@ -145,6 +145,8 @@ pub struct BuildOptions {
|
||||
pub enable_ssa_ast_snapshot: bool,
|
||||
#[clap(long, help = "Writes AST snapshot of the flattened AST.")]
|
||||
pub enable_flattened_ast_snapshot: bool,
|
||||
#[clap(long, help = "Writes AST snapshot of the destructured AST.")]
|
||||
pub enable_destructured_ast_snapshot: bool,
|
||||
#[clap(long, help = "Writes AST snapshot of the inlined AST.")]
|
||||
pub enable_inlined_ast_snapshot: bool,
|
||||
#[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")]
|
||||
|
@ -7,9 +7,9 @@ outputs:
|
||||
unrolled_symbol_table: 583ed0adba552a2abfd5927ecebd5c20fa943380c8d0b45e00a33e7c03de3300
|
||||
initial_ast: 34a1afc5b8e850d3ca1fffbabcfb5ea6bacea945b20628868784f8a5b4140854
|
||||
unrolled_ast: 34a1afc5b8e850d3ca1fffbabcfb5ea6bacea945b20628868784f8a5b4140854
|
||||
ssa_ast: df3ca19301a9f38667d034bfdb7ae892292ffa822eaa491e72cf75730c6355be
|
||||
flattened_ast: ede7aeb18282c9c9b48b3b60212fea5fb8886321d4a0742e96b2b640129b0463
|
||||
inlined_ast: ede7aeb18282c9c9b48b3b60212fea5fb8886321d4a0742e96b2b640129b0463
|
||||
dce_ast: a53f58149602de59ef43a6987aac4e8fbec357995ca89e3d5093aedce9af73f4
|
||||
ssa_ast: bb6b1c14a80f6c148484d7e330bac0d6591163a2a98d0787f530ae5d28dcaed3
|
||||
flattened_ast: 4752b34e62f67e177c91688f03fe3f1f827420b09e586d5daccfbe19beb5ab18
|
||||
inlined_ast: 4752b34e62f67e177c91688f03fe3f1f827420b09e586d5daccfbe19beb5ab18
|
||||
dce_ast: 4d25901f577f93b7a8ab66c82774d538f648eb0d7675c3d4513e558f8a19c967
|
||||
bytecode: 4f4c5c377fed78feede8ee754c9f838f449f8d00cf771b2bb65884e876f90b7e
|
||||
warnings: ""
|
||||
|
@ -41,6 +41,8 @@ enum BenchMode {
|
||||
Ssa,
|
||||
/// Benchmarks flattening.
|
||||
Flatten,
|
||||
/// Benchmarks destructuring.
|
||||
Destructure,
|
||||
/// Benchmarks function inlining.
|
||||
Inline,
|
||||
/// Benchmarks dead code elimination.
|
||||
@ -98,6 +100,7 @@ fn new_compiler(handler: &Handler) -> Compiler<'_> {
|
||||
unrolled_ast: false,
|
||||
ssa_ast: false,
|
||||
flattened_ast: false,
|
||||
destructured_ast: false,
|
||||
inlined_ast: false,
|
||||
dce_ast: false,
|
||||
},
|
||||
@ -125,6 +128,7 @@ impl Sample {
|
||||
BenchMode::Unroll => self.bench_loop_unroller(c),
|
||||
BenchMode::Ssa => self.bench_ssa(c),
|
||||
BenchMode::Flatten => self.bench_flattener(c),
|
||||
BenchMode::Destructure => self.bench_destructurer(c),
|
||||
BenchMode::Inline => self.bench_inline(c),
|
||||
BenchMode::Dce => self.bench_dce(c),
|
||||
BenchMode::Codegen => self.bench_codegen(c),
|
||||
@ -229,6 +233,22 @@ impl Sample {
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_destructurer(&self, c: &mut Criterion) {
|
||||
self.bencher_after_parse(c, "destructurer pass", |mut compiler| {
|
||||
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
|
||||
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");
|
||||
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.destructuring_pass(&symbol_table);
|
||||
let time = start.elapsed();
|
||||
out.expect("failed to run destructurer pass");
|
||||
time
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_inline(&self, c: &mut Criterion) {
|
||||
self.bencher_after_parse(c, "inliner pass", |mut compiler| {
|
||||
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
|
||||
@ -237,6 +257,7 @@ impl Sample {
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling 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.destructuring_pass(&symbol_table).expect("failed to run destructurer pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.function_inlining_pass(&call_graph);
|
||||
let time = start.elapsed();
|
||||
@ -253,6 +274,7 @@ impl Sample {
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling 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.destructuring_pass(&symbol_table).expect("failed to run destructurer pass");
|
||||
compiler.function_inlining_pass(&call_graph).expect("failed to run inliner pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.dead_code_elimination_pass();
|
||||
@ -270,6 +292,7 @@ impl Sample {
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling 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.destructuring_pass(&symbol_table).expect("failed to run destructurer 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();
|
||||
@ -291,6 +314,7 @@ impl Sample {
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling 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.destructuring_pass(&symbol_table).expect("failed to run destructuring 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
|
||||
@ -315,6 +339,7 @@ bench!(bench_type, BenchMode::Type);
|
||||
bench!(bench_unroll, BenchMode::Unroll);
|
||||
bench!(bench_ssa, BenchMode::Ssa);
|
||||
bench!(bench_flatten, BenchMode::Flatten);
|
||||
bench!(bench_destructure, BenchMode::Destructure);
|
||||
bench!(bench_inline, BenchMode::Inline);
|
||||
bench!(bench_dce, BenchMode::Dce);
|
||||
bench!(bench_codegen, BenchMode::Codegen);
|
||||
@ -330,6 +355,7 @@ criterion_group!(
|
||||
bench_unroll,
|
||||
bench_ssa,
|
||||
bench_flatten,
|
||||
bench_destructure,
|
||||
bench_inline,
|
||||
bench_dce,
|
||||
bench_codegen,
|
||||
|
Loading…
Reference in New Issue
Block a user