From e1a84d24adb6b3aeb9faeb59f5726929c18ad56c Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 26 Jun 2024 21:10:24 +0000 Subject: [PATCH 1/3] chore: pull out noir-lang/noir#5120 --- .../circuits/assert_lt/src/main.nr | 3 - .../circuits/recursion/src/main.nr | 2 - .../src/brillig/brillig_gen.rs | 7 +- .../brillig/brillig_gen/brillig_black_box.rs | 19 +- .../src/brillig/brillig_gen/brillig_block.rs | 6 +- .../brillig_gen/brillig_block_variables.rs | 13 +- .../brillig/brillig_gen/brillig_directive.rs | 15 +- .../src/brillig/brillig_gen/brillig_fn.rs | 2 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 4 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 24 +- .../src/brillig/brillig_ir/artifact.rs | 26 +- .../src/brillig/brillig_ir/codegen_binary.rs | 8 +- .../src/brillig/brillig_ir/codegen_calls.rs | 7 +- .../brillig_ir/codegen_control_flow.rs | 27 +- .../brillig/brillig_ir/codegen_intrinsic.rs | 12 +- .../src/brillig/brillig_ir/codegen_memory.rs | 5 +- .../src/brillig/brillig_ir/codegen_stack.rs | 6 +- .../src/brillig/brillig_ir/debug_show.rs | 8 +- .../src/brillig/brillig_ir/entry_point.rs | 45 ++-- .../src/brillig/brillig_ir/instructions.rs | 38 ++- .../src/brillig/brillig_ir/registers.rs | 2 +- .../noirc_evaluator/src/brillig/mod.rs | 11 +- .../compiler/noirc_evaluator/src/ssa.rs | 5 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 239 ++++++++++-------- .../src/ssa/acir_gen/acir_ir/big_int.rs | 16 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 71 +++--- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 35 +-- .../src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- 28 files changed, 340 insertions(+), 318 deletions(-) diff --git a/noir/noir-repo/compiler/integration-tests/circuits/assert_lt/src/main.nr b/noir/noir-repo/compiler/integration-tests/circuits/assert_lt/src/main.nr index b8e255ca492..47e229d6c8b 100644 --- a/noir/noir-repo/compiler/integration-tests/circuits/assert_lt/src/main.nr +++ b/noir/noir-repo/compiler/integration-tests/circuits/assert_lt/src/main.nr @@ -1,10 +1,7 @@ -use dep::std; - fn main(x: u64, y: pub u64) -> pub u64 { // We include a println statement to show that noirJS will ignore this and continue execution std::println("foo"); - assert(x < y); x + y } diff --git a/noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr b/noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr index 173207766fb..94cae14daa7 100644 --- a/noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr +++ b/noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr @@ -1,5 +1,3 @@ -use dep::std; - fn main( verification_key: [Field; 114], proof: [Field; 93], diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs index 5576d673f1d..ee61a9d13d3 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs @@ -6,12 +6,17 @@ pub(crate) mod brillig_fn; pub(crate) mod brillig_slice_ops; mod variable_liveness; +use acvm::FieldElement; + use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext}; use super::brillig_ir::{artifact::BrilligArtifact, BrilligContext}; use crate::ssa::ir::function::Function; /// Converting an SSA function into Brillig bytecode. -pub(crate) fn convert_ssa_function(func: &Function, enable_debug_trace: bool) -> BrilligArtifact { +pub(crate) fn convert_ssa_function( + func: &Function, + enable_debug_trace: bool, +) -> BrilligArtifact { let mut brillig_context = BrilligContext::new(enable_debug_trace); let mut function_context = FunctionContext::new(func); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index f56c5daf315..367cdbe4973 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,18 +1,19 @@ use acvm::{ acir::{brillig::BlackBoxOp, BlackBoxFunc}, - FieldElement, + AcirField, }; use crate::brillig::brillig_ir::{ brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, BrilligBinaryOp, BrilligContext, }; /// Transforms SSA's black box function calls into the corresponding brillig instructions /// Extracting arguments and results from the SSA function call /// And making any necessary type conversions to adapt noir's blackbox calls to brillig's -pub(crate) fn convert_black_box_call( - brillig_context: &mut BrilligContext, +pub(crate) fn convert_black_box_call( + brillig_context: &mut BrilligContext, bb_func: &BlackBoxFunc, function_arguments: &[BrilligVariable], function_results: &[BrilligVariable], @@ -341,7 +342,7 @@ pub(crate) fn convert_black_box_call( let inputs_vector = convert_array_or_vector(brillig_context, inputs, bb_func); let modulus_vector = convert_array_or_vector(brillig_context, modulus, bb_func); let output_id = brillig_context.get_new_bigint_id(); - brillig_context.const_instruction(*output, FieldElement::from(output_id as u128)); + brillig_context.const_instruction(*output, F::from(output_id as u128)); brillig_context.black_box_op_instruction(BlackBoxOp::BigIntFromLeBytes { inputs: inputs_vector.to_heap_vector(), modulus: modulus_vector.to_heap_vector(), @@ -426,8 +427,8 @@ pub(crate) fn convert_black_box_call( } } -fn convert_array_or_vector( - brillig_context: &mut BrilligContext, +fn convert_array_or_vector( + brillig_context: &mut BrilligContext, array_or_vector: &BrilligVariable, bb_func: &BlackBoxFunc, ) -> BrilligVector { @@ -442,8 +443,8 @@ fn convert_array_or_vector( } } -fn prepare_bigint_output( - brillig_context: &mut BrilligContext, +fn prepare_bigint_output( + brillig_context: &mut BrilligContext, lhs_modulus: &SingleAddrVariable, rhs_modulus: &SingleAddrVariable, output: &SingleAddrVariable, @@ -465,6 +466,6 @@ fn prepare_bigint_output( brillig_context.deallocate_register(condition); // Set output id let output_id = brillig_context.get_new_bigint_id(); - brillig_context.const_instruction(*output, FieldElement::from(output_id as u128)); + brillig_context.const_instruction(*output, F::from(output_id as u128)); brillig_context.mov_instruction(modulus_id.address, lhs_modulus.address); } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 1fa4f41b29c..df7112d437d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -33,7 +33,7 @@ pub(crate) struct BrilligBlock<'block> { /// The basic block that is being converted pub(crate) block_id: BasicBlockId, /// Context for creating brillig opcodes - pub(crate) brillig_context: &'block mut BrilligContext, + pub(crate) brillig_context: &'block mut BrilligContext, /// Tracks the available variable during the codegen of the block pub(crate) variables: BlockVariables, /// For each instruction, the set of values that are not used anymore after it. @@ -44,7 +44,7 @@ impl<'block> BrilligBlock<'block> { /// Converts an SSA Basic block into a sequence of Brillig opcodes pub(crate) fn compile( function_context: &'block mut FunctionContext, - brillig_context: &'block mut BrilligContext, + brillig_context: &'block mut BrilligContext, block_id: BasicBlockId, dfg: &DataFlowGraph, ) { @@ -944,7 +944,7 @@ impl<'block> BrilligBlock<'block> { } pub(crate) fn store_variable_in_array_with_ctx( - ctx: &mut BrilligContext, + ctx: &mut BrilligContext, destination_pointer: MemoryAddress, index_register: SingleAddrVariable, value_variable: BrilligVariable, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index fb9a8577d94..ffbca256d28 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -1,3 +1,4 @@ +use acvm::FieldElement; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ @@ -50,7 +51,7 @@ impl BlockVariables { pub(crate) fn define_variable( &mut self, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, ) -> BrilligVariable { @@ -70,7 +71,7 @@ impl BlockVariables { pub(crate) fn define_single_addr_variable( &mut self, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value: ValueId, dfg: &DataFlowGraph, ) -> SingleAddrVariable { @@ -83,7 +84,7 @@ impl BlockVariables { &mut self, value_id: &ValueId, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, ) { assert!(self.available_variables.remove(value_id), "ICE: Variable is not available"); let variable = function_context @@ -122,7 +123,7 @@ impl BlockVariables { /// We keep constants block-local. pub(crate) fn allocate_constant( &mut self, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, ) -> BrilligVariable { @@ -154,9 +155,9 @@ pub(crate) fn compute_array_length(item_typ: &CompositeType, elem_count: usize) } /// For a given value_id, allocates the necessary registers to hold it. -pub(crate) fn allocate_value( +pub(crate) fn allocate_value( value_id: ValueId, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, dfg: &DataFlowGraph, ) -> BrilligVariable { let typ = dfg.type_of_value(value_id); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 74319595795..ae159f2c45c 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,13 +1,12 @@ use acvm::{ acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode}, acir::AcirField, - FieldElement, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; /// Generates brillig bytecode which computes the inverse of its input if not null, and zero else. -pub(crate) fn directive_invert() -> GeneratedBrillig { +pub(crate) fn directive_invert() -> GeneratedBrillig { // We generate the following code: // fn invert(x : Field) -> Field { // 1/ x @@ -28,8 +27,8 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // Put value zero in register (2) BrilligOpcode::Const { destination: zero_const, - value: FieldElement::from(0_usize), - bit_size: FieldElement::max_num_bits(), + value: F::from(0_usize), + bit_size: F::max_num_bits(), }, BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, @@ -42,8 +41,8 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // Put value one in register (1) BrilligOpcode::Const { destination: one_const, - value: FieldElement::from(1_usize), - bit_size: FieldElement::max_num_bits(), + value: F::one(), + bit_size: F::max_num_bits(), }, // Divide 1 by the input, and set the result of the division into register (0) BrilligOpcode::BinaryFieldOp { @@ -68,13 +67,13 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { /// (a/b, a-a/b*b) /// } /// ``` -pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { +pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { // `a` is (0) (i.e register index 0) // `b` is (1) // TODO: The only difference between these implementations is the integer version will truncate the input to the `bit_size` via cast. // Once we deduplicate brillig functions then we can modify this so that fields and integers share the same quotient function. - if bit_size >= FieldElement::max_num_bits() { + if bit_size >= F::max_num_bits() { // Field version GeneratedBrillig { byte_code: vec![ diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 000d1230ece..f0752c80c46 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -28,7 +28,7 @@ pub(crate) struct FunctionContext { } impl FunctionContext { - /// Creates a new function context. It will compute the liveness of every variable. + /// Creates a new function context. It will allocate parameters for all blocks and compute the liveness of every variable. pub(crate) fn new(function: &Function) -> Self { let id = function.id(); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 491086e8c0f..d17b15a13b5 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -372,7 +372,7 @@ mod tests { use crate::ssa::ir::map::Id; use crate::ssa::ssa_gen::Ssa; - fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { + fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { let mut builder = FunctionBuilder::new("main".to_string(), Id::test_new(0)); builder.set_runtime(RuntimeType::Brillig); @@ -385,7 +385,7 @@ mod tests { fn create_brillig_block<'a>( function_context: &'a mut FunctionContext, - brillig_context: &'a mut BrilligContext, + brillig_context: &'a mut BrilligContext, ) -> BrilligBlock<'a> { let variables = BlockVariables::default(); BrilligBlock { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index ebccf7a0bf1..9785e073be9 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -25,11 +25,13 @@ mod instructions; pub(crate) use instructions::BrilligBinaryOp; -use self::{artifact::BrilligArtifact, registers::BrilligRegistersContext}; +use self::{ + artifact::BrilligArtifact, debug_show::DebugToString, registers::BrilligRegistersContext, +}; use crate::ssa::ir::dfg::CallStack; use acvm::{ acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, - FieldElement, + AcirField, }; use debug_show::DebugShow; @@ -76,8 +78,8 @@ impl ReservedRegisters { /// Brillig context object that is used while constructing the /// Brillig bytecode. -pub(crate) struct BrilligContext { - obj: BrilligArtifact, +pub(crate) struct BrilligContext { + obj: BrilligArtifact, /// Tracks register allocations registers: BrilligRegistersContext, /// Context label, must be unique with respect to the function @@ -93,9 +95,9 @@ pub(crate) struct BrilligContext { bigint_new_id: u32, } -impl BrilligContext { +impl BrilligContext { /// Initial context state - pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext { + pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext { BrilligContext { obj: BrilligArtifact::default(), registers: BrilligRegistersContext::new(), @@ -113,12 +115,12 @@ impl BrilligContext { result } /// Adds a brillig instruction to the brillig byte code - fn push_opcode(&mut self, opcode: BrilligOpcode) { + fn push_opcode(&mut self, opcode: BrilligOpcode) { self.obj.push_opcode(opcode); } /// Returns the artifact - pub(crate) fn artifact(self) -> BrilligArtifact { + pub(crate) fn artifact(self) -> BrilligArtifact { self.obj } @@ -200,17 +202,17 @@ pub(crate) mod tests { } } - pub(crate) fn create_context() -> BrilligContext { + pub(crate) fn create_context() -> BrilligContext { let mut context = BrilligContext::new(true); context.enter_context("test"); context } pub(crate) fn create_entry_point_bytecode( - context: BrilligContext, + context: BrilligContext, arguments: Vec, returns: Vec, - ) -> GeneratedBrillig { + ) -> GeneratedBrillig { let artifact = context.artifact(); let mut entry_point_artifact = BrilligContext::new_entry_point_artifact(arguments, returns, "test".to_string()); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 99e922c1580..2d0bdb5955c 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -1,4 +1,4 @@ -use acvm::{acir::brillig::Opcode as BrilligOpcode, FieldElement}; +use acvm::acir::brillig::Opcode as BrilligOpcode; use std::collections::{BTreeMap, HashMap}; use crate::ssa::ir::dfg::CallStack; @@ -18,8 +18,8 @@ pub(crate) enum BrilligParameter { /// The result of compiling and linking brillig artifacts. /// This is ready to run bytecode with attached metadata. #[derive(Debug, Default)] -pub(crate) struct GeneratedBrillig { - pub(crate) byte_code: Vec>, +pub(crate) struct GeneratedBrillig { + pub(crate) byte_code: Vec>, pub(crate) locations: BTreeMap, pub(crate) assert_messages: BTreeMap, } @@ -27,8 +27,8 @@ pub(crate) struct GeneratedBrillig { #[derive(Default, Debug, Clone)] /// Artifacts resulting from the compilation of a function into brillig byte code. /// It includes the bytecode of the function and all the metadata that allows linking with other functions. -pub(crate) struct BrilligArtifact { - pub(crate) byte_code: Vec>, +pub(crate) struct BrilligArtifact { + pub(crate) byte_code: Vec>, /// A map of bytecode positions to assertion messages. /// Some error messages (compiler intrinsics) are not emitted via revert data, /// instead, they are handled externally so they don't add size to user programs. @@ -73,9 +73,9 @@ pub(crate) type JumpInstructionPosition = OpcodeLocation; /// to their position in the bytecode. pub(crate) type UnresolvedJumpLocation = Label; -impl BrilligArtifact { +impl BrilligArtifact { /// Resolves all jumps and generates the final bytecode - pub(crate) fn finish(mut self) -> GeneratedBrillig { + pub(crate) fn finish(mut self) -> GeneratedBrillig { self.resolve_jumps(); GeneratedBrillig { byte_code: self.byte_code, @@ -94,7 +94,7 @@ impl BrilligArtifact { /// This method will offset the positions in the Brillig artifact to /// account for the fact that it is being appended to the end of this /// Brillig artifact (self). - pub(crate) fn link_with(&mut self, obj: &BrilligArtifact) { + pub(crate) fn link_with(&mut self, obj: &BrilligArtifact) { // Add the unresolved jumps of the linked function to this artifact. self.add_unresolved_jumps_and_calls(obj); @@ -128,7 +128,7 @@ impl BrilligArtifact { } /// Adds unresolved jumps & function calls from another artifact offset by the current opcode count in the artifact. - fn add_unresolved_jumps_and_calls(&mut self, obj: &BrilligArtifact) { + fn add_unresolved_jumps_and_calls(&mut self, obj: &BrilligArtifact) { let offset = self.index_of_next_opcode(); for (jump_label, jump_location) in &obj.unresolved_jumps { self.unresolved_jumps.push((jump_label + offset, jump_location.clone())); @@ -154,7 +154,7 @@ impl BrilligArtifact { } /// Adds a brillig instruction to the brillig byte code - pub(crate) fn push_opcode(&mut self, opcode: BrilligOpcode) { + pub(crate) fn push_opcode(&mut self, opcode: BrilligOpcode) { if !self.call_stack.is_empty() { self.locations.insert(self.index_of_next_opcode(), self.call_stack.clone()); } @@ -164,7 +164,7 @@ impl BrilligArtifact { /// Adds a unresolved jump to be fixed at the end of bytecode processing. pub(crate) fn add_unresolved_jump( &mut self, - jmp_instruction: BrilligOpcode, + jmp_instruction: BrilligOpcode, destination: UnresolvedJumpLocation, ) { assert!( @@ -178,7 +178,7 @@ impl BrilligArtifact { /// Adds a unresolved external call that will be fixed once linking has been done. pub(crate) fn add_unresolved_external_call( &mut self, - call_instruction: BrilligOpcode, + call_instruction: BrilligOpcode, destination: UnresolvedJumpLocation, ) { // TODO: Add a check to ensure that the opcode is a call instruction @@ -188,7 +188,7 @@ impl BrilligArtifact { } /// Returns true if the opcode is a jump instruction - fn is_jmp_instruction(instruction: &BrilligOpcode) -> bool { + fn is_jmp_instruction(instruction: &BrilligOpcode) -> bool { matches!( instruction, BrilligOpcode::JumpIfNot { .. } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs index 4ef279bd532..a9c4f238491 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs @@ -1,8 +1,8 @@ -use acvm::{acir::brillig::MemoryAddress, FieldElement}; +use acvm::{acir::brillig::MemoryAddress, AcirField}; -use super::{instructions::BrilligBinaryOp, BrilligContext}; +use super::{debug_show::DebugToString, instructions::BrilligBinaryOp, BrilligContext}; -impl BrilligContext { +impl BrilligContext { /// Utility method to perform a binary instruction with a constant value in place pub(crate) fn codegen_usize_op_in_place( &mut self, @@ -21,7 +21,7 @@ impl BrilligContext { op: BrilligBinaryOp, constant: usize, ) { - let const_register = self.make_usize_constant_instruction(FieldElement::from(constant)); + let const_register = self.make_usize_constant_instruction(F::from(constant)); self.memory_op_instruction(operand, const_register.address, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_single_addr(const_register); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs index db65849a6b8..2d93cf70181 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs @@ -1,10 +1,11 @@ -use acvm::acir::brillig::MemoryAddress; +use acvm::{acir::brillig::MemoryAddress, AcirField}; use super::{ - brillig_variable::BrilligVariable, BrilligBinaryOp, BrilligContext, ReservedRegisters, + brillig_variable::BrilligVariable, debug_show::DebugToString, BrilligBinaryOp, BrilligContext, + ReservedRegisters, }; -impl BrilligContext { +impl BrilligContext { /// Saves all of the registers that have been used up until this point. fn codegen_save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { // Save all of the used registers at this point in memory diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs index fee3a450119..10badcd7308 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -1,12 +1,16 @@ -use acvm::acir::brillig::{HeapArray, MemoryAddress}; +use acvm::{ + acir::brillig::{HeapArray, MemoryAddress}, + AcirField, +}; use super::{ artifact::BrilligParameter, brillig_variable::{BrilligVariable, SingleAddrVariable}, + debug_show::DebugToString, BrilligBinaryOp, BrilligContext, ReservedRegisters, }; -impl BrilligContext { +impl BrilligContext { /// Codegens a return from the current function. /// /// For Brillig, the return is implicit, since there is no explicit return instruction. @@ -36,10 +40,11 @@ impl BrilligContext { /// This codegen will issue a loop that will iterate iteration_count times /// The body of the loop should be issued by the caller in the on_iteration closure. - pub(crate) fn codegen_loop(&mut self, iteration_count: MemoryAddress, on_iteration: F) - where - F: FnOnce(&mut BrilligContext, SingleAddrVariable), - { + pub(crate) fn codegen_loop( + &mut self, + iteration_count: MemoryAddress, + on_iteration: impl FnOnce(&mut BrilligContext, SingleAddrVariable), + ) { let iterator_register = self.make_usize_constant_instruction(0_u128.into()); let (loop_section, loop_label) = self.reserve_next_section_label(); @@ -87,7 +92,7 @@ impl BrilligContext { pub(crate) fn codegen_branch( &mut self, condition: MemoryAddress, - mut f: impl FnMut(&mut BrilligContext, bool), + mut f: impl FnMut(&mut BrilligContext, bool), ) { // Reserve 3 sections let (then_section, then_label) = self.reserve_next_section_label(); @@ -112,7 +117,7 @@ impl BrilligContext { pub(crate) fn codegen_if( &mut self, condition: MemoryAddress, - f: impl FnOnce(&mut BrilligContext), + f: impl FnOnce(&mut BrilligContext), ) { let (end_section, end_label) = self.reserve_next_section_label(); let (then_section, then_label) = self.reserve_next_section_label(); @@ -130,7 +135,7 @@ impl BrilligContext { pub(crate) fn codegen_if_not( &mut self, condition: MemoryAddress, - f: impl FnOnce(&mut BrilligContext), + f: impl FnOnce(&mut BrilligContext), ) { let (end_section, end_label) = self.reserve_next_section_label(); @@ -156,7 +161,7 @@ impl BrilligContext { let revert_data = HeapArray { pointer: ctx.allocate_register(), // + 1 due to the revert data id being the first item returned - size: BrilligContext::flattened_tuple_size(&revert_data_types) + 1, + size: Self::flattened_tuple_size(&revert_data_types) + 1, }; ctx.codegen_allocate_fixed_length_array(revert_data.pointer, revert_data.size); @@ -169,7 +174,7 @@ impl BrilligContext { for (revert_variable, revert_param) in revert_data_items.into_iter().zip(revert_data_types.into_iter()) { - let flattened_size = BrilligContext::flattened_size(&revert_param); + let flattened_size = Self::flattened_size(&revert_param); match revert_param { BrilligParameter::SingleAddr(_) => { ctx.store_instruction( diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index 42f3b34aea0..b1cb2b19764 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -1,15 +1,15 @@ use acvm::{ acir::brillig::{BlackBoxOp, HeapArray}, acir::AcirField, - FieldElement, }; use super::{ brillig_variable::{BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, BrilligContext, }; -impl BrilligContext { +impl BrilligContext { /// Codegens a truncation of a value to the given bit size pub(crate) fn codegen_truncate( &mut self, @@ -43,7 +43,7 @@ impl BrilligContext { big_endian: bool, limb_bit_size: u32, ) { - assert!(source_field.bit_size == FieldElement::max_num_bits()); + assert!(source_field.bit_size == F::max_num_bits()); self.usize_const_instruction(target_vector.size, limb_count.into()); self.usize_const_instruction(target_vector.rc, 1_usize.into()); @@ -55,12 +55,10 @@ impl BrilligContext { output: HeapArray { pointer: target_vector.pointer, size: limb_count }, }); - let limb_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - + let limb_field = SingleAddrVariable::new(self.allocate_register(), F::max_num_bits()); let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); - if limb_bit_size != FieldElement::max_num_bits() { + if limb_bit_size != F::max_num_bits() { self.codegen_loop(target_vector.size, |ctx, iterator_register| { // Read the limb ctx.codegen_array_get(target_vector.pointer, iterator_register, limb_field.address); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs index 15761113f51..81c1c3847b1 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs @@ -1,13 +1,14 @@ -use acvm::acir::brillig::MemoryAddress; +use acvm::{acir::brillig::MemoryAddress, AcirField}; use crate::brillig::brillig_ir::BrilligBinaryOp; use super::{ brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; -impl BrilligContext { +impl BrilligContext { /// Allocates an array of size `size` and stores the pointer to the array /// in `pointer_register` pub(crate) fn codegen_allocate_fixed_length_array( diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs index 1c30f0f848f..943b0b9d7a3 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs @@ -1,8 +1,8 @@ -use acvm::acir::brillig::MemoryAddress; +use acvm::{acir::brillig::MemoryAddress, AcirField}; -use super::BrilligContext; +use super::{debug_show::DebugToString, BrilligContext}; -impl BrilligContext { +impl BrilligContext { /// This function moves values from a set of registers to another set of registers. /// It first moves all sources to new allocated registers to avoid overwriting. pub(crate) fn codegen_mov_registers_to_registers( diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index def91f82bfd..b258905d657 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -8,7 +8,7 @@ use acvm::{ }; /// Trait for converting values into debug-friendly strings. -trait DebugToString { +pub(crate) trait DebugToString { fn debug_to_string(&self) -> String; } @@ -59,8 +59,8 @@ impl DebugToString for BrilligBinaryOp { BrilligBinaryOp::UnsignedDiv => "/".into(), BrilligBinaryOp::LessThan => "<".into(), BrilligBinaryOp::LessThanEquals => "<=".into(), - BrilligBinaryOp::And => "&&".into(), - BrilligBinaryOp::Or => "||".into(), + BrilligBinaryOp::And => "&".into(), + BrilligBinaryOp::Or => "|".into(), BrilligBinaryOp::Xor => "^".into(), BrilligBinaryOp::Shl => "<<".into(), BrilligBinaryOp::Shr => ">>".into(), @@ -169,7 +169,7 @@ impl DebugShow { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: FieldElement) { + pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: F) { debug_println!(self.enable_debug_trace, " CONST {} = {}", result, constant); } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 9023183eb36..dc06c2fa0d7 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -1,21 +1,21 @@ use super::{ artifact::{BrilligArtifact, BrilligParameter}, brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, - debug_show::DebugShow, + debug_show::{DebugShow, DebugToString}, registers::BrilligRegistersContext, BrilligBinaryOp, BrilligContext, ReservedRegisters, }; -use acvm::{acir::brillig::MemoryAddress, acir::AcirField, FieldElement}; +use acvm::{acir::brillig::MemoryAddress, acir::AcirField}; pub(crate) const MAX_STACK_SIZE: usize = 2048; -impl BrilligContext { +impl BrilligContext { /// Creates an entry point artifact that will jump to the function label provided. pub(crate) fn new_entry_point_artifact( arguments: Vec, return_parameters: Vec, target_function: T, - ) -> BrilligArtifact { + ) -> BrilligArtifact { let mut context = BrilligContext { obj: BrilligArtifact::default(), registers: BrilligRegistersContext::new(), @@ -42,8 +42,8 @@ impl BrilligContext { arguments: &[BrilligParameter], return_parameters: &[BrilligParameter], ) { - let calldata_size = BrilligContext::flattened_tuple_size(arguments); - let return_data_size = BrilligContext::flattened_tuple_size(return_parameters); + let calldata_size = Self::flattened_tuple_size(arguments); + let return_data_size = Self::flattened_tuple_size(return_parameters); // Set initial value of stack pointer: MAX_STACK_SIZE + calldata_size + return_data_size self.const_instruction( @@ -74,7 +74,7 @@ impl BrilligContext { let pointer_to_the_array_in_calldata = self.make_usize_constant_instruction(current_calldata_pointer.into()); let rc_register = self.make_usize_constant_instruction(1_usize.into()); - let flattened_size = BrilligContext::flattened_size(argument); + let flattened_size = Self::flattened_size(argument); let var = BrilligVariable::BrilligArray(BrilligArray { pointer: pointer_to_the_array_in_calldata.address, size: flattened_size, @@ -88,7 +88,7 @@ impl BrilligContext { let pointer_to_the_array_in_calldata = self.make_usize_constant_instruction(current_calldata_pointer.into()); - let flattened_size = BrilligContext::flattened_size(argument); + let flattened_size = Self::flattened_size(argument); let size_register = self.make_usize_constant_instruction(flattened_size.into()); let rc_register = self.make_usize_constant_instruction(1_usize.into()); @@ -121,7 +121,7 @@ impl BrilligContext { BrilligVariable::BrilligVector(vector), BrilligParameter::Slice(item_type, item_count), ) => { - let flattened_size = BrilligContext::flattened_size(argument); + let flattened_size = Self::flattened_size(argument); let deflattened_address = self.deflatten_array(item_type, flattened_size, vector.pointer); @@ -139,7 +139,7 @@ impl BrilligContext { } fn copy_and_cast_calldata(&mut self, arguments: &[BrilligParameter]) { - let calldata_size = BrilligContext::flattened_tuple_size(arguments); + let calldata_size = Self::flattened_tuple_size(arguments); self.calldata_copy_instruction(MemoryAddress(MAX_STACK_SIZE), calldata_size, 0); fn flat_bit_sizes(param: &BrilligParameter) -> Box + '_> { @@ -154,7 +154,7 @@ impl BrilligContext { for (i, bit_size) in arguments.iter().flat_map(flat_bit_sizes).enumerate() { // Calldatacopy tags everything with field type, so when downcast when necessary - if bit_size < FieldElement::max_num_bits() { + if bit_size < F::max_num_bits() { self.cast_instruction( SingleAddrVariable::new(MemoryAddress(MAX_STACK_SIZE + i), bit_size), SingleAddrVariable::new_field(MemoryAddress(MAX_STACK_SIZE + i)), @@ -169,7 +169,7 @@ impl BrilligContext { BrilligParameter::SingleAddr(_) => 1, BrilligParameter::Array(item_types, item_count) | BrilligParameter::Slice(item_types, item_count) => { - let item_size: usize = item_types.iter().map(BrilligContext::flattened_size).sum(); + let item_size: usize = item_types.iter().map(Self::flattened_size).sum(); item_count * item_size } } @@ -177,7 +177,7 @@ impl BrilligContext { /// Computes the size of a parameter if it was flattened pub(super) fn flattened_tuple_size(tuple: &[BrilligParameter]) -> usize { - tuple.iter().map(BrilligContext::flattened_size).sum() + tuple.iter().map(Self::flattened_size).sum() } /// Computes the size of a parameter if it was flattened @@ -193,12 +193,12 @@ impl BrilligContext { item_count: usize, flattened_array_pointer: MemoryAddress, ) -> MemoryAddress { - if BrilligContext::has_nested_arrays(item_type) { + if Self::has_nested_arrays(item_type) { let movement_register = self.allocate_register(); let deflattened_array_pointer = self.allocate_register(); let target_item_size = item_type.len(); - let source_item_size = BrilligContext::flattened_tuple_size(item_type); + let source_item_size = Self::flattened_tuple_size(item_type); self.codegen_allocate_fixed_length_array( deflattened_array_pointer, @@ -276,7 +276,7 @@ impl BrilligContext { .into_iter() .for_each(|register| self.deallocate_register(register)); - source_offset += BrilligContext::flattened_size(subitem); + source_offset += Self::flattened_size(subitem); } BrilligParameter::Slice(..) => unreachable!("ICE: Cannot deflatten slices"), } @@ -328,8 +328,8 @@ impl BrilligContext { .collect(); // Now, we deflatten the return data - let calldata_size = BrilligContext::flattened_tuple_size(arguments); - let return_data_size = BrilligContext::flattened_tuple_size(return_parameters); + let calldata_size = Self::flattened_tuple_size(arguments); + let return_data_size = Self::flattened_tuple_size(return_parameters); // Return data has a reserved space after calldata let return_data_offset = MAX_STACK_SIZE + calldata_size; @@ -357,7 +357,7 @@ impl BrilligContext { ); self.deallocate_single_addr(pointer_to_return_data); - return_data_index += BrilligContext::flattened_size(return_param); + return_data_index += Self::flattened_size(return_param); } BrilligParameter::Slice(..) => { unreachable!("ICE: Cannot return slices from brillig entrypoints") @@ -376,12 +376,11 @@ impl BrilligContext { flattened_array_pointer: MemoryAddress, deflattened_array_pointer: MemoryAddress, ) { - if BrilligContext::has_nested_arrays(item_type) { + if Self::has_nested_arrays(item_type) { let movement_register = self.allocate_register(); let source_item_size = item_type.len(); - let target_item_size: usize = - item_type.iter().map(BrilligContext::flattened_size).sum(); + let target_item_size: usize = item_type.iter().map(Self::flattened_size).sum(); for item_index in 0..item_count { let source_item_base_index = item_index * source_item_size; @@ -462,7 +461,7 @@ impl BrilligContext { .into_iter() .for_each(|register| self.deallocate_register(register)); - target_offset += BrilligContext::flattened_size(subitem); + target_offset += Self::flattened_size(subitem); } BrilligParameter::Slice(..) => unreachable!("ICE: Cannot flatten slices"), } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 03a9216b73a..a614f93fa30 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -10,12 +10,13 @@ use acvm::{ use super::{ artifact::UnresolvedJumpLocation, brillig_variable::{BrilligArray, BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; /// Low level instructions of the brillig IR, used by the brillig ir codegens and brillig_gen /// Printed using debug_slow -impl BrilligContext { +impl BrilligContext { /// Processes a binary instruction according `operation`. /// /// This method will compute lhs rhs @@ -42,8 +43,7 @@ impl BrilligContext { ) { self.debug_show.not_instruction(input.address, input.bit_size, result.address); // Compile !x as ((-1) - x) - let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) - - FieldElement::one(); + let u_max = F::from(2_u128).pow(&F::from(input.bit_size as u128)) - F::one(); let max = self.make_constant(u_max, input.bit_size); self.binary(max, input, result, BrilligBinaryOp::Sub); @@ -63,7 +63,7 @@ impl BrilligContext { SingleAddrVariable::new_usize(rhs), SingleAddrVariable::new( destination, - BrilligContext::binary_result_bit_size(op, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), + Self::binary_result_bit_size(op, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ), op, ); @@ -77,8 +77,7 @@ impl BrilligContext { operation: BrilligBinaryOp, ) { let is_field_op = lhs.bit_size == FieldElement::max_num_bits(); - let expected_result_bit_size = - BrilligContext::binary_result_bit_size(operation, lhs.bit_size); + let expected_result_bit_size = Self::binary_result_bit_size(operation, lhs.bit_size); assert!( result.bit_size == expected_result_bit_size, "Expected result bit size to be {}, got {} for operation {:?}", @@ -213,7 +212,7 @@ impl BrilligContext { /// Adds a unresolved `Jump` to the bytecode. fn add_unresolved_jump( &mut self, - jmp_instruction: BrilligOpcode, + jmp_instruction: BrilligOpcode, destination: UnresolvedJumpLocation, ) { self.obj.add_unresolved_jump(jmp_instruction, destination); @@ -369,12 +368,12 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: FieldElement) { + pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: F) { self.debug_show.const_instruction(result.address, constant); self.constant(result, constant); } - fn constant(&mut self, result: SingleAddrVariable, constant: FieldElement) { + fn constant(&mut self, result: SingleAddrVariable, constant: F) { assert!( result.bit_size >= constant.num_bits(), "Constant {} does not fit in bit size {}", @@ -382,10 +381,10 @@ impl BrilligContext { result.bit_size ); if result.bit_size > 128 && constant.num_bits() > 128 { - let high = FieldElement::from_be_bytes_reduce( + let high = F::from_be_bytes_reduce( constant.to_be_bytes().get(0..16).expect("FieldElement::to_be_bytes() too short!"), ); - let low = FieldElement::from(constant.to_u128()); + let low = F::from(constant.to_u128()); let high_register = SingleAddrVariable::new(self.allocate_register(), 254); let low_register = SingleAddrVariable::new(self.allocate_register(), 254); let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); @@ -393,7 +392,7 @@ impl BrilligContext { self.constant(low_register, low); // I want to multiply high by 2^128, but I can't get that big constant in. // So I'll multiply by 2^64 twice. - self.constant(intermediate_register, FieldElement::from(1_u128 << 64)); + self.constant(intermediate_register, F::from(1_u128 << 64)); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); // Now we can add. @@ -411,18 +410,14 @@ impl BrilligContext { } } - pub(crate) fn usize_const_instruction( - &mut self, - result: MemoryAddress, - constant: FieldElement, - ) { + pub(crate) fn usize_const_instruction(&mut self, result: MemoryAddress, constant: F) { self.const_instruction(SingleAddrVariable::new_usize(result), constant); } /// Returns a register which holds the value of a constant pub(crate) fn make_constant_instruction( &mut self, - constant: FieldElement, + constant: F, bit_size: u32, ) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); @@ -430,17 +425,14 @@ impl BrilligContext { var } - fn make_constant(&mut self, constant: FieldElement, bit_size: u32) -> SingleAddrVariable { + fn make_constant(&mut self, constant: F, bit_size: u32) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); self.constant(var, constant); var } /// Returns a register which holds the value of an usize constant - pub(crate) fn make_usize_constant_instruction( - &mut self, - constant: FieldElement, - ) -> SingleAddrVariable { + pub(crate) fn make_usize_constant_instruction(&mut self, constant: F) -> SingleAddrVariable { let register = self.allocate_register(); self.usize_const_instruction(register, constant); SingleAddrVariable::new_usize(register) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index f756f06aa69..ae506462b25 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -82,7 +82,7 @@ impl BrilligRegistersContext { } } -impl BrilligContext { +impl BrilligContext { /// Returns the i'th register after the reserved ones pub(crate) fn register(&self, i: usize) -> MemoryAddress { MemoryAddress::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs index eda1ac97c1e..70c0959517b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs @@ -1,6 +1,8 @@ pub(crate) mod brillig_gen; pub(crate) mod brillig_ir; +use acvm::FieldElement; + use self::{ brillig_gen::{brillig_fn::FunctionContext, convert_ssa_function}, brillig_ir::artifact::{BrilligArtifact, Label}, @@ -16,7 +18,7 @@ use std::collections::{BTreeSet, HashMap}; #[derive(Default)] pub struct Brillig { /// Maps SSA function labels to their brillig artifact - ssa_function_to_brillig: HashMap, + ssa_function_to_brillig: HashMap>, } impl Brillig { @@ -27,7 +29,10 @@ impl Brillig { } /// Finds a brillig function artifact by its function label - pub(crate) fn find_by_function_label(&self, function_label: Label) -> Option<&BrilligArtifact> { + pub(crate) fn find_by_function_label( + &self, + function_label: Label, + ) -> Option<&BrilligArtifact> { self.ssa_function_to_brillig.iter().find_map(|(function_id, obj)| { if FunctionContext::function_id_to_function_label(*function_id) == function_label { Some(obj) @@ -39,7 +44,7 @@ impl Brillig { } impl std::ops::Index for Brillig { - type Output = BrilligArtifact; + type Output = BrilligArtifact; fn index(&self, id: FunctionId) -> &Self::Output { &self.ssa_function_to_brillig[&id] } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs index 80a63f223e7..c56e0b2cd3d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs @@ -17,8 +17,7 @@ use acvm::{ Program as AcirProgram, PublicInputs, }, native_types::Witness, - }, - FieldElement, + }, FieldElement }; use noirc_errors::debug_info::{DebugFunctions, DebugInfo, DebugTypes, DebugVariables}; @@ -206,7 +205,7 @@ pub struct SsaCircuitArtifact { } fn convert_generated_acir_into_circuit( - mut generated_acir: GeneratedAcir, + mut generated_acir: GeneratedAcir, func_sig: FunctionSignature, recursive: bool, debug_variables: DebugVariables, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index ac7f2c09687..928a7b105ea 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -20,7 +20,6 @@ use acvm::{ native_types::{Expression, Witness}, BlackBoxFunc, }, - FieldElement, }; use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; @@ -48,12 +47,12 @@ impl AcirType { } /// Returns the bit size of the underlying type - pub(crate) fn bit_size(&self) -> u32 { + pub(crate) fn bit_size(&self) -> u32 { match self { AcirType::NumericType(numeric_type) => match numeric_type { NumericType::Signed { bit_size } => *bit_size, NumericType::Unsigned { bit_size } => *bit_size, - NumericType::NativeField => FieldElement::max_num_bits(), + NumericType::NativeField => F::max_num_bits(), }, AcirType::Array(_, _) => unreachable!("cannot fetch bit size of array type"), } @@ -106,13 +105,13 @@ impl From for AcirType { /// 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(crate) struct AcirContext { /// Two-way map that links `AcirVar` to `AcirVarData`. /// /// The vars object is an instance of the `TwoWayMap`, which provides a bidirectional mapping between `AcirVar` and `AcirVarData`. - vars: HashMap, + vars: HashMap>, - constant_witnesses: HashMap, + constant_witnesses: HashMap, /// An in-memory representation of ACIR. /// @@ -121,13 +120,13 @@ pub(crate) struct AcirContext { /// For example, If one was to add two Variables together, /// then the `acir_ir` will be populated to assert this /// addition. - acir_ir: GeneratedAcir, + acir_ir: GeneratedAcir, /// The BigIntContext, used to generate identifiers for BigIntegers big_int_ctx: BigIntContext, } -impl AcirContext { +impl AcirContext { pub(crate) fn current_witness_index(&self) -> Witness { self.acir_ir.current_witness_index() } @@ -148,7 +147,7 @@ impl AcirContext { } /// Adds a constant to the context and assigns a Variable to represent it - pub(crate) fn add_constant(&mut self, constant: impl Into) -> AcirVar { + pub(crate) fn add_constant(&mut self, constant: impl Into) -> AcirVar { let constant_data = AcirVarData::Const(constant.into()); self.add_data(constant_data) } @@ -156,7 +155,7 @@ impl AcirContext { /// Returns the constant represented by the given variable. /// /// Panics: if the variable does not represent a constant. - pub(crate) fn constant(&self, var: AcirVar) -> FieldElement { + pub(crate) fn constant(&self, var: AcirVar) -> &F { self.vars[&var].as_constant().expect("ICE - expected the variable to be a constant value") } @@ -270,10 +269,7 @@ impl AcirContext { } /// Converts an [`AcirVar`] to an [`Expression`] - pub(crate) fn var_to_expression( - &self, - var: AcirVar, - ) -> Result, InternalError> { + pub(crate) fn var_to_expression(&self, var: AcirVar) -> Result, InternalError> { let var_data = match self.vars.get(&var) { Some(var_data) => var_data, None => { @@ -408,7 +404,7 @@ impl AcirContext { if lhs_expr == rhs_expr { // x ^ x == 0 - let zero = self.add_constant(FieldElement::zero()); + let zero = self.add_constant(F::zero()); return Ok(zero); } else if lhs_expr.is_zero() { // 0 ^ x == x @@ -418,14 +414,14 @@ impl AcirContext { return Ok(lhs); } - let bit_size = typ.bit_size(); + let bit_size = typ.bit_size::(); if bit_size == 1 { // Operands are booleans. // // a ^ b == a + b - 2*a*b let prod = self.mul_var(lhs, rhs)?; let sum = self.add_var(lhs, rhs)?; - self.add_mul_var(sum, -FieldElement::from(2_i128), prod) + self.add_mul_var(sum, -F::from(2_u128), prod) } else { let inputs = vec![AcirValue::Var(lhs, typ.clone()), AcirValue::Var(rhs, typ)]; let outputs = self.black_box_function(BlackBoxFunc::XOR, inputs, 1)?; @@ -448,11 +444,11 @@ impl AcirContext { return Ok(lhs); } else if lhs_expr.is_zero() || rhs_expr.is_zero() { // x & 0 == 0 and 0 & x == 0 - let zero = self.add_constant(FieldElement::zero()); + let zero = self.add_constant(F::zero()); return Ok(zero); } - let bit_size = typ.bit_size(); + let bit_size = typ.bit_size::(); if bit_size == 1 { // Operands are booleans. self.mul_var(lhs, rhs) @@ -480,7 +476,7 @@ impl AcirContext { return Ok(lhs); } - let bit_size = typ.bit_size(); + let bit_size = typ.bit_size::(); if bit_size == 1 { // Operands are booleans // a + b - ab @@ -502,7 +498,7 @@ impl AcirContext { &mut self, lhs: AcirVar, rhs: AcirVar, - assert_message: Option>, + assert_message: Option>, ) -> Result<(), RuntimeError> { let lhs_expr = self.var_to_expression(lhs)?; let rhs_expr = self.var_to_expression(rhs)?; @@ -531,7 +527,7 @@ impl AcirContext { pub(crate) fn vars_to_expressions_or_memory( &self, values: &[AcirValue], - ) -> Result>, RuntimeError> { + ) -> Result>, RuntimeError> { let mut result = Vec::with_capacity(values.len()); for value in values { match value { @@ -597,7 +593,7 @@ impl AcirContext { (AcirVarData::Const(constant), _) | (_, AcirVarData::Const(constant)) if constant.is_zero() => { - self.add_constant(FieldElement::zero()) + self.add_constant(F::zero()) } (AcirVarData::Const(lhs_constant), AcirVarData::Const(rhs_constant)) => { @@ -615,7 +611,7 @@ impl AcirContext { } (AcirVarData::Witness(lhs_witness), AcirVarData::Witness(rhs_witness)) => { let mut expr = Expression::default(); - expr.push_multiplication_term(FieldElement::one(), lhs_witness, rhs_witness); + expr.push_multiplication_term(F::one(), lhs_witness, rhs_witness); self.add_data(AcirVarData::Expr(expr)) } (AcirVarData::Expr(expression), AcirVarData::Witness(witness)) @@ -681,12 +677,7 @@ impl AcirContext { /// Adds a new Variable to context whose value will /// be constrained to be the expression `lhs + k * rhs` - fn add_mul_var( - &mut self, - lhs: AcirVar, - k: FieldElement, - rhs: AcirVar, - ) -> Result { + fn add_mul_var(&mut self, lhs: AcirVar, k: F, rhs: AcirVar) -> Result { let k_var = self.add_constant(k); let intermediate = self.mul_var(k_var, rhs)?; @@ -695,7 +686,7 @@ impl AcirContext { /// Adds a new variable that is constrained to be the logical NOT of `x`. pub(crate) fn not_var(&mut self, x: AcirVar, typ: AcirType) -> Result { - let bit_size = typ.bit_size(); + let bit_size = typ.bit_size::(); // Subtracting from max flips the bits let max = self.add_constant((1_u128 << bit_size) - 1); self.sub_var(max, x) @@ -709,8 +700,8 @@ impl AcirContext { bit_size: u32, predicate: AcirVar, ) -> Result<(AcirVar, AcirVar), RuntimeError> { - let zero = self.add_constant(FieldElement::zero()); - let one = self.add_constant(FieldElement::one()); + let zero = self.add_constant(F::zero()); + let one = self.add_constant(F::one()); let lhs_expr = self.var_to_expression(lhs)?; let rhs_expr = self.var_to_expression(rhs)?; @@ -829,7 +820,7 @@ impl AcirContext { // Avoids overflow: 'q*b+r < 2^max_q_bits*2^max_rhs_bits' let mut avoid_overflow = false; - if max_q_bits + max_rhs_bits >= FieldElement::max_num_bits() - 1 { + if max_q_bits + max_rhs_bits >= F::max_num_bits() - 1 { // q*b+r can overflow; we avoid this when b is constant if rhs_expr.is_const() { avoid_overflow = true; @@ -843,16 +834,16 @@ impl AcirContext { if avoid_overflow { // we compute q0 = p/rhs let rhs_big = BigUint::from_bytes_be(&rhs_const.to_be_bytes()); - let q0_big = FieldElement::modulus() / &rhs_big; - let q0 = FieldElement::from_be_bytes_reduce(&q0_big.to_bytes_be()); + let q0_big = F::modulus() / &rhs_big; + let q0 = F::from_be_bytes_reduce(&q0_big.to_bytes_be()); let q0_var = self.add_constant(q0); // when q == q0, b*q+r can overflow so we need to bound r to avoid the overflow. let size_predicate = self.eq_var(q0_var, quotient_var)?; let predicate = self.mul_var(size_predicate, predicate)?; // Ensure that there is no overflow, under q == q0 predicate - let max_r_big = FieldElement::modulus() - q0_big * rhs_big; - let max_r = FieldElement::from_be_bytes_reduce(&max_r_big.to_bytes_be()); + let max_r_big = F::modulus() - q0_big * rhs_big; + let max_r = F::from_be_bytes_reduce(&max_r_big.to_bytes_be()); let max_r_var = self.add_constant(max_r); let max_r_predicate = self.mul_var(predicate, max_r_var)?; @@ -897,7 +888,7 @@ impl AcirContext { } assert!( - bits < FieldElement::max_num_bits(), + bits < F::max_num_bits(), "range check with bit size of the prime field is not implemented yet" ); @@ -921,7 +912,7 @@ impl AcirContext { // however, since it is a constant, we can compute it's actual bit size let r_bit_size = bit_size_u128(r); // witness = lhs_offset + r - assert!(bits + r_bit_size < FieldElement::max_num_bits()); //we need to ensure lhs_offset + r does not overflow + assert!(bits + r_bit_size < F::max_num_bits()); //we need to ensure lhs_offset + r does not overflow let r_var = self.add_constant(r); let aor = self.add_var(lhs_offset, r_var)?; @@ -945,14 +936,13 @@ impl AcirContext { leading: AcirVar, max_bit_size: u32, ) -> Result { - let max_power_of_two = self.add_constant( - FieldElement::from(2_i128).pow(&FieldElement::from(max_bit_size as i128 - 1)), - ); + let max_power_of_two = + self.add_constant(F::from(2_u128).pow(&F::from(max_bit_size as u128 - 1))); let intermediate = self.sub_var(max_power_of_two, lhs)?; let intermediate = self.mul_var(intermediate, leading)?; - self.add_mul_var(lhs, FieldElement::from(2_i128), intermediate) + self.add_mul_var(lhs, F::from(2_u128), intermediate) } /// Returns the quotient and remainder such that lhs = rhs * quotient + remainder @@ -976,11 +966,10 @@ impl AcirContext { assert_ne!(bit_size, 0, "signed integer should have at least one bit"); // 2^{max_bit size-1} - let max_power_of_two = self.add_constant( - FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128 - 1)), - ); - let zero = self.add_constant(FieldElement::zero()); - let one = self.add_constant(FieldElement::one()); + let max_power_of_two = + self.add_constant(F::from(2_u128).pow(&F::from(bit_size as u128 - 1))); + let zero = self.add_constant(F::zero()); + let one = self.add_constant(F::one()); // Get the sign bit of rhs by computing rhs / max_power_of_two let (rhs_leading, _) = self.euclidean_division_var(rhs, max_power_of_two, bit_size, one)?; @@ -1071,9 +1060,8 @@ impl AcirContext { max_bit_size: u32, ) -> Result { // 2^{rhs} - let divisor = - self.add_constant(FieldElement::from(2_u128).pow(&FieldElement::from(rhs as u128))); - let one = self.add_constant(FieldElement::one()); + let divisor = self.add_constant(F::from(2_u128).pow(&F::from(rhs as u128))); + let one = self.add_constant(F::one()); // Computes lhs = 2^{rhs} * q + r let (_, remainder) = self.euclidean_division_var(lhs, divisor, max_bit_size, one)?; @@ -1093,8 +1081,8 @@ impl AcirContext { rhs: AcirVar, bit_count: u32, ) -> Result { - let pow_last = self.add_constant(FieldElement::from(1_u128 << (bit_count - 1))); - let pow = self.add_constant(FieldElement::from(1_u128 << (bit_count))); + let pow_last = self.add_constant(F::from(1_u128 << (bit_count - 1))); + let pow = self.add_constant(F::from(1_u128 << (bit_count))); // We check whether the inputs have same sign or not by computing the XOR of their bit sign @@ -1163,10 +1151,9 @@ impl AcirContext { // Ensure that 2^{max_bits + 1} is less than the field size // // TODO: perhaps this should be a user error, instead of an assert - assert!(max_bits + 1 < FieldElement::max_num_bits()); + assert!(max_bits + 1 < F::max_num_bits()); - let two_max_bits = self - .add_constant(FieldElement::from(2_i128).pow(&FieldElement::from(max_bits as i128))); + let two_max_bits = self.add_constant(F::from(2_u128).pow(&F::from(max_bits as u128))); let diff = self.sub_var(lhs, rhs)?; let comparison_evaluation = self.add_var(diff, two_max_bits)?; @@ -1214,7 +1201,7 @@ impl AcirContext { // compute less than. let comparison = self.more_than_eq_var(lhs, rhs, bit_size)?; - let one = self.add_constant(FieldElement::one()); + let one = self.add_constant(F::one()); self.sub_var(one, comparison) // comparison_negated } @@ -1251,7 +1238,7 @@ impl AcirContext { } }; - (vec![domain_constant], Vec::new()) + (vec![*domain_constant], Vec::new()) } BlackBoxFunc::Poseidon2Permutation => { // The last argument is the state length, which must be a constant @@ -1276,7 +1263,7 @@ impl AcirContext { } }; - (vec![state_len], Vec::new()) + (vec![*state_len], Vec::new()) } BlackBoxFunc::BigIntAdd | BlackBoxFunc::BigIntSub @@ -1297,7 +1284,7 @@ impl AcirContext { output_count = 0; let mut field_inputs = Vec::new(); for i in const_inputs { - field_inputs.push(i?); + field_inputs.push(*i?); } if field_inputs[1] != field_inputs[3] { return Err(RuntimeError::BigIntModulus { call_stack: self.get_call_stack() }); @@ -1306,7 +1293,7 @@ impl AcirContext { let result_id = self.big_int_ctx.new_big_int(field_inputs[1]); ( vec![field_inputs[0], field_inputs[2]], - vec![result_id.bigint_id(), result_id.modulus_id()], + vec![result_id.bigint_id::(), result_id.modulus_id::()], ) } BlackBoxFunc::BigIntToLeBytes => { @@ -1323,10 +1310,10 @@ impl AcirContext { inputs = Vec::new(); let mut field_inputs = Vec::new(); for i in const_inputs { - field_inputs.push(i?); + field_inputs.push(*i?); } let bigint = self.big_int_ctx.get(field_inputs[0]); - let modulus = self.big_int_ctx.modulus(bigint.modulus_id()); + let modulus = self.big_int_ctx.modulus(bigint.modulus_id::()); let bytes_len = ((modulus - BigUint::from(1_u32)).bits() - 1) / 8 + 1; output_count = bytes_len as usize; assert!(bytes_len == 32); @@ -1339,7 +1326,7 @@ impl AcirContext { match inputs.pop().expect(invalid_input) { AcirValue::Array(values) => { for value in values { - modulus.push(self.vars[&value.into_var()?].as_constant().ok_or( + modulus.push(*self.vars[&value.into_var()?].as_constant().ok_or( RuntimeError::InternalError(InternalError::NotAConstant { name: "big integer".to_string(), call_stack: self.get_call_stack(), @@ -1359,9 +1346,8 @@ impl AcirContext { output_count = 0; let modulus_id = self.big_int_ctx.get_or_insert_modulus(big_modulus); - let result_id = - self.big_int_ctx.new_big_int(FieldElement::from(modulus_id as u128)); - (modulus, vec![result_id.bigint_id(), result_id.modulus_id()]) + let result_id = self.big_int_ctx.new_big_int(F::from(modulus_id as u128)); + (modulus, vec![result_id.bigint_id::(), result_id.modulus_id::()]) } BlackBoxFunc::AES128Encrypt => { let invalid_input = "aes128_encrypt - operation requires a plaintext to encrypt"; @@ -1376,7 +1362,7 @@ impl AcirContext { } }?; output_count = input_size + (16 - input_size % 16); - (vec![], vec![FieldElement::from(output_count as u128)]) + (vec![], vec![F::from(output_count as u128)]) } _ => (vec![], vec![]), }; @@ -1420,7 +1406,7 @@ impl AcirContext { // constants too. let witness_var = self.get_or_create_witness_var(input)?; let witness = self.var_to_witness(witness_var)?; - let num_bits = typ.bit_size(); + let num_bits = typ.bit_size::(); single_val_witnesses.push(FunctionInput { witness, num_bits }); } witnesses.push(single_val_witnesses); @@ -1531,7 +1517,7 @@ impl AcirContext { inputs: Vec, return_values: Vec, warnings: Vec, - ) -> GeneratedAcir { + ) -> GeneratedAcir { self.acir_ir.input_witnesses = inputs; self.acir_ir.return_witnesses = return_values; self.acir_ir.warnings = warnings; @@ -1543,7 +1529,7 @@ impl AcirContext { /// Variable can be seen as an index into the context. /// We use a two-way map so that it is efficient to lookup /// either the key or the value. - fn add_data(&mut self, data: AcirVarData) -> AcirVar { + fn add_data(&mut self, data: AcirVarData) -> AcirVar { let id = AcirVar(self.vars.len()); self.vars.insert(id, data); id @@ -1553,7 +1539,7 @@ impl AcirContext { pub(crate) fn brillig_call( &mut self, predicate: AcirVar, - generated_brillig: &GeneratedBrillig, + generated_brillig: &GeneratedBrillig, inputs: Vec, outputs: Vec, attempt_execution: bool, @@ -1561,14 +1547,34 @@ impl AcirContext { brillig_function_index: u32, brillig_stdlib_func: Option, ) -> Result, RuntimeError> { - let brillig_inputs: Vec> = + let predicate = self.var_to_expression(predicate)?; + if predicate.is_zero() { + // If the predicate has a constant value of zero, the brillig call will never be executed. + // We can then immediately zero out all of its outputs as this is the value which would be written + // if we waited until runtime to resolve this call. + let outputs_var = vecmap(outputs, |output| match output { + AcirType::NumericType(_) => { + let var = self.add_constant(F::zero()); + AcirValue::Var(var, output.clone()) + } + AcirType::Array(element_types, size) => { + self.zeroed_array_output(&element_types, size) + } + }); + + return Ok(outputs_var); + } + // Remove "always true" predicates. + let predicate = if predicate == Expression::one() { None } else { Some(predicate) }; + + let brillig_inputs: Vec> = try_vecmap(inputs, |i| -> Result<_, InternalError> { match i { AcirValue::Var(var, _) => { Ok(BrilligInputs::Single(self.var_to_expression(var)?)) } AcirValue::Array(vars) => { - let mut var_expressions: Vec> = Vec::new(); + let mut var_expressions: Vec> = Vec::new(); for var in vars { self.brillig_array_input(&mut var_expressions, var)?; } @@ -1608,10 +1614,9 @@ impl AcirContext { acir_value } }); - let predicate = self.var_to_expression(predicate)?; self.acir_ir.brillig_call( - Some(predicate), + predicate, generated_brillig, brillig_inputs, brillig_outputs, @@ -1619,8 +1624,8 @@ impl AcirContext { brillig_stdlib_func, ); - fn range_constraint_value( - context: &mut AcirContext, + fn range_constraint_value( + context: &mut AcirContext, value: &AcirValue, ) -> Result<(), RuntimeError> { match value { @@ -1655,7 +1660,7 @@ impl AcirContext { fn brillig_array_input( &mut self, - var_expressions: &mut Vec>, + var_expressions: &mut Vec>, input: AcirValue, ) -> Result<(), InternalError> { match input { @@ -1682,6 +1687,27 @@ impl AcirContext { Ok(()) } + /// Recursively create zeroed-out acir values for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. + fn zeroed_array_output(&mut self, element_types: &[AcirType], size: usize) -> 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.zeroed_array_output(nested_element_types, *nested_size); + array_values.push_back(nested_acir_value); + } + AcirType::NumericType(_) => { + let var = self.add_constant(F::zero()); + array_values.push_back(AcirValue::Var(var, element_type.clone())); + } + } + } + } + AcirValue::Array(array_values) + } + /// Recursively create acir values for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. /// A singular array of witnesses is collected for a top level array, by deflattening the assigned witnesses at each level. fn brillig_array_output( @@ -1714,8 +1740,8 @@ impl AcirContext { fn execute_brillig( &mut self, - code: &[BrilligOpcode], - inputs: &[BrilligInputs], + code: &[BrilligOpcode], + inputs: &[BrilligInputs], outputs_types: &[AcirType], ) -> Option> { let mut memory = (execute_brillig(code, inputs)?).into_iter(); @@ -1740,7 +1766,7 @@ impl AcirContext { &mut self, element_types: &[AcirType], size: usize, - memory_iter: &mut impl Iterator>, + memory_iter: &mut impl Iterator>, ) -> AcirValue { let mut array_values = im::Vector::new(); for _ in 0..size { @@ -1821,7 +1847,7 @@ impl AcirContext { ) -> Result<(), InternalError> { let initialized_values = match optional_value { None => { - let zero = self.add_constant(FieldElement::zero()); + let zero = self.add_constant(F::zero()); let zero_witness = self.var_to_witness(zero)?; vec![zero_witness; len] } @@ -1893,13 +1919,13 @@ impl AcirContext { /// Enum representing the possible values that a /// Variable can be given. #[derive(Debug, Eq, Clone)] -enum AcirVarData { +enum AcirVarData { Witness(Witness), - Expr(Expression), - Const(FieldElement), + Expr(Expression), + Const(F), } -impl PartialEq for AcirVarData { +impl PartialEq for AcirVarData { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Witness(l0), Self::Witness(r0)) => l0 == r0, @@ -1911,23 +1937,26 @@ impl PartialEq for AcirVarData { } // TODO: check/test this hash impl -impl std::hash::Hash for AcirVarData { +impl std::hash::Hash for AcirVarData { fn hash(&self, state: &mut H) { core::mem::discriminant(self).hash(state); } } -impl AcirVarData { +impl AcirVarData { /// Returns a FieldElement, if the underlying `AcirVarData` /// represents a constant. - pub(crate) fn as_constant(&self) -> Option { + pub(crate) fn as_constant(&self) -> Option<&F> { if let AcirVarData::Const(field) = self { - return Some(*field); + return Some(field); } None } +} + +impl AcirVarData { /// Converts all enum variants to an Expression. - pub(crate) fn to_expression(&self) -> Cow> { + pub(crate) fn to_expression(&self) -> Cow> { match self { AcirVarData::Witness(witness) => Cow::Owned(Expression::from(*witness)), AcirVarData::Expr(expr) => Cow::Borrowed(expr), @@ -1936,23 +1965,17 @@ impl AcirVarData { } } -impl From for AcirVarData { - fn from(constant: FieldElement) -> Self { - AcirVarData::Const(constant) - } -} - -impl From for AcirVarData { +impl From for AcirVarData { fn from(witness: Witness) -> Self { AcirVarData::Witness(witness) } } -impl From> for AcirVarData { - fn from(expr: Expression) -> Self { +impl From> for AcirVarData { + fn from(expr: Expression) -> Self { // Prefer simpler variants if possible. if let Some(constant) = expr.to_const() { - AcirVarData::from(*constant) + AcirVarData::Const(*constant) } else if let Some(witness) = expr.to_witness() { AcirVarData::from(witness) } else { @@ -1970,12 +1993,12 @@ pub(crate) struct AcirVar(usize); /// 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], - inputs: &[BrilligInputs], -) -> Option>> { +fn execute_brillig( + code: &[BrilligOpcode], + inputs: &[BrilligInputs], +) -> Option>> { // Set input values - let mut calldata: Vec = Vec::new(); + 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. diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs index b9c596d80c7..30297b42ecf 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs @@ -1,4 +1,4 @@ -use acvm::{acir::AcirField, FieldElement}; +use acvm::acir::AcirField; use num_bigint::BigUint; /// Represents a bigint value in the form (id, modulus) where @@ -11,12 +11,12 @@ pub(crate) struct BigIntId { } impl BigIntId { - pub(crate) fn bigint_id(&self) -> FieldElement { - FieldElement::from(self.bigint_id as u128) + pub(crate) fn bigint_id>(&self) -> F { + F::from(self.bigint_id as u128) } - pub(crate) fn modulus_id(&self) -> FieldElement { - FieldElement::from(self.modulus_id as u128) + pub(crate) fn modulus_id>(&self) -> F { + F::from(self.modulus_id as u128) } } @@ -29,7 +29,7 @@ pub(crate) struct BigIntContext { impl BigIntContext { /// Creates a new BigIntId for the given modulus identifier and returns it. - pub(crate) fn new_big_int(&mut self, modulus_id: FieldElement) -> BigIntId { + pub(crate) fn new_big_int(&mut self, modulus_id: F) -> BigIntId { let id = self.big_integers.len() as u32; let result = BigIntId { bigint_id: id, modulus_id: modulus_id.to_u128() as u32 }; self.big_integers.push(result); @@ -37,12 +37,12 @@ impl BigIntContext { } /// Returns the modulus corresponding to the given modulus index - pub(crate) fn modulus(&self, idx: FieldElement) -> BigUint { + pub(crate) fn modulus(&self, idx: F) -> BigUint { self.modulus[idx.to_u128() as usize].clone() } /// Returns the BigIntId corresponding to the given identifier - pub(crate) fn get(&self, id: FieldElement) -> BigIntId { + pub(crate) fn get(&self, id: F) -> BigIntId { self.big_integers[id.to_u128() as usize] } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 9a09e7c06ee..bcccfac8950 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -19,7 +19,6 @@ use acvm::acir::{ use acvm::{ acir::AcirField, acir::{circuit::directives::Directive, native_types::Expression}, - FieldElement, }; use iter_extended::vecmap; use num_bigint::BigUint; @@ -32,7 +31,7 @@ pub(crate) const PLACEHOLDER_BRILLIG_INDEX: u32 = 0; #[derive(Debug, Default)] /// The output of the Acir-gen pass, which should only be produced for entry point Acir functions -pub(crate) struct GeneratedAcir { +pub(crate) struct GeneratedAcir { /// The next witness index that may be declared. /// If witness index is `None` then we have not yet created a witness /// and thus next witness index that be declared is zero. @@ -42,7 +41,7 @@ pub(crate) struct GeneratedAcir { current_witness_index: Option, /// The opcodes of which the compiled ACIR will comprise. - opcodes: Vec>, + opcodes: Vec>, /// All witness indices that comprise the final return value of the program pub(crate) return_witnesses: Vec, @@ -58,7 +57,7 @@ pub(crate) struct GeneratedAcir { pub(crate) call_stack: CallStack, /// Correspondence between an opcode index and the error message associated with it. - pub(crate) assertion_payloads: BTreeMap>, + pub(crate) assertion_payloads: BTreeMap>, pub(crate) warnings: Vec, @@ -80,7 +79,7 @@ pub(crate) enum BrilligStdlibFunc { } impl BrilligStdlibFunc { - pub(crate) fn get_generated_brillig(&self) -> GeneratedBrillig { + pub(crate) fn get_generated_brillig(&self) -> GeneratedBrillig { match self { BrilligStdlibFunc::Inverse => brillig_directive::directive_invert(), BrilligStdlibFunc::Quotient(bit_size) => { @@ -90,25 +89,25 @@ impl BrilligStdlibFunc { } } -impl GeneratedAcir { +impl GeneratedAcir { /// Returns the current witness index. pub(crate) fn current_witness_index(&self) -> Witness { Witness(self.current_witness_index.unwrap_or(0)) } /// Adds a new opcode into ACIR. - pub(crate) fn push_opcode(&mut self, opcode: AcirOpcode) { + pub(crate) fn push_opcode(&mut self, opcode: AcirOpcode) { self.opcodes.push(opcode); if !self.call_stack.is_empty() { self.locations.insert(self.last_acir_opcode_location(), self.call_stack.clone()); } } - pub(crate) fn opcodes(&self) -> &[AcirOpcode] { + pub(crate) fn opcodes(&self) -> &[AcirOpcode] { &self.opcodes } - pub(crate) fn take_opcodes(&mut self) -> Vec> { + pub(crate) fn take_opcodes(&mut self) -> Vec> { std::mem::take(&mut self.opcodes) } @@ -127,7 +126,7 @@ impl GeneratedAcir { /// /// If `expr` can be represented as a `Witness` then this function will return it, /// else a new opcode will be added to create a `Witness` that is equal to `expr`. - pub(crate) fn get_or_create_witness(&mut self, expr: &Expression) -> Witness { + pub(crate) fn get_or_create_witness(&mut self, expr: &Expression) -> Witness { match expr.to_witness() { Some(witness) => witness, None => self.create_witness_for_expression(expr), @@ -140,10 +139,7 @@ impl GeneratedAcir { /// This means you cannot multiply an infinite amount of `Expression`s together. /// Once the `Expression` goes over degree-2, then it needs to be reduced to a `Witness` /// which has degree-1 in order to be able to continue the multiplication chain. - pub(crate) fn create_witness_for_expression( - &mut self, - expression: &Expression, - ) -> Witness { + pub(crate) fn create_witness_for_expression(&mut self, expression: &Expression) -> Witness { let fresh_witness = self.next_witness_index(); // Create a constraint that sets them to be equal to each other @@ -163,15 +159,15 @@ impl GeneratedAcir { } } -impl GeneratedAcir { +impl GeneratedAcir { /// Calls a black box function and returns the output /// of said blackbox function. pub(crate) fn call_black_box( &mut self, func_name: BlackBoxFunc, inputs: &[Vec], - constant_inputs: Vec, - constant_outputs: Vec, + constant_inputs: Vec, + constant_outputs: Vec, output_count: usize, ) -> Result, InternalError> { let input_count = inputs.iter().fold(0usize, |sum, val| sum + val.len()); @@ -388,7 +384,7 @@ impl GeneratedAcir { /// Only radix that are a power of two are supported pub(crate) fn radix_le_decompose( &mut self, - input_expr: &Expression, + input_expr: &Expression, radix: u32, limb_count: u32, bit_size: u32, @@ -414,7 +410,7 @@ impl GeneratedAcir { self.range_constraint(*limb_witness, bit_size)?; composed_limbs = composed_limbs.add_mul( - FieldElement::from_be_bytes_reduce(&radix_pow.to_bytes_be()), + F::from_be_bytes_reduce(&radix_pow.to_bytes_be()), &Expression::from(*limb_witness), ); @@ -434,7 +430,7 @@ impl GeneratedAcir { /// /// Safety: It is the callers responsibility to ensure that the /// resulting `Witness` is constrained to be the inverse. - pub(crate) fn brillig_inverse(&mut self, expr: Expression) -> Witness { + pub(crate) fn brillig_inverse(&mut self, expr: Expression) -> Witness { // Create the witness for the result let inverted_witness = self.next_witness_index(); @@ -443,7 +439,7 @@ impl GeneratedAcir { let inputs = vec![BrilligInputs::Single(expr)]; let outputs = vec![BrilligOutputs::Simple(inverted_witness)]; self.brillig_call( - Some(Expression::one()), + None, &inverse_code, inputs, outputs, @@ -458,18 +454,14 @@ impl GeneratedAcir { /// /// If `expr` is not zero, then the constraint system will /// fail upon verification. - pub(crate) fn assert_is_zero(&mut self, expr: Expression) { + pub(crate) fn assert_is_zero(&mut self, expr: Expression) { self.push_opcode(AcirOpcode::AssertZero(expr)); } /// Returns a `Witness` that is constrained to be: /// - `1` if `lhs == rhs` /// - `0` otherwise - pub(crate) fn is_equal( - &mut self, - lhs: &Expression, - rhs: &Expression, - ) -> Witness { + pub(crate) fn is_equal(&mut self, lhs: &Expression, rhs: &Expression) -> Witness { let t = lhs - rhs; self.is_zero(&t) @@ -527,13 +519,13 @@ impl GeneratedAcir { /// By setting `z` to be `0`, we can make `y` equal to `1`. /// This is easily observed: `y = 1 - t * 0` /// Now since `y` is one, this means that `t` needs to be zero, or else `y * t == 0` will fail. - fn is_zero(&mut self, t_expr: &Expression) -> Witness { + fn is_zero(&mut self, t_expr: &Expression) -> Witness { // We're checking for equality with zero so we can negate the expression without changing the result. // This is useful as it will sometimes allow us to simplify an expression down to a witness. let t_witness = if let Some(witness) = t_expr.to_witness() { witness } else { - let negated_expr = t_expr * -FieldElement::one(); + let negated_expr = t_expr * -F::one(); self.get_or_create_witness(&negated_expr) }; @@ -545,17 +537,17 @@ impl GeneratedAcir { // Add constraint y == 1 - tz => y + tz - 1 == 0 let y_is_boolean_constraint = Expression { - mul_terms: vec![(FieldElement::one(), t_witness, z)], - linear_combinations: vec![(FieldElement::one(), y)], - q_c: -FieldElement::one(), + mul_terms: vec![(F::one(), t_witness, z)], + linear_combinations: vec![(F::one(), y)], + q_c: -F::one(), }; self.assert_is_zero(y_is_boolean_constraint); // Add constraint that y * t == 0; let ty_zero_constraint = Expression { - mul_terms: vec![(FieldElement::one(), t_witness, y)], + mul_terms: vec![(F::one(), t_witness, y)], linear_combinations: vec![], - q_c: FieldElement::zero(), + q_c: F::zero(), }; self.assert_is_zero(ty_zero_constraint); @@ -571,9 +563,9 @@ impl GeneratedAcir { ) -> Result<(), RuntimeError> { // We class this as an error because users should instead // do `as Field`. - if num_bits >= FieldElement::max_num_bits() { + if num_bits >= F::max_num_bits() { return Err(RuntimeError::InvalidRangeConstraint { - num_bits: FieldElement::max_num_bits(), + num_bits: F::max_num_bits(), call_stack: self.call_stack.clone(), }); }; @@ -588,9 +580,9 @@ impl GeneratedAcir { pub(crate) fn brillig_call( &mut self, - predicate: Option>, - generated_brillig: &GeneratedBrillig, - inputs: Vec>, + predicate: Option>, + generated_brillig: &GeneratedBrillig, + inputs: Vec>, outputs: Vec, brillig_function_index: u32, stdlib_func: Option, @@ -717,6 +709,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::Poseidon2Permutation => None, BlackBoxFunc::Sha256Compression => Some(8), + // Pedersen commitment returns a point BlackBoxFunc::PedersenCommitment => Some(2), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 40170e58a30..aaa483b91c9 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -42,11 +42,11 @@ use im::Vector; use iter_extended::{try_vecmap, vecmap}; #[derive(Default)] -struct SharedContext { +struct SharedContext { /// Final list of Brillig functions which will be part of the final program /// This is shared across `Context` structs as we want one list of Brillig /// functions across all ACIR artifacts - generated_brillig: Vec, + generated_brillig: Vec>, /// Maps SSA function index -> Final generated Brillig artifact index. /// There can be Brillig functions specified in SSA which do not act as @@ -65,7 +65,7 @@ struct SharedContext { brillig_stdlib_calls_to_resolve: HashMap>, } -impl SharedContext { +impl SharedContext { fn generated_brillig_pointer( &self, func_id: FunctionId, @@ -74,7 +74,7 @@ impl SharedContext { self.brillig_generated_func_pointers.get(&(func_id, arguments)) } - fn generated_brillig(&self, func_pointer: usize) -> &GeneratedBrillig { + fn generated_brillig(&self, func_pointer: usize) -> &GeneratedBrillig { &self.generated_brillig[func_pointer] } @@ -83,7 +83,7 @@ impl SharedContext { func_id: FunctionId, arguments: Vec, generated_pointer: u32, - code: GeneratedBrillig, + code: GeneratedBrillig, ) { self.brillig_generated_func_pointers.insert((func_id, arguments), generated_pointer); self.generated_brillig.push(code); @@ -123,7 +123,7 @@ impl SharedContext { generated_pointer: u32, func_id: FunctionId, opcode_location: OpcodeLocation, - code: GeneratedBrillig, + code: GeneratedBrillig, ) { self.brillig_stdlib_func_pointer.insert(brillig_stdlib_func, generated_pointer); self.add_call_to_resolve(func_id, (opcode_location, generated_pointer)); @@ -151,7 +151,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 /// @@ -189,7 +189,7 @@ struct Context<'a> { data_bus: DataBus, /// Contains state that is generated and also used across ACIR functions - shared_context: &'a mut SharedContext, + shared_context: &'a mut SharedContext, } #[derive(Clone)] @@ -274,8 +274,11 @@ impl AcirValue { } } -pub(crate) type Artifacts = - (Vec, Vec>, BTreeMap); +pub(crate) type Artifacts = ( + Vec>, + Vec>, + BTreeMap, +); impl Ssa { #[tracing::instrument(level = "trace", skip_all)] @@ -331,7 +334,7 @@ impl Ssa { } impl<'a> Context<'a> { - fn new(shared_context: &'a mut SharedContext) -> Context<'a> { + fn new(shared_context: &'a mut SharedContext) -> Context<'a> { let mut acir_context = AcirContext::default(); let current_side_effects_enabled_var = acir_context.add_constant(FieldElement::one()); @@ -354,7 +357,7 @@ impl<'a> Context<'a> { ssa: &Ssa, function: &Function, brillig: &Brillig, - ) -> Result, RuntimeError> { + ) -> Result>, RuntimeError> { match function.runtime() { RuntimeType::Acir(inline_type) => { match inline_type { @@ -386,7 +389,7 @@ impl<'a> Context<'a> { main_func: &Function, ssa: &Ssa, brillig: &Brillig, - ) -> Result { + ) -> Result, RuntimeError> { let dfg = &main_func.dfg; let entry_block = &dfg[main_func.entry_block()]; let input_witness = self.convert_ssa_block_params(entry_block.parameters(), dfg)?; @@ -435,7 +438,7 @@ impl<'a> Context<'a> { mut self, main_func: &Function, brillig: &Brillig, - ) -> Result { + ) -> Result, RuntimeError> { let dfg = &main_func.dfg; let inputs = try_vecmap(dfg[main_func.entry_block()].parameters(), |param_id| { @@ -919,7 +922,7 @@ impl<'a> Context<'a> { func: &Function, arguments: Vec, brillig: &Brillig, - ) -> Result { + ) -> Result, InternalError> { // Create the entry point artifact let mut entry_point = BrilligContext::new_entry_point_artifact( arguments, @@ -1897,7 +1900,7 @@ impl<'a> Context<'a> { } let binary_type = AcirType::from(binary_type); - let bit_count = binary_type.bit_size(); + let bit_count = binary_type.bit_size::(); let num_type = binary_type.to_numeric_type(); let result = match binary.operator { BinaryOp::Add => self.acir_context.add_var(lhs, rhs), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index c59134e4ecc..de75d34565e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -304,7 +304,7 @@ impl<'a> ValueMerger<'a> { let mut current_then = then_value; let mut current_else = else_value; - // Arbitrarily limit this to looking at at most 10 past ArraySet operations. + // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. let max_iters = 2; let mut seen_then = Vec::with_capacity(max_iters); From d0af7ff9698509b111dcc264a283ac3cb68a75ca Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 26 Jun 2024 21:19:21 +0000 Subject: [PATCH 2/3] chore: revert meaningful changes --- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 928a7b105ea..56b869fbf6b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1547,26 +1547,6 @@ impl AcirContext { brillig_function_index: u32, brillig_stdlib_func: Option, ) -> Result, RuntimeError> { - let predicate = self.var_to_expression(predicate)?; - if predicate.is_zero() { - // If the predicate has a constant value of zero, the brillig call will never be executed. - // We can then immediately zero out all of its outputs as this is the value which would be written - // if we waited until runtime to resolve this call. - let outputs_var = vecmap(outputs, |output| match output { - AcirType::NumericType(_) => { - let var = self.add_constant(F::zero()); - AcirValue::Var(var, output.clone()) - } - AcirType::Array(element_types, size) => { - self.zeroed_array_output(&element_types, size) - } - }); - - return Ok(outputs_var); - } - // Remove "always true" predicates. - let predicate = if predicate == Expression::one() { None } else { Some(predicate) }; - let brillig_inputs: Vec> = try_vecmap(inputs, |i| -> Result<_, InternalError> { match i { @@ -1614,9 +1594,10 @@ impl AcirContext { acir_value } }); + let predicate = self.var_to_expression(predicate)?; self.acir_ir.brillig_call( - predicate, + Some(predicate), generated_brillig, brillig_inputs, brillig_outputs, @@ -1687,27 +1668,6 @@ impl AcirContext { Ok(()) } - /// Recursively create zeroed-out acir values for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. - fn zeroed_array_output(&mut self, element_types: &[AcirType], size: usize) -> 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.zeroed_array_output(nested_element_types, *nested_size); - array_values.push_back(nested_acir_value); - } - AcirType::NumericType(_) => { - let var = self.add_constant(F::zero()); - array_values.push_back(AcirValue::Var(var, element_type.clone())); - } - } - } - } - AcirValue::Array(array_values) - } - /// Recursively create acir values for returned arrays. This is necessary because a brillig returned array can have nested arrays as elements. /// A singular array of witnesses is collected for a top level array, by deflattening the assigned witnesses at each level. fn brillig_array_output( From de18d156e08cbc6576842b3f37d2505eb3b2408e Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 26 Jun 2024 21:30:22 +0000 Subject: [PATCH 3/3] chore: fmt --- noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs index c56e0b2cd3d..f7b6dfd3771 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs @@ -17,7 +17,8 @@ use acvm::{ Program as AcirProgram, PublicInputs, }, native_types::Witness, - }, FieldElement + }, + FieldElement, }; use noirc_errors::debug_info::{DebugFunctions, DebugInfo, DebugTypes, DebugVariables};