diff --git a/compiler/noirc_evaluator/src/acir/acir_context/black_box.rs b/compiler/noirc_evaluator/src/acir/acir_context/black_box.rs index 7fcf4f270b6..45f349e7e68 100644 --- a/compiler/noirc_evaluator/src/acir/acir_context/black_box.rs +++ b/compiler/noirc_evaluator/src/acir/acir_context/black_box.rs @@ -1,9 +1,6 @@ -use acvm::{ - BlackBoxFunctionSolver, - acir::{ - AcirField, BlackBoxFunc, - circuit::opcodes::{ConstantOrWitnessEnum, FunctionInput}, - }, +use acvm::acir::{ + AcirField, BlackBoxFunc, + circuit::opcodes::{ConstantOrWitnessEnum, FunctionInput}, }; use iter_extended::vecmap; use num_bigint::BigUint; @@ -12,7 +9,7 @@ use crate::errors::{InternalError, RuntimeError}; use super::{AcirContext, AcirValue, AcirVar}; -impl> AcirContext { +impl AcirContext { /// Calls a Blackbox function on the given inputs and returns a given set of outputs /// to represent the result of the blackbox function. pub(crate) fn black_box_function( diff --git a/compiler/noirc_evaluator/src/acir/acir_context/brillig_call.rs b/compiler/noirc_evaluator/src/acir/acir_context/brillig_call.rs index 0cde0a2a1ef..e34817e39ed 100644 --- a/compiler/noirc_evaluator/src/acir/acir_context/brillig_call.rs +++ b/compiler/noirc_evaluator/src/acir/acir_context/brillig_call.rs @@ -1,12 +1,7 @@ -use acvm::{ - BlackBoxFunctionSolver, - acir::{ - AcirField, - brillig::Opcode as BrilligOpcode, - circuit::brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, - native_types::{Expression, Witness}, - }, - brillig_vm::{MemoryValue, VM, VMStatus}, +use acvm::acir::{ + AcirField, + circuit::brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, + native_types::{Expression, Witness}, }; use iter_extended::{try_vecmap, vecmap}; @@ -16,7 +11,7 @@ use crate::errors::{InternalError, RuntimeError}; use super::generated_acir::{BrilligStdlibFunc, PLACEHOLDER_BRILLIG_INDEX}; use super::{AcirContext, AcirDynamicArray, AcirType, AcirValue, AcirVar}; -impl> AcirContext { +impl AcirContext { /// Generates a brillig call to a handwritten section of brillig bytecode. pub(crate) fn stdlib_brillig_call( &mut self, @@ -25,14 +20,12 @@ impl> AcirContext { stdlib_func_bytecode: &GeneratedBrillig, inputs: Vec, outputs: Vec, - attempt_execution: bool, ) -> Result, RuntimeError> { self.brillig_call( predicate, stdlib_func_bytecode, inputs, outputs, - attempt_execution, false, PLACEHOLDER_BRILLIG_INDEX, Some(brillig_stdlib_func), @@ -46,7 +39,6 @@ impl> AcirContext { generated_brillig: &GeneratedBrillig, inputs: Vec, outputs: Vec, - attempt_execution: bool, unsafe_return_values: bool, brillig_function_index: BrilligFunctionId, brillig_stdlib_func: Option, @@ -90,20 +82,6 @@ impl> AcirContext { } })?; - // Optimistically try executing the brillig now, if we can complete execution they just return the results. - // This is a temporary measure pending SSA optimizations being applied to Brillig which would remove constant-input opcodes (See #2066) - // - // We do _not_ want to do this in the situation where the `main` function is unconstrained, as if execution succeeds - // the entire program will be replaced with witness constraints to its outputs. - if attempt_execution { - if let Some(brillig_outputs) = - self.execute_brillig(&generated_brillig.byte_code, &brillig_inputs, &outputs) - { - return Ok(brillig_outputs); - } - } - - // Otherwise we must generate ACIR for it and execute at runtime. let mut brillig_outputs = Vec::new(); let outputs_var = vecmap(outputs, |output| match output { AcirType::NumericType(_) => { @@ -129,8 +107,8 @@ impl> AcirContext { brillig_stdlib_func, ); - fn range_constraint_value>( - context: &mut AcirContext, + fn range_constraint_value( + context: &mut AcirContext, value: &AcirValue, ) -> Result<(), RuntimeError> { let one = context.add_constant(G::one()); @@ -247,120 +225,4 @@ impl> AcirContext { } (AcirValue::Array(array_values), witnesses) } - - fn execute_brillig( - &mut self, - code: &[BrilligOpcode], - inputs: &[BrilligInputs], - outputs_types: &[AcirType], - ) -> Option> { - let mut memory = (execute_brillig(code, &self.blackbox_solver, inputs)?).into_iter(); - - let outputs_var = vecmap(outputs_types.iter(), |output| match output { - AcirType::NumericType(_) => { - let var = self.add_constant(memory.next().expect("Missing return data").to_field()); - AcirValue::Var(var, output.clone()) - } - AcirType::Array(element_types, size) => { - self.brillig_constant_array_output(element_types, *size, &mut memory) - } - }); - - Some(outputs_var) - } - - /// Recursively create [`AcirValue`]s for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. - fn brillig_constant_array_output( - &mut self, - element_types: &[AcirType], - size: usize, - memory_iter: &mut impl Iterator>, - ) -> AcirValue { - let mut array_values = im::Vector::new(); - for _ in 0..size { - for element_type in element_types { - match element_type { - AcirType::Array(nested_element_types, nested_size) => { - let nested_acir_value = self.brillig_constant_array_output( - nested_element_types, - *nested_size, - memory_iter, - ); - array_values.push_back(nested_acir_value); - } - AcirType::NumericType(_) => { - let memory_value = - memory_iter.next().expect("ICE: Unexpected end of memory"); - let var = self.add_constant(memory_value.to_field()); - array_values.push_back(AcirValue::Var(var, element_type.clone())); - } - } - } - } - AcirValue::Array(array_values) - } -} - -/// Attempts to execute the provided [`Brillig`][`acvm::acir::brillig`] bytecode -/// -/// Returns the finished state of the Brillig VM if execution can complete. -/// -/// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig>( - code: &[BrilligOpcode], - blackbox_solver: &B, - inputs: &[BrilligInputs], -) -> Option>> { - // Set input values - let mut calldata: Vec = Vec::new(); - - // Each input represents a constant or array of constants. - // Iterate over each input and push it into registers and/or memory. - for input in inputs { - match input { - BrilligInputs::Single(expr) => { - calldata.push(*expr.to_const()?); - } - BrilligInputs::Array(expr_arr) => { - // Attempt to fetch all array input values - for expr in expr_arr.iter() { - calldata.push(*expr.to_const()?); - } - } - BrilligInputs::MemoryArray(_) => { - return None; - } - } - } - - // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. - let profiling_active = false; - let mut vm = VM::new(calldata, code, blackbox_solver, profiling_active, None); - - // Run the Brillig VM on these inputs, bytecode, etc! - let vm_status = vm.process_opcodes(); - - // Check the status of the Brillig VM. - // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. - // If it's finished then we can omit the opcode and just write in the return values. - match vm_status { - VMStatus::Finished { return_data_offset, return_data_size } => Some( - vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), - ), - VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), - VMStatus::Failure { .. } => { - // TODO: Return an error stating that the brillig function failed. - None - } - VMStatus::ForeignCallWait { .. } => { - // If execution can't complete then keep the opcode - - // TODO: We could bake in all the execution up to this point by replacing the inputs - // such that they initialize the registers/memory to the current values and then discard - // any opcodes prior to the one which performed this foreign call. - // - // Seems overkill for now however. - None - } - } } diff --git a/compiler/noirc_evaluator/src/acir/acir_context/mod.rs b/compiler/noirc_evaluator/src/acir/acir_context/mod.rs index 21d9f1d8233..f41006a7c85 100644 --- a/compiler/noirc_evaluator/src/acir/acir_context/mod.rs +++ b/compiler/noirc_evaluator/src/acir/acir_context/mod.rs @@ -8,16 +8,13 @@ //! [`AcirContext`] also tracks [`Expression`]s which have been simplified into a [`Witness`], or constant witnesses //! allowing these to be reused later in the program. -use acvm::{ - BlackBoxFunctionSolver, - acir::{ - AcirField, BlackBoxFunc, - circuit::{ - AssertionPayload, ErrorSelector, ExpressionOrMemory, ExpressionWidth, Opcode, - opcodes::{AcirFunctionId, BlockId, BlockType, MemOp}, - }, - native_types::{Expression, Witness}, +use acvm::acir::{ + AcirField, BlackBoxFunc, + circuit::{ + AssertionPayload, ErrorSelector, ExpressionOrMemory, ExpressionWidth, Opcode, + opcodes::{AcirFunctionId, BlockId, BlockType, MemOp}, }, + native_types::{Expression, Witness}, }; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::call_stack::{CallStack, CallStackHelper}; @@ -50,8 +47,7 @@ pub(crate) use generated_acir::{BrilligStdLib, BrilligStdlibFunc}; /// Context object which holds the relationship between /// `Variables`(AcirVar) and types such as `Expression` and `Witness` /// which are placed into ACIR. -pub(crate) struct AcirContext> { - pub(super) blackbox_solver: B, +pub(crate) struct AcirContext { brillig_stdlib: BrilligStdLib, vars: HashMap>, @@ -75,11 +71,10 @@ pub(crate) struct AcirContext> { pub(super) warnings: Vec, } -impl> AcirContext { - pub(super) fn new(brillig_stdlib: BrilligStdLib, blackbox_solver: B) -> Self { +impl AcirContext { + pub(super) fn new(brillig_stdlib: BrilligStdLib) -> Self { AcirContext { brillig_stdlib, - blackbox_solver, vars: Default::default(), constant_witnesses: Default::default(), acir_ir: Default::default(), @@ -302,7 +297,6 @@ impl> AcirContext { &self.brillig_stdlib.get_code(BrilligStdlibFunc::Inverse).clone(), vec![AcirValue::Var(var, AcirType::field())], vec![AcirType::field()], - true, )?; let inverted_var = Self::expect_one_var(results); @@ -898,7 +892,6 @@ impl> AcirContext { AcirValue::Var(rhs, AcirType::unsigned(bit_size)), ], vec![AcirType::unsigned(max_q_bits), AcirType::unsigned(max_rhs_bits)], - true, )? .try_into() .expect("quotient only returns two values"); diff --git a/compiler/noirc_evaluator/src/acir/mod.rs b/compiler/noirc_evaluator/src/acir/mod.rs index 4ba4d3d2bb6..a596d0721ac 100644 --- a/compiler/noirc_evaluator/src/acir/mod.rs +++ b/compiler/noirc_evaluator/src/acir/mod.rs @@ -19,7 +19,6 @@ use acvm::acir::{ native_types::Witness, }; use acvm::{FieldElement, acir::AcirField, acir::circuit::opcodes::BlockId}; -use bn254_blackbox_solver::Bn254BlackBoxSolver; use iter_extended::{try_vecmap, vecmap}; use noirc_frontend::monomorphization::ast::InlineType; @@ -183,7 +182,7 @@ struct Context<'a> { current_side_effects_enabled_var: AcirVar, /// Manages and builds the `AcirVar`s to which the converted SSA values refer. - acir_context: AcirContext, + acir_context: AcirContext, /// Track initialized acir dynamic arrays /// @@ -237,7 +236,7 @@ impl<'a> Context<'a> { brillig_stdlib: BrilligStdLib, brillig_options: &'a BrilligOptions, ) -> Context<'a> { - let mut acir_context = AcirContext::new(brillig_stdlib, Bn254BlackBoxSolver::default()); + let mut acir_context = AcirContext::new(brillig_stdlib); acir_context.set_expression_width(expression_width); let current_side_effects_enabled_var = acir_context.add_constant(FieldElement::one()); @@ -407,7 +406,6 @@ impl<'a> Context<'a> { &code, inputs, outputs, - false, true, // We are guaranteed to have a Brillig function pointer of `0` as main itself is marked as unconstrained BrilligFunctionId(0), @@ -784,7 +782,6 @@ impl<'a> Context<'a> { code, inputs, outputs, - true, false, *generated_pointer, None, @@ -803,7 +800,6 @@ impl<'a> Context<'a> { &code, inputs, outputs, - true, false, generated_pointer, None,