From c8026d557d535b10fe455165d6445076df7a03de Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:30:22 +0000 Subject: [PATCH] feat: add support for overriding expression width (#4117) # Description ## Problem\* Resolves #3854 ## Summary\* This PR adds the `expression-width` option to the CLI which allows users to specify the expression width they want to use. Passing zero will result in an unbounded width. ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [ ] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: kevaundray --- acvm-repo/acvm/src/lib.rs | 10 +++++++ compiler/noirc_driver/src/lib.rs | 18 ++++++++++-- tooling/nargo_cli/src/cli/compile_cmd.rs | 5 +++- tooling/nargo_cli/src/cli/dap_cmd.rs | 37 +++++++++++++++++++----- tooling/nargo_cli/src/cli/debug_cmd.rs | 5 +++- tooling/nargo_cli/src/cli/execute_cmd.rs | 5 +++- tooling/nargo_cli/src/cli/info_cmd.rs | 5 +++- tooling/nargo_cli/src/cli/prove_cmd.rs | 5 +++- tooling/nargo_cli/src/cli/verify_cmd.rs | 5 +++- 9 files changed, 79 insertions(+), 16 deletions(-) diff --git a/acvm-repo/acvm/src/lib.rs b/acvm-repo/acvm/src/lib.rs index 626bb2c9b9..264479d8a1 100644 --- a/acvm-repo/acvm/src/lib.rs +++ b/acvm-repo/acvm/src/lib.rs @@ -31,3 +31,13 @@ pub enum ExpressionWidth { Unbounded, Bounded { width: usize }, } + +impl From for ExpressionWidth { + fn from(width: usize) -> ExpressionWidth { + if width == 0 { + ExpressionWidth::Unbounded + } else { + ExpressionWidth::Bounded { width } + } + } +} diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index a2570b26f3..6fd69f8b57 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -3,6 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] +use acvm::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -16,7 +17,6 @@ use noirc_frontend::hir::Context; use noirc_frontend::macros_api::MacroProcessor; use noirc_frontend::monomorphization::monomorphize; use noirc_frontend::node_interner::FuncId; -use serde::{Deserialize, Serialize}; use std::path::Path; use tracing::info; @@ -43,8 +43,12 @@ pub const NOIRC_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const NOIR_ARTIFACT_VERSION_STRING: &str = concat!(env!("CARGO_PKG_VERSION"), "+", env!("GIT_COMMIT")); -#[derive(Args, Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Args, Clone, Debug, Default)] pub struct CompileOptions { + /// Override the expression width requested by the backend. + #[arg(long, value_parser = parse_expression_width)] + pub expression_width: Option, + /// Force a full recompilation. #[arg(long = "force")] pub force_compile: bool, @@ -81,6 +85,16 @@ pub struct CompileOptions { pub show_monomorphized: bool, } +fn parse_expression_width(input: &str) -> Result { + use std::io::{Error, ErrorKind}; + + let width = input + .parse::() + .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; + + Ok(ExpressionWidth::from(width)) +} + /// Helper type used to signify where only warnings are expected in file diagnostics pub type Warnings = Vec; diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index 25cf06a731..34fb05249b 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -61,7 +61,10 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let (compiled_program, compiled_contracts) = compile_workspace( &workspace_file_manager, &parsed_files, diff --git a/tooling/nargo_cli/src/cli/dap_cmd.rs b/tooling/nargo_cli/src/cli/dap_cmd.rs index a02cd66fd4..67322b1873 100644 --- a/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,4 +1,5 @@ use acvm::acir::native_types::WitnessMap; +use acvm::ExpressionWidth; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; @@ -29,7 +30,21 @@ use crate::errors::CliError; use super::NargoConfig; #[derive(Debug, Clone, Args)] -pub(crate) struct DapCommand; +pub(crate) struct DapCommand { + /// Override the expression width requested by the backend. + #[arg(long, value_parser = parse_expression_width)] + expression_width: Option, +} + +fn parse_expression_width(input: &str) -> Result { + use std::io::{Error, ErrorKind}; + + let width = input + .parse::() + .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; + + Ok(ExpressionWidth::from(width)) +} struct LoadError(&'static str); @@ -54,16 +69,14 @@ fn find_workspace(project_folder: &str, package: Option<&str>) -> Option, prover_name: &str, + expression_width: ExpressionWidth, ) -> Result<(CompiledProgram, WitnessMap), LoadError> { let workspace = find_workspace(project_folder, package).ok_or(LoadError("Cannot open workspace"))?; - let expression_width = - backend.get_backend_info().map_err(|_| LoadError("Failed to get backend info"))?; let package = workspace .into_iter() .find(|p| p.is_binary()) @@ -100,7 +113,7 @@ fn load_and_compile_project( fn loop_uninitialized_dap( mut server: Server, - backend: &Backend, + expression_width: ExpressionWidth, ) -> Result<(), ServerError> { loop { let req = match server.poll_request()? { @@ -140,7 +153,12 @@ fn loop_uninitialized_dap( eprintln!("Package: {}", package.unwrap_or("(default)")); eprintln!("Prover name: {}", prover_name); - match load_and_compile_project(backend, project_folder, package, prover_name) { + match load_and_compile_project( + project_folder, + package, + prover_name, + expression_width, + ) { Ok((compiled_program, initial_witness)) => { server.respond(req.ack()?)?; @@ -176,12 +194,15 @@ fn loop_uninitialized_dap( pub(crate) fn run( backend: &Backend, - _args: DapCommand, + args: DapCommand, _config: NargoConfig, ) -> Result<(), CliError> { let output = BufWriter::new(std::io::stdout()); let input = BufReader::new(std::io::stdin()); let server = Server::new(input, output); - loop_uninitialized_dap(server, backend).map_err(CliError::DapError) + let expression_width = + args.expression_width.unwrap_or_else(|| backend.get_backend_info_or_default()); + + loop_uninitialized_dap(server, expression_width).map_err(CliError::DapError) } diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 58cc453e01..a0bac3bdac 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -54,7 +54,10 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; let target_dir = &workspace.target_directory_path(); - let expression_width = backend.get_backend_info()?; + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let mut workspace_file_manager = file_manager_with_stdlib(std::path::Path::new("")); insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index c1fd398350..a3fcebab94 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -68,7 +68,10 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); for package in binary_packages { let compilation_result = compile_program( diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index 0e9feaca1c..131fd6ad21 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -69,7 +69,10 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let (compiled_programs, compiled_contracts) = compile_workspace( &workspace_file_manager, &parsed_files, diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index 479ca2c945..1d20e97af8 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -69,7 +69,10 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info()?; + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); for package in binary_packages { let compilation_result = compile_program( diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index 582fa32bd8..ea4aaa051b 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -54,7 +54,10 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info()?; + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); for package in binary_packages { let compilation_result = compile_program(