From c5f7c01f023a96e4ef0ddefcaaf7fc23fa703037 Mon Sep 17 00:00:00 2001 From: d0cd Date: Mon, 13 Mar 2023 09:18:42 -0700 Subject: [PATCH] Add an option to enable DCE in the compiler --- compiler/compiler/src/compiler.rs | 32 +++++++++++--------- compiler/compiler/src/options.rs | 4 ++- compiler/compiler/tests/utilities/mod.rs | 5 +-- leo/commands/build.rs | 15 +++++---- leo/commands/run.rs | 2 +- tests/test-framework/benches/leo_compiler.rs | 14 +++++++-- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/compiler/compiler/src/compiler.rs b/compiler/compiler/src/compiler.rs index 23b9808f38..4a02ec7793 100644 --- a/compiler/compiler/src/compiler.rs +++ b/compiler/compiler/src/compiler.rs @@ -30,7 +30,7 @@ use sha2::{Digest, Sha256}; use std::fs; use std::path::PathBuf; -use crate::OutputOptions; +use crate::CompilerOptions; /// The primary entry point of the Leo compiler. #[derive(Clone)] @@ -49,8 +49,8 @@ pub struct Compiler<'a> { pub ast: Ast, /// The input ast for the program if it exists. pub input_ast: Option, - /// Compiler options on some optional output files. - output_options: OutputOptions, + /// Options configuring compilation. + compiler_options: CompilerOptions, } impl<'a> Compiler<'a> { @@ -61,7 +61,7 @@ impl<'a> Compiler<'a> { handler: &'a Handler, main_file_path: PathBuf, output_directory: PathBuf, - output_options: Option, + compiler_options: Option, ) -> Self { Self { handler, @@ -71,7 +71,7 @@ impl<'a> Compiler<'a> { network, ast: Ast::new(Program::default()), input_ast: None, - output_options: output_options.unwrap_or_default(), + compiler_options: compiler_options.unwrap_or_default(), } } @@ -111,7 +111,7 @@ impl<'a> Compiler<'a> { .into()); } - if self.output_options.initial_ast { + if self.compiler_options.initial_ast { self.write_ast_to_json("initial_ast.json")?; } @@ -136,9 +136,9 @@ impl<'a> Compiler<'a> { // Parse and serialize it. let input_ast = leo_parser::parse_input(self.handler, &input_sf.src, input_sf.start_pos)?; - if self.output_options.initial_ast { + if self.compiler_options.initial_ast { // Write the input AST snapshot post parsing. - if self.output_options.spans_enabled { + if self.compiler_options.spans_enabled { input_ast.to_json_file( self.output_directory.clone(), &format!("{}.initial_input_ast.json", self.program_name), @@ -172,7 +172,7 @@ impl<'a> Compiler<'a> { let (ast, symbol_table) = Unroller::do_pass((std::mem::take(&mut self.ast), self.handler, symbol_table))?; self.ast = ast; - if self.output_options.unrolled_ast { + if self.compiler_options.unrolled_ast { self.write_ast_to_json("unrolled_ast.json")?; } @@ -184,7 +184,7 @@ impl<'a> Compiler<'a> { let (ast, assigner) = StaticSingleAssigner::do_pass((std::mem::take(&mut self.ast), symbol_table))?; self.ast = ast; - if self.output_options.ssa_ast { + if self.compiler_options.ssa_ast { self.write_ast_to_json("ssa_ast.json")?; } @@ -196,7 +196,7 @@ impl<'a> Compiler<'a> { let (ast, assigner) = Flattener::do_pass((std::mem::take(&mut self.ast), symbol_table, assigner))?; self.ast = ast; - if self.output_options.flattened_ast { + if self.compiler_options.flattened_ast { self.write_ast_to_json("flattened_ast.json")?; } @@ -208,7 +208,7 @@ impl<'a> Compiler<'a> { let (ast, assigner) = FunctionInliner::do_pass((std::mem::take(&mut self.ast), call_graph, assigner))?; self.ast = ast; - if self.output_options.inlined_ast { + if self.compiler_options.inlined_ast { self.write_ast_to_json("inlined_ast.json")?; } @@ -217,9 +217,11 @@ impl<'a> Compiler<'a> { /// Runs the dead code elimination pass. pub fn dead_code_elimination_pass(&mut self) -> Result<()> { - self.ast = DeadCodeEliminator::do_pass(std::mem::take(&mut self.ast))?; + if self.compiler_options.dce_enabled { + self.ast = DeadCodeEliminator::do_pass(std::mem::take(&mut self.ast))?; + } - if self.output_options.dce_ast { + if self.compiler_options.dce_ast { self.write_ast_to_json("dce_ast.json")?; } @@ -266,7 +268,7 @@ impl<'a> Compiler<'a> { /// Writes the AST to a JSON file. fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> { // Remove `Span`s if they are not enabled. - if self.output_options.spans_enabled { + if self.compiler_options.spans_enabled { self.ast.to_json_file( self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name), diff --git a/compiler/compiler/src/options.rs b/compiler/compiler/src/options.rs index a6af589c81..6dbc5f825d 100644 --- a/compiler/compiler/src/options.rs +++ b/compiler/compiler/src/options.rs @@ -17,9 +17,11 @@ // NOTE: If compiler passes are made optional, pass preconditions and invariants may not necessarily hold true. #[derive(Clone, Default)] -pub struct OutputOptions { +pub struct CompilerOptions { /// Whether spans are enabled in the output ASTs. pub spans_enabled: bool, + /// Whether to enable dead code elimination. + pub dce_enabled: bool, /// If enabled writes the AST after parsing. pub initial_ast: bool, /// If enabled writes the input AST after parsing. diff --git a/compiler/compiler/tests/utilities/mod.rs b/compiler/compiler/tests/utilities/mod.rs index 861cf28a26..18ca04f589 100644 --- a/compiler/compiler/tests/utilities/mod.rs +++ b/compiler/compiler/tests/utilities/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use leo_compiler::{Compiler, OutputOptions}; +use leo_compiler::{Compiler, CompilerOptions}; use leo_errors::{ emitter::{Buffer, Emitter, Handler}, LeoError, LeoWarning, @@ -95,8 +95,9 @@ pub fn new_compiler(handler: &Handler, main_file_path: PathBuf) -> Compiler<'_> handler, main_file_path, output_dir, - Some(OutputOptions { + Some(CompilerOptions { spans_enabled: false, + dce_enabled: true, initial_input_ast: true, initial_ast: true, unrolled_ast: true, diff --git a/leo/commands/build.rs b/leo/commands/build.rs index cb7981766c..0cc13ad659 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -18,7 +18,7 @@ use crate::commands::ALEO_CLI_COMMAND; use crate::{commands::Command, context::Context}; use leo_ast::Struct; -use leo_compiler::{Compiler, InputAst, OutputOptions}; +use leo_compiler::{Compiler, CompilerOptions, InputAst}; use leo_errors::{CliError, CompilerError, PackageError, Result}; use leo_package::source::SourceDirectory; use leo_package::{inputs::InputFile, outputs::OutputsDirectory}; @@ -46,6 +46,8 @@ pub struct BuildOptions { pub offline: bool, #[structopt(long, help = "Enable spans in AST snapshots.")] pub enable_spans: bool, + #[structopt(long, help = "Enables dead code elimination in the compiler.")] + pub enable_dce: bool, #[structopt(long, help = "Writes all AST snapshots for the different compiler phases.")] pub enable_all_ast_snapshots: bool, #[structopt(long, help = "Writes Input AST snapshot of the initial parse.")] @@ -64,10 +66,11 @@ pub struct BuildOptions { pub enable_dce_ast_snapshot: bool, } -impl From for OutputOptions { +impl From for CompilerOptions { fn from(options: BuildOptions) -> Self { let mut out_options = Self { spans_enabled: options.enable_spans, + dce_enabled: options.enable_dce, initial_input_ast: options.enable_initial_input_ast_snapshot, initial_ast: options.enable_initial_ast_snapshot, unrolled_ast: options.enable_unrolled_ast_snapshot, @@ -94,7 +97,7 @@ impl From for OutputOptions { #[derive(StructOpt, Debug)] pub struct Build { #[structopt(flatten)] - pub(crate) compiler_options: BuildOptions, + pub(crate) options: BuildOptions, } impl Command for Build { @@ -144,7 +147,7 @@ impl Command for Build { &outputs_directory, &build_directory, &handler, - self.compiler_options.clone(), + self.options.clone(), false, )?); } @@ -165,7 +168,7 @@ impl Command for Build { &outputs_directory, &build_imports_directory, &handler, - self.compiler_options.clone(), + self.options.clone(), true, )?); } @@ -197,7 +200,7 @@ impl Command for Build { // Call the `aleo build` command with the appropriate from the Aleo SDK. let mut args = vec![ALEO_CLI_COMMAND]; - if self.compiler_options.offline { + if self.options.offline { args.push("--offline"); } let command = AleoBuild::try_parse_from(&args).map_err(CliError::failed_to_execute_aleo_build)?; diff --git a/leo/commands/run.rs b/leo/commands/run.rs index 81bea8135b..b099e83cef 100644 --- a/leo/commands/run.rs +++ b/leo/commands/run.rs @@ -54,7 +54,7 @@ impl Command for Run { fn prelude(&self, context: Context) -> Result { (Build { - compiler_options: self.compiler_options.clone(), + options: self.compiler_options.clone(), }) .execute(context) } diff --git a/tests/test-framework/benches/leo_compiler.rs b/tests/test-framework/benches/leo_compiler.rs index 6c01328c30..75462f0d70 100644 --- a/tests/test-framework/benches/leo_compiler.rs +++ b/tests/test-framework/benches/leo_compiler.rs @@ -16,7 +16,7 @@ //! This file contains tools for benchmarking the Leo compiler and its stages. -use leo_compiler::Compiler; +use leo_compiler::{Compiler, CompilerOptions}; use leo_errors::emitter::{Emitter, Handler}; use leo_span::{source_map::FileName, symbol::SESSION_GLOBALS}; use leo_test_framework::get_benches; @@ -84,7 +84,17 @@ fn new_compiler(handler: &Handler) -> Compiler<'_> { handler, PathBuf::from(String::new()), PathBuf::from(String::new()), - None, + Some(CompilerOptions { + spans_enabled: false, + dce_enabled: true, + initial_ast: false, + initial_input_ast: false, + unrolled_ast: false, + ssa_ast: false, + flattened_ast: false, + inlined_ast: false, + dce_ast: false, + }), ) }