From 85c63efc2950473d1783166a993ea887147576c5 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Tue, 21 Nov 2023 12:10:46 +0000 Subject: [PATCH] wip: refactor brillig variable vs registerormemory --- .../brillig/brillig_gen/brillig_black_box.rs | 86 +- .../src/brillig/brillig_gen/brillig_block.rs | 157 +-- .../brillig_gen/brillig_block_variables.rs | 40 +- .../src/brillig/brillig_gen/brillig_fn.rs | 4 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 946 +++++++++--------- .../noirc_evaluator/src/brillig/brillig_ir.rs | 57 +- .../brillig/brillig_ir/brillig_variable.rs | 80 ++ .../src/brillig/brillig_ir/entry_point.rs | 135 ++- 8 files changed, 851 insertions(+), 654 deletions(-) create mode 100644 compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 0d97dd12601..9979bf0cd29 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,9 +1,9 @@ -use acvm::acir::{ - brillig::{BlackBoxOp, HeapVector, RegisterOrMemory}, - BlackBoxFunc, -}; +use acvm::acir::{brillig::BlackBoxOp, BlackBoxFunc}; -use crate::brillig::brillig_ir::BrilligContext; +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVariable, BrilligVector}, + BrilligContext, +}; /// Transforms SSA's black box function calls into the corresponding brillig instructions /// Extracting arguments and results from the SSA function call @@ -11,31 +11,31 @@ use crate::brillig::brillig_ir::BrilligContext; pub(crate) fn convert_black_box_call( brillig_context: &mut BrilligContext, bb_func: &BlackBoxFunc, - function_arguments: &[RegisterOrMemory], - function_results: &[RegisterOrMemory], + function_arguments: &[BrilligVariable], + function_results: &[BrilligVariable], ) { match bb_func { BlackBoxFunc::SHA256 => { - if let ([message], [RegisterOrMemory::HeapArray(result_array)]) = + if let ([message], [BrilligVariable::BrilligArray(result_array)]) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Sha256 { - message: message_vector, - output: *result_array, + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: SHA256 expects one array argument and one array result") } } BlackBoxFunc::Blake2s => { - if let ([message], [RegisterOrMemory::HeapArray(result_array)]) = + if let ([message], [BrilligVariable::BrilligArray(result_array)]) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Blake2s { - message: message_vector, - output: *result_array, + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Blake2s expects one array argument and one array result") @@ -43,28 +43,28 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::Keccak256 => { if let ( - [message, RegisterOrMemory::RegisterIndex(array_size)], - [RegisterOrMemory::HeapArray(result_array)], + [message, BrilligVariable::Simple(array_size)], + [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func); message_vector.size = *array_size; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { - message: message_vector, - output: *result_array, + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Keccak256 expects message, message size and result array") } } BlackBoxFunc::HashToField128Security => { - if let ([message], [RegisterOrMemory::RegisterIndex(result_register)]) = + if let ([message], [BrilligVariable::Simple(result_register)]) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::HashToField128Security { - message: message_vector, + message: message_vector.to_heap_vector(), output: *result_register, }); } else { @@ -73,17 +73,17 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::EcdsaSecp256k1 => { if let ( - [RegisterOrMemory::HeapArray(public_key_x), RegisterOrMemory::HeapArray(public_key_y), RegisterOrMemory::HeapArray(signature), message], - [RegisterOrMemory::RegisterIndex(result_register)], + [BrilligVariable::BrilligArray(public_key_x), BrilligVariable::BrilligArray(public_key_y), BrilligVariable::BrilligArray(signature), message], + [BrilligVariable::Simple(result_register)], ) = (function_arguments, function_results) { let message_hash_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256k1 { - hashed_msg: message_hash_vector, - public_key_x: *public_key_x, - public_key_y: *public_key_y, - signature: *signature, + hashed_msg: message_hash_vector.to_heap_vector(), + public_key_x: public_key_x.to_heap_array(), + public_key_y: public_key_y.to_heap_array(), + signature: signature.to_heap_array(), result: *result_register, }); } else { @@ -94,15 +94,15 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::PedersenCommitment => { if let ( - [message, RegisterOrMemory::RegisterIndex(domain_separator)], - [RegisterOrMemory::HeapArray(result_array)], + [message, BrilligVariable::Simple(domain_separator)], + [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { - inputs: message_vector, + inputs: message_vector.to_heap_vector(), domain_separator: *domain_separator, - output: *result_array, + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Pedersen expects one array argument, a register for the domain separator, and one array result") @@ -110,13 +110,13 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::PedersenHash => { if let ( - [message, RegisterOrMemory::RegisterIndex(domain_separator)], - [RegisterOrMemory::RegisterIndex(result)], + [message, BrilligVariable::Simple(domain_separator)], + [BrilligVariable::Simple(result)], ) = (function_arguments, function_results) { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { - inputs: message_vector, + inputs: message_vector.to_heap_vector(), domain_separator: *domain_separator, output: *result, }); @@ -126,8 +126,8 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::SchnorrVerify => { if let ( - [RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), message], - [RegisterOrMemory::RegisterIndex(result_register)], + [BrilligVariable::Simple(public_key_x), BrilligVariable::Simple(public_key_y), BrilligVariable::BrilligArray(signature), message], + [BrilligVariable::Simple(result_register)], ) = (function_arguments, function_results) { let message_hash = convert_array_or_vector(brillig_context, message, bb_func); @@ -135,8 +135,8 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { public_key_x: *public_key_x, public_key_y: *public_key_y, - message: message_hash, - signature, + message: message_hash.to_heap_vector(), + signature: signature.to_heap_vector(), result: *result_register, }); } else { @@ -145,14 +145,14 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::FixedBaseScalarMul => { if let ( - [RegisterOrMemory::RegisterIndex(low), RegisterOrMemory::RegisterIndex(high)], - [RegisterOrMemory::HeapArray(result_array)], + [BrilligVariable::Simple(low), BrilligVariable::Simple(high)], + [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::FixedBaseScalarMul { low: *low, high: *high, - result: *result_array, + result: result_array.to_heap_array(), }); } else { unreachable!( @@ -166,12 +166,12 @@ pub(crate) fn convert_black_box_call( fn convert_array_or_vector( brillig_context: &mut BrilligContext, - array_or_vector: &RegisterOrMemory, + array_or_vector: &BrilligVariable, bb_func: &BlackBoxFunc, -) -> HeapVector { +) -> BrilligVector { match array_or_vector { - RegisterOrMemory::HeapArray(array) => brillig_context.array_to_vector(array), - RegisterOrMemory::HeapVector(vector) => *vector, + BrilligVariable::BrilligArray(array) => brillig_context.array_to_vector(array), + BrilligVariable::BrilligVector(vector) => *vector, _ => unreachable!( "ICE: {} expected an array or a vector, but got {:?}", bb_func.name(), diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index da07f7609a1..399a5217838 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,6 +1,6 @@ +use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; use crate::brillig::brillig_ir::{ - extract_heap_array, extract_register, extract_registers, BrilligBinaryOp, BrilligContext, - BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, + BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; use crate::ssa::ir::dfg::CallStack; use crate::ssa::ir::{ @@ -13,7 +13,7 @@ use crate::ssa::ir::{ types::{NumericType, Type}, value::{Value, ValueId}, }; -use acvm::acir::brillig::{BinaryFieldOp, BinaryIntOp, HeapArray, RegisterIndex, RegisterOrMemory}; +use acvm::acir::brillig::{BinaryFieldOp, BinaryIntOp, RegisterIndex, RegisterOrMemory}; use acvm::brillig_vm::brillig::HeapVector; use acvm::FieldElement; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -53,7 +53,7 @@ impl<'block> BrilligBlock<'block> { variables .get_available_variables(function_context) .into_iter() - .flat_map(extract_registers) + .flat_map(|variable| variable.extract_registers()) .collect(), ); let last_uses = function_context.liveness.get_last_uses(&block_id).clone(); @@ -159,7 +159,7 @@ impl<'block> BrilligBlock<'block> { .iter() .flat_map(|value_id| { let return_variable = self.convert_ssa_value(*value_id, dfg); - extract_registers(return_variable) + return_variable.extract_registers() }) .collect(); self.brillig_context.return_instruction(&return_registers); @@ -168,32 +168,44 @@ impl<'block> BrilligBlock<'block> { } /// Passes an arbitrary variable from the registers of the source to the registers of the destination - fn pass_variable(&mut self, source: RegisterOrMemory, destination: RegisterOrMemory) { + fn pass_variable(&mut self, source: BrilligVariable, destination: BrilligVariable) { match (source, destination) { ( - RegisterOrMemory::RegisterIndex(source_register), - RegisterOrMemory::RegisterIndex(destination_register), + BrilligVariable::Simple(source_register), + BrilligVariable::Simple(destination_register), ) => { self.brillig_context.mov_instruction(destination_register, source_register); } ( - RegisterOrMemory::HeapArray(HeapArray { pointer: source_pointer, .. }), - RegisterOrMemory::HeapArray(HeapArray { pointer: destination_pointer, .. }), + BrilligVariable::BrilligArray(BrilligArray { + pointer: source_pointer, + size: _, + rc: source_rc, + }), + BrilligVariable::BrilligArray(BrilligArray { + pointer: destination_pointer, + size: _, + rc: destination_rc, + }), ) => { self.brillig_context.mov_instruction(destination_pointer, source_pointer); + self.brillig_context.mov_instruction(destination_rc, source_rc); } ( - RegisterOrMemory::HeapVector(HeapVector { + BrilligVariable::BrilligVector(BrilligVector { pointer: source_pointer, size: source_size, + rc: source_rc, }), - RegisterOrMemory::HeapVector(HeapVector { + BrilligVariable::BrilligVector(BrilligVector { pointer: destination_pointer, size: destination_size, + rc: destination_rc, }), ) => { self.brillig_context.mov_instruction(destination_pointer, source_pointer); self.brillig_context.mov_instruction(destination_size, source_size); + self.brillig_context.mov_instruction(destination_rc, source_rc); } (_, _) => { unreachable!("ICE: Cannot pass value from {:?} to {:?}", source, destination); @@ -299,10 +311,11 @@ impl<'block> BrilligBlock<'block> { Value::ForeignFunction(func_name) => { let result_ids = dfg.instruction_results(instruction_id); - let input_registers = - vecmap(arguments, |value_id| self.convert_ssa_value(*value_id, dfg)); + let input_registers = vecmap(arguments, |value_id| { + self.convert_ssa_value(*value_id, dfg).to_register_or_memory() + }); let output_registers = vecmap(result_ids, |value_id| { - self.allocate_external_call_result(*value_id, dfg) + self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), @@ -388,7 +401,7 @@ impl<'block> BrilligBlock<'block> { // or an array in the case of an array. if let Type::Numeric(_) = dfg.type_of_value(param_id) { let len_variable = self.convert_ssa_value(arguments[0], dfg); - let len_register_index = extract_register(len_variable); + let len_register_index = len_variable.extract_register(); self.brillig_context.mov_instruction(result_register, len_register_index); } else { self.convert_ssa_array_len(arguments[0], result_register, dfg); @@ -422,7 +435,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ); - let target_len = extract_register(target_len_variable); + let target_len = target_len_variable.extract_register(); let target_slice = self.variables.define_variable( self.function_context, @@ -431,7 +444,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); - let heap_vec = self.brillig_context.extract_heap_vector(target_slice); + let heap_vec = target_slice.extract_vector(); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len, limb_count); @@ -456,7 +469,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ); - let target_len = extract_register(target_len_variable); + let target_len = target_len_variable.extract_register(); let target_slice = self.variables.define_variable( self.function_context, @@ -466,7 +479,7 @@ impl<'block> BrilligBlock<'block> { ); let radix = self.brillig_context.make_constant(2_usize.into()); - let heap_vec = self.brillig_context.extract_heap_vector(target_slice); + let heap_vec = target_slice.extract_vector(); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len, limb_count); @@ -523,8 +536,8 @@ impl<'block> BrilligBlock<'block> { let array_variable = self.convert_ssa_value(*array, dfg); let array_pointer = match array_variable { - RegisterOrMemory::HeapArray(HeapArray { pointer, .. }) => pointer, - RegisterOrMemory::HeapVector(HeapVector { pointer, .. }) => pointer, + BrilligVariable::BrilligArray(BrilligArray { pointer, .. }) => pointer, + BrilligVariable::BrilligVector(BrilligVector { pointer, .. }) => pointer, _ => unreachable!("ICE: array get on non-array"), }; @@ -601,10 +614,7 @@ impl<'block> BrilligBlock<'block> { // Convert the arguments to registers casting those to the types of the receiving function let argument_registers: Vec = arguments .iter() - .flat_map(|argument_id| { - let variable_to_pass = self.convert_ssa_value(*argument_id, dfg); - extract_registers(variable_to_pass) - }) + .flat_map(|argument_id| self.convert_ssa_value(*argument_id, dfg).extract_registers()) .collect(); let result_ids = dfg.instruction_results(instruction_id); @@ -640,7 +650,7 @@ impl<'block> BrilligBlock<'block> { // Collect the registers that should have been returned let returned_registers: Vec = variables_assigned_to .iter() - .flat_map(|returned_variable| extract_registers(*returned_variable)) + .flat_map(|returned_variable| returned_variable.extract_registers()) .collect(); assert!( @@ -657,17 +667,13 @@ impl<'block> BrilligBlock<'block> { &mut self, array_pointer: RegisterIndex, index_register: RegisterIndex, - destination_variable: RegisterOrMemory, + destination_variable: BrilligVariable, ) { match destination_variable { - RegisterOrMemory::RegisterIndex(destination_register) => { + BrilligVariable::Simple(destination_register) => { self.brillig_context.array_get(array_pointer, index_register, destination_register); } - RegisterOrMemory::HeapArray(HeapArray { pointer, .. }) => { - self.brillig_context.array_get(array_pointer, index_register, pointer); - } - RegisterOrMemory::HeapVector(..) => { - // Vectors are stored as references inside arrays to be able to match SSA indexes + BrilligVariable::BrilligArray(..) | BrilligVariable::BrilligVector(..) => { let reference = self.brillig_context.allocate_register(); self.brillig_context.array_get(array_pointer, index_register, reference); self.brillig_context.load_variable_instruction(destination_variable, reference); @@ -680,25 +686,25 @@ impl<'block> BrilligBlock<'block> { /// With a specific value changed. fn convert_ssa_array_set( &mut self, - source_variable: RegisterOrMemory, - destination_variable: RegisterOrMemory, + source_variable: BrilligVariable, + destination_variable: BrilligVariable, index_register: RegisterIndex, - value_variable: RegisterOrMemory, + value_variable: BrilligVariable, ) { let destination_pointer = match destination_variable { - RegisterOrMemory::HeapArray(HeapArray { pointer, .. }) => pointer, - RegisterOrMemory::HeapVector(HeapVector { pointer, .. }) => pointer, + BrilligVariable::BrilligArray(BrilligArray { pointer, .. }) => pointer, + BrilligVariable::BrilligVector(BrilligVector { pointer, .. }) => pointer, _ => unreachable!("ICE: array set returns non-array"), }; // First issue a array copy to the destination let (source_pointer, source_size_as_register) = match source_variable { - RegisterOrMemory::HeapArray(HeapArray { size, pointer }) => { + BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); self.brillig_context.const_instruction(source_size_register, size.into()); (pointer, source_size_register) } - RegisterOrMemory::HeapVector(HeapVector { size, pointer }) => { + BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); self.brillig_context.mov_instruction(source_size_register, size); (pointer, source_size_register) @@ -715,7 +721,7 @@ impl<'block> BrilligBlock<'block> { source_size_as_register, ); - if let RegisterOrMemory::HeapVector(HeapVector { size: target_size, .. }) = + if let BrilligVariable::BrilligVector(BrilligVector { size: target_size, .. }) = destination_variable { self.brillig_context.mov_instruction(target_size, source_size_as_register); @@ -731,17 +737,13 @@ impl<'block> BrilligBlock<'block> { &mut self, destination_pointer: RegisterIndex, index_register: RegisterIndex, - value_variable: RegisterOrMemory, + value_variable: BrilligVariable, ) { match value_variable { - RegisterOrMemory::RegisterIndex(value_register) => { + BrilligVariable::Simple(value_register) => { self.brillig_context.array_set(destination_pointer, index_register, value_register); } - RegisterOrMemory::HeapArray(HeapArray { pointer, .. }) => { - self.brillig_context.array_set(destination_pointer, index_register, pointer); - } - RegisterOrMemory::HeapVector(_) => { - // Vectors are stored as references inside arrays to be able to match SSA indexes + BrilligVariable::BrilligArray(_) | BrilligVariable::BrilligVector(_) => { let reference = self.brillig_context.allocate_register(); self.brillig_context.allocate_variable_instruction(reference); self.brillig_context.store_variable_instruction(reference, value_variable); @@ -773,7 +775,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -784,7 +786,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); let item_values = vecmap(&arguments[2..element_size + 2], |arg| { self.convert_ssa_value(*arg, dfg) }); @@ -800,7 +802,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -810,7 +812,7 @@ impl<'block> BrilligBlock<'block> { results[1], dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); let item_values = vecmap(&arguments[2..element_size + 2], |arg| { self.convert_ssa_value(*arg, dfg) }); @@ -826,7 +828,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -837,7 +839,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); let pop_variables = vecmap(&results[2..element_size + 2], |result| { self.variables.define_variable( @@ -859,7 +861,7 @@ impl<'block> BrilligBlock<'block> { results[element_size], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -878,7 +880,7 @@ impl<'block> BrilligBlock<'block> { results[element_size + 1], dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Sub); @@ -891,7 +893,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -903,7 +905,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); // Remove if indexing in insert is changed to flattened indexing // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 @@ -934,7 +936,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ) { - RegisterOrMemory::RegisterIndex(register_index) => register_index, + BrilligVariable::Simple(register_index) => register_index, _ => unreachable!("ICE: first value of a slice must be a register index"), }; @@ -946,7 +948,7 @@ impl<'block> BrilligBlock<'block> { target_id, dfg, ); - let target_vector = self.brillig_context.extract_heap_vector(target_variable); + let target_vector = target_variable.extract_vector(); // Remove if indexing in remove is changed to flattened indexing // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 @@ -1001,7 +1003,7 @@ impl<'block> BrilligBlock<'block> { binary_op: BinaryIntOp, ) { let source_len_variable = self.convert_ssa_value(source_value, dfg); - let source_len = extract_register(source_len_variable); + let source_len = source_len_variable.extract_register(); self.brillig_context.usize_op(source_len, target_len, binary_op, 1); } @@ -1067,7 +1069,7 @@ impl<'block> BrilligBlock<'block> { } /// Converts an SSA `ValueId` into a `RegisterOrMemory`. Initializes if necessary. - fn convert_ssa_value(&mut self, value_id: ValueId, dfg: &DataFlowGraph) -> RegisterOrMemory { + fn convert_ssa_value(&mut self, value_id: ValueId, dfg: &DataFlowGraph) -> BrilligVariable { let value_id = dfg.resolve(value_id); let value = &dfg[value_id]; @@ -1085,7 +1087,7 @@ impl<'block> BrilligBlock<'block> { } else { let new_variable = self.variables.allocate_constant(self.brillig_context, value_id, dfg); - let register_index = extract_register(new_variable); + let register_index = new_variable.extract_register(); self.brillig_context.const_instruction(register_index, (*constant).into()); new_variable @@ -1100,17 +1102,20 @@ impl<'block> BrilligBlock<'block> { // Initialize the variable let pointer = match new_variable { - RegisterOrMemory::HeapArray(heap_array) => { + BrilligVariable::BrilligArray(brillig_array) => { + self.brillig_context + .allocate_fixed_length_array(brillig_array.pointer, array.len()); self.brillig_context - .allocate_fixed_length_array(heap_array.pointer, array.len()); + .const_instruction(brillig_array.rc, 1_usize.into()); - heap_array.pointer + brillig_array.pointer } - RegisterOrMemory::HeapVector(heap_vector) => { + BrilligVariable::BrilligVector(heap_vector) => { self.brillig_context .const_instruction(heap_vector.size, array.len().into()); self.brillig_context .allocate_array_instruction(heap_vector.pointer, heap_vector.size); + self.brillig_context.const_instruction(heap_vector.rc, 1_usize.into()); heap_vector.pointer } @@ -1154,14 +1159,14 @@ impl<'block> BrilligBlock<'block> { dfg: &DataFlowGraph, ) -> RegisterIndex { let variable = self.convert_ssa_value(value_id, dfg); - extract_register(variable) + variable.extract_register() } fn allocate_external_call_result( &mut self, result: ValueId, dfg: &DataFlowGraph, - ) -> RegisterOrMemory { + ) -> BrilligVariable { let typ = dfg[result].get_type(); match typ { Type::Numeric(_) => self.variables.define_variable( @@ -1178,8 +1183,10 @@ impl<'block> BrilligBlock<'block> { result, dfg, ); - let array = extract_heap_array(variable); + let array = variable.extract_array(); self.brillig_context.allocate_fixed_length_array(array.pointer, array.size); + self.brillig_context.const_instruction(array.rc, 1_usize.into()); + variable } Type::Slice(_) => { @@ -1189,12 +1196,14 @@ impl<'block> BrilligBlock<'block> { result, dfg, ); - let vector = self.brillig_context.extract_heap_vector(variable); + let vector = variable.extract_vector(); // Set the pointer to the current stack frame // The stack pointer will then be updated by the caller of this method // once the external call is resolved and the array size is known self.brillig_context.set_array_pointer(vector.pointer); + self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + variable } _ => { @@ -1216,11 +1225,11 @@ impl<'block> BrilligBlock<'block> { let element_size = dfg.type_of_value(array_id).element_size(); match array_variable { - RegisterOrMemory::HeapArray(HeapArray { size, .. }) => { + BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { self.brillig_context .const_instruction(result_register, (size / element_size).into()); } - RegisterOrMemory::HeapVector(HeapVector { size, .. }) => { + BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { self.brillig_context.usize_op( size, result_register, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index 8fde654a402..f2e698c0aa9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -1,8 +1,11 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; +use acvm::brillig_vm::brillig::RegisterIndex; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ - brillig::brillig_ir::{extract_register, BrilligContext}, + brillig::brillig_ir::{ + brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}, + BrilligContext, + }, ssa::ir::{ basic_block::BasicBlockId, dfg::DataFlowGraph, @@ -16,7 +19,7 @@ use super::brillig_fn::FunctionContext; #[derive(Debug, Default)] pub(crate) struct BlockVariables { available_variables: HashSet, - available_constants: HashMap, + available_constants: HashMap, } impl BlockVariables { @@ -32,7 +35,7 @@ impl BlockVariables { pub(crate) fn get_available_variables( &self, function_context: &FunctionContext, - ) -> Vec { + ) -> Vec { self.available_variables .iter() .map(|value_id| { @@ -52,7 +55,7 @@ impl BlockVariables { brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, - ) -> RegisterOrMemory { + ) -> BrilligVariable { let value_id = dfg.resolve(value_id); let variable = allocate_value(value_id, brillig_context, dfg); @@ -74,7 +77,7 @@ impl BlockVariables { dfg: &DataFlowGraph, ) -> RegisterIndex { let variable = self.define_variable(function_context, brillig_context, value, dfg); - extract_register(variable) + variable.extract_register() } /// Removes a variable so it's not used anymore within this block. @@ -88,7 +91,7 @@ impl BlockVariables { function_context: &FunctionContext, value_id: ValueId, dfg: &DataFlowGraph, - ) -> RegisterOrMemory { + ) -> BrilligVariable { let value_id = dfg.resolve(value_id); if let Some(constant) = self.available_constants.get(&value_id) { *constant @@ -112,7 +115,7 @@ impl BlockVariables { brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, - ) -> RegisterOrMemory { + ) -> BrilligVariable { let value_id = dfg.resolve(value_id); let constant = allocate_value(value_id, brillig_context, dfg); self.available_constants.insert(value_id, constant); @@ -124,7 +127,7 @@ impl BlockVariables { &mut self, value_id: ValueId, dfg: &DataFlowGraph, - ) -> Option { + ) -> Option { let value_id = dfg.resolve(value_id); self.available_constants.get(&value_id).cloned() } @@ -141,7 +144,7 @@ impl BlockVariables { block_id: BasicBlockId, value_id: ValueId, dfg: &DataFlowGraph, - ) -> RegisterOrMemory { + ) -> BrilligVariable { let value_id = dfg.resolve(value_id); assert!( function_context @@ -166,25 +169,34 @@ pub(crate) fn allocate_value( value_id: ValueId, brillig_context: &mut BrilligContext, dfg: &DataFlowGraph, -) -> RegisterOrMemory { +) -> BrilligVariable { let typ = dfg.type_of_value(value_id); match typ { Type::Numeric(_) | Type::Reference(_) => { let register = brillig_context.allocate_register(); - RegisterOrMemory::RegisterIndex(register) + BrilligVariable::Simple(register) } Type::Array(item_typ, elem_count) => { let pointer_register = brillig_context.allocate_register(); + let rc_register = brillig_context.allocate_register(); let size = compute_array_length(&item_typ, elem_count); - RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_register, size }) + + BrilligVariable::BrilligArray(BrilligArray { + pointer: pointer_register, + size, + rc: rc_register, + }) } Type::Slice(_) => { let pointer_register = brillig_context.allocate_register(); let size_register = brillig_context.allocate_register(); - RegisterOrMemory::HeapVector(HeapVector { + let rc_register = brillig_context.allocate_register(); + + BrilligVariable::BrilligVector(BrilligVector { pointer: pointer_register, size: size_register, + rc: rc_register, }) } Type::Function => { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 42f834fc35c..026def4ef11 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -1,9 +1,9 @@ -use acvm::brillig_vm::brillig::RegisterOrMemory; use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ artifact::{BrilligParameter, Label}, + brillig_variable::BrilligVariable, BrilligContext, }, ssa::ir::{ @@ -21,7 +21,7 @@ use super::{brillig_block_variables::allocate_value, variable_liveness::Variable pub(crate) struct FunctionContext { pub(crate) function_id: FunctionId, /// Map from SSA values its allocation. Since values can be only defined once in SSA form, we insert them here on when we allocate them at their definition. - pub(crate) ssa_value_allocations: HashMap, + pub(crate) ssa_value_allocations: HashMap, /// Block parameters are pre allocated at the function level. pub(crate) block_parameters: HashMap>, /// The block ids of the function in reverse post order. diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 211d670e7d8..bfe53623122 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -1,13 +1,15 @@ -use acvm::brillig_vm::brillig::{BinaryIntOp, HeapVector, RegisterIndex, RegisterOrMemory}; +use acvm::brillig_vm::brillig::{BinaryIntOp, RegisterIndex}; + +use crate::brillig::brillig_ir::brillig_variable::{BrilligVariable, BrilligVector}; use super::brillig_block::BrilligBlock; impl<'block> BrilligBlock<'block> { pub(crate) fn slice_push_back_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, - variables_to_insert: &[RegisterOrMemory], + target_vector: BrilligVector, + source_vector: BrilligVector, + variables_to_insert: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by variables_to_insert.len() self.brillig_context.usize_op( @@ -40,9 +42,9 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn slice_push_front_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, - variables_to_insert: &[RegisterOrMemory], + target_vector: BrilligVector, + source_vector: BrilligVector, + variables_to_insert: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by variables_to_insert.len() self.brillig_context.usize_op( @@ -81,9 +83,9 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn slice_pop_front_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, - removed_items: &[RegisterOrMemory], + target_vector: BrilligVector, + source_vector: BrilligVector, + removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() self.brillig_context.usize_op( @@ -121,9 +123,9 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn slice_pop_back_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, - removed_items: &[RegisterOrMemory], + target_vector: BrilligVector, + source_vector: BrilligVector, + removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() self.brillig_context.usize_op( @@ -156,10 +158,10 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn slice_insert_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, + target_vector: BrilligVector, + source_vector: BrilligVector, index: RegisterIndex, - items: &[RegisterOrMemory], + items: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by items.len() self.brillig_context.usize_op( @@ -226,10 +228,10 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn slice_remove_operation( &mut self, - target_vector: HeapVector, - source_vector: HeapVector, + target_vector: BrilligVector, + source_vector: BrilligVector, index: RegisterIndex, - removed_items: &[RegisterOrMemory], + removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() self.brillig_context.usize_op( @@ -297,11 +299,11 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn convert_array_or_vector_to_vector( &mut self, - source_variable: RegisterOrMemory, - ) -> HeapVector { + source_variable: BrilligVariable, + ) -> BrilligVector { match source_variable { - RegisterOrMemory::HeapVector(source_vector) => source_vector, - RegisterOrMemory::HeapArray(source_array) => { + BrilligVariable::BrilligVector(source_vector) => source_vector, + BrilligVariable::BrilligArray(source_array) => { self.brillig_context.array_to_vector(&source_array) } _ => unreachable!("ICE: unsupported slice push back source {:?}", source_variable), @@ -309,452 +311,452 @@ impl<'block> BrilligBlock<'block> { } } -#[cfg(test)] -mod tests { - use std::vec; - - use acvm::acir::brillig::{HeapVector, Value}; - use acvm::brillig_vm::brillig::{RegisterIndex, RegisterOrMemory}; - - use crate::brillig::brillig_gen::brillig_block::BrilligBlock; - use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; - use crate::brillig::brillig_gen::brillig_fn::FunctionContext; - use crate::brillig::brillig_ir::artifact::BrilligParameter; - use crate::brillig::brillig_ir::tests::{ - create_and_run_vm, create_context, create_entry_point_bytecode, - }; - use crate::brillig::brillig_ir::BrilligContext; - use crate::ssa::function_builder::FunctionBuilder; - use crate::ssa::ir::function::RuntimeType; - use crate::ssa::ir::map::Id; - use crate::ssa::ssa_gen::Ssa; - - fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { - let builder = - FunctionBuilder::new("main".to_string(), Id::test_new(0), RuntimeType::Brillig); - let ssa = builder.finish(); - let mut brillig_context = create_context(); - - let function_context = FunctionContext::new(ssa.main(), &mut brillig_context); - (ssa, function_context, brillig_context) - } - - fn create_brillig_block<'a>( - function_context: &'a mut FunctionContext, - brillig_context: &'a mut BrilligContext, - ) -> BrilligBlock<'a> { - let variables = BlockVariables::default(); - BrilligBlock { - function_context, - block_id: Id::test_new(0), - brillig_context, - variables, - last_uses: Default::default(), - } - } - - #[test] - fn test_slice_push_operation() { - fn test_case_push( - push_back: bool, - array: Vec, - expected_mem: Vec, - item_to_push: Value, - ) { - let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, - ]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), - BrilligParameter::Simple, - ]; - - let (_, mut function_context, mut context) = create_test_environment(); - - // Allocate the parameters - let array_pointer = context.allocate_register(); - let item_to_insert = context.allocate_register(); - - // Cast the source array to a vector - let array_size = context.make_constant(array.len().into()); - - // Allocate the results - let copied_array_pointer = context.allocate_register(); - let copied_array_size = context.allocate_register(); - - let mut block = create_brillig_block(&mut function_context, &mut context); - - if push_back { - block.slice_push_back_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - &[RegisterOrMemory::RegisterIndex(item_to_insert)], - ); - } else { - block.slice_push_front_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - &[RegisterOrMemory::RegisterIndex(item_to_insert)], - ); - } - - context.return_instruction(&[copied_array_pointer, copied_array_size]); - - let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm( - array.clone(), - vec![Value::from(0_usize), item_to_push], - &bytecode, - ); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); - } - - test_case_push( - true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), - ], - Value::from(27_usize), - ); - test_case_push(true, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); - test_case_push( - false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - ], - Value::from(27_usize), - ); - test_case_push(false, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); - } - - #[test] - fn test_slice_pop_back_operation() { - fn test_case_pop( - pop_back: bool, - array: Vec, - expected_mem: Vec, - expected_removed_item: Value, - ) { - let arguments = - vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len())]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), - BrilligParameter::Simple, - BrilligParameter::Simple, - ]; - - let (_, mut function_context, mut context) = create_test_environment(); - - // Allocate the parameters - let array_pointer = context.allocate_register(); - - // Cast the source array to a vector - let array_size = context.make_constant(array.len().into()); - - // Allocate the results - let copied_array_pointer = context.allocate_register(); - let removed_item = context.allocate_register(); - - let copied_array_size = context.allocate_register(); - - let mut block = create_brillig_block(&mut function_context, &mut context); - - if pop_back { - block.slice_pop_back_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - &[RegisterOrMemory::RegisterIndex(removed_item)], - ); - } else { - block.slice_pop_front_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - &[RegisterOrMemory::RegisterIndex(removed_item)], - ); - } - - context.return_instruction(&[copied_array_pointer, copied_array_size, removed_item]); - - let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize)], &bytecode); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); - assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); - } - - test_case_pop( - true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - ], - Value::from(3_usize), - ); - test_case_pop( - true, - vec![Value::from(1_usize)], - vec![Value::from(1_usize)], - Value::from(1_usize), - ); - test_case_pop( - false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(2_usize), - Value::from(3_usize), - ], - Value::from(1_usize), - ); - } - - #[test] - fn test_slice_insert_operation() { - fn test_case_insert( - array: Vec, - expected_mem: Vec, - item: Value, - index: Value, - ) { - let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, - BrilligParameter::Simple, - ]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), - BrilligParameter::Simple, - ]; - - let (_, mut function_context, mut context) = create_test_environment(); - - // Allocate the parameters - let array_pointer = context.allocate_register(); - let item_to_insert = context.allocate_register(); - let index_to_insert = context.allocate_register(); - - // Cast the source array to a vector - let array_size = context.make_constant(array.len().into()); - - // Allocate the results - let copied_array_pointer = context.allocate_register(); - - let copied_array_size = context.allocate_register(); - - let mut block = create_brillig_block(&mut function_context, &mut context); - - block.slice_insert_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - index_to_insert, - &[RegisterOrMemory::RegisterIndex(item_to_insert)], - ); - - context.return_instruction(&[copied_array_pointer, copied_array_size]); - - let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm( - array.clone(), - vec![Value::from(0_usize), item, index], - &bytecode, - ); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); - } - - test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(27_usize), - Value::from(2_usize), - Value::from(3_usize), - ], - Value::from(27_usize), - Value::from(1_usize), - ); - - test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - ], - Value::from(27_usize), - Value::from(0_usize), - ); - test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(27_usize), - Value::from(3_usize), - ], - Value::from(27_usize), - Value::from(2_usize), - ); - test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), - ], - Value::from(27_usize), - Value::from(3_usize), - ); - test_case_insert( - vec![], - vec![Value::from(27_usize)], - Value::from(27_usize), - Value::from(0_usize), - ); - } - - #[test] - fn test_slice_remove_operation() { - fn test_case_remove( - array: Vec, - expected_mem: Vec, - index: Value, - expected_removed_item: Value, - ) { - let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, - ]; - let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), - BrilligParameter::Simple, - BrilligParameter::Simple, - ]; - - let (_, mut function_context, mut context) = create_test_environment(); - - // Allocate the parameters - let array_pointer = context.allocate_register(); - let index_to_insert = context.allocate_register(); - - // Cast the source array to a vector - let array_size = context.make_constant(array.len().into()); - - // Allocate the results - let copied_array_pointer = context.allocate_register(); - let removed_item = context.allocate_register(); - - let copied_array_size = context.allocate_register(); - - let mut block = create_brillig_block(&mut function_context, &mut context); - - block.slice_remove_operation( - HeapVector { pointer: copied_array_pointer, size: copied_array_size }, - HeapVector { pointer: array_pointer, size: array_size }, - index_to_insert, - &[RegisterOrMemory::RegisterIndex(removed_item)], - ); - - context.return_instruction(&[copied_array_pointer, copied_array_size, removed_item]); - - let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; - let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize), index], &bytecode); - - assert_eq!(vm.get_memory(), &expected_mem); - - assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); - assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); - assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); - } - - test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(2_usize), - Value::from(3_usize), - ], - Value::from(0_usize), - Value::from(1_usize), - ); - - test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(3_usize), - ], - Value::from(1_usize), - Value::from(2_usize), - ); - - test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(1_usize), - Value::from(2_usize), - ], - Value::from(2_usize), - Value::from(3_usize), - ); - test_case_remove( - vec![Value::from(1_usize)], - vec![Value::from(1_usize)], - Value::from(0_usize), - Value::from(1_usize), - ); - } -} +// #[cfg(test)] +// mod tests { +// use std::vec; + +// use acvm::acir::brillig::{HeapVector, Value}; +// use acvm::brillig_vm::brillig::{RegisterIndex, RegisterOrMemory}; + +// use crate::brillig::brillig_gen::brillig_block::BrilligBlock; +// use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; +// use crate::brillig::brillig_gen::brillig_fn::FunctionContext; +// use crate::brillig::brillig_ir::artifact::BrilligParameter; +// use crate::brillig::brillig_ir::tests::{ +// create_and_run_vm, create_context, create_entry_point_bytecode, +// }; +// use crate::brillig::brillig_ir::BrilligContext; +// use crate::ssa::function_builder::FunctionBuilder; +// use crate::ssa::ir::function::RuntimeType; +// use crate::ssa::ir::map::Id; +// use crate::ssa::ssa_gen::Ssa; + +// fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { +// let builder = +// FunctionBuilder::new("main".to_string(), Id::test_new(0), RuntimeType::Brillig); +// let ssa = builder.finish(); +// let mut brillig_context = create_context(); + +// let function_context = FunctionContext::new(ssa.main(), &mut brillig_context); +// (ssa, function_context, brillig_context) +// } + +// fn create_brillig_block<'a>( +// function_context: &'a mut FunctionContext, +// brillig_context: &'a mut BrilligContext, +// ) -> BrilligBlock<'a> { +// let variables = BlockVariables::default(); +// BrilligBlock { +// function_context, +// block_id: Id::test_new(0), +// brillig_context, +// variables, +// last_uses: Default::default(), +// } +// } + +// #[test] +// fn test_slice_push_operation() { +// fn test_case_push( +// push_back: bool, +// array: Vec, +// expected_mem: Vec, +// item_to_push: Value, +// ) { +// let arguments = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), +// BrilligParameter::Simple, +// ]; +// let returns = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), +// BrilligParameter::Simple, +// ]; + +// let (_, mut function_context, mut context) = create_test_environment(); + +// // Allocate the parameters +// let array_pointer = context.allocate_register(); +// let item_to_insert = context.allocate_register(); + +// // Cast the source array to a vector +// let array_size = context.make_constant(array.len().into()); + +// // Allocate the results +// let copied_array_pointer = context.allocate_register(); +// let copied_array_size = context.allocate_register(); + +// let mut block = create_brillig_block(&mut function_context, &mut context); + +// if push_back { +// block.slice_push_back_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// &[RegisterOrMemory::RegisterIndex(item_to_insert)], +// ); +// } else { +// block.slice_push_front_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// &[RegisterOrMemory::RegisterIndex(item_to_insert)], +// ); +// } + +// context.return_instruction(&[copied_array_pointer, copied_array_size]); + +// let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; +// let vm = create_and_run_vm( +// array.clone(), +// vec![Value::from(0_usize), item_to_push], +// &bytecode, +// ); + +// assert_eq!(vm.get_memory(), &expected_mem); + +// assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); +// assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); +// } + +// test_case_push( +// true, +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(27_usize), +// ], +// Value::from(27_usize), +// ); +// test_case_push(true, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); +// test_case_push( +// false, +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(27_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// ], +// Value::from(27_usize), +// ); +// test_case_push(false, vec![], vec![Value::from(27_usize)], Value::from(27_usize)); +// } + +// #[test] +// fn test_slice_pop_back_operation() { +// fn test_case_pop( +// pop_back: bool, +// array: Vec, +// expected_mem: Vec, +// expected_removed_item: Value, +// ) { +// let arguments = +// vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len())]; +// let returns = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), +// BrilligParameter::Simple, +// BrilligParameter::Simple, +// ]; + +// let (_, mut function_context, mut context) = create_test_environment(); + +// // Allocate the parameters +// let array_pointer = context.allocate_register(); + +// // Cast the source array to a vector +// let array_size = context.make_constant(array.len().into()); + +// // Allocate the results +// let copied_array_pointer = context.allocate_register(); +// let removed_item = context.allocate_register(); + +// let copied_array_size = context.allocate_register(); + +// let mut block = create_brillig_block(&mut function_context, &mut context); + +// if pop_back { +// block.slice_pop_back_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// &[RegisterOrMemory::RegisterIndex(removed_item)], +// ); +// } else { +// block.slice_pop_front_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// &[RegisterOrMemory::RegisterIndex(removed_item)], +// ); +// } + +// context.return_instruction(&[copied_array_pointer, copied_array_size, removed_item]); + +// let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; +// let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize)], &bytecode); + +// assert_eq!(vm.get_memory(), &expected_mem); + +// assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); +// assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); +// assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); +// } + +// test_case_pop( +// true, +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// ], +// Value::from(3_usize), +// ); +// test_case_pop( +// true, +// vec![Value::from(1_usize)], +// vec![Value::from(1_usize)], +// Value::from(1_usize), +// ); +// test_case_pop( +// false, +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// ], +// Value::from(1_usize), +// ); +// } + +// #[test] +// fn test_slice_insert_operation() { +// fn test_case_insert( +// array: Vec, +// expected_mem: Vec, +// item: Value, +// index: Value, +// ) { +// let arguments = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), +// BrilligParameter::Simple, +// BrilligParameter::Simple, +// ]; +// let returns = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1), +// BrilligParameter::Simple, +// ]; + +// let (_, mut function_context, mut context) = create_test_environment(); + +// // Allocate the parameters +// let array_pointer = context.allocate_register(); +// let item_to_insert = context.allocate_register(); +// let index_to_insert = context.allocate_register(); + +// // Cast the source array to a vector +// let array_size = context.make_constant(array.len().into()); + +// // Allocate the results +// let copied_array_pointer = context.allocate_register(); + +// let copied_array_size = context.allocate_register(); + +// let mut block = create_brillig_block(&mut function_context, &mut context); + +// block.slice_insert_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// index_to_insert, +// &[RegisterOrMemory::RegisterIndex(item_to_insert)], +// ); + +// context.return_instruction(&[copied_array_pointer, copied_array_size]); + +// let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; +// let vm = create_and_run_vm( +// array.clone(), +// vec![Value::from(0_usize), item, index], +// &bytecode, +// ); + +// assert_eq!(vm.get_memory(), &expected_mem); + +// assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); +// assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() + 1)); +// } + +// test_case_insert( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(27_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// ], +// Value::from(27_usize), +// Value::from(1_usize), +// ); + +// test_case_insert( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(27_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// ], +// Value::from(27_usize), +// Value::from(0_usize), +// ); +// test_case_insert( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(27_usize), +// Value::from(3_usize), +// ], +// Value::from(27_usize), +// Value::from(2_usize), +// ); +// test_case_insert( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(27_usize), +// ], +// Value::from(27_usize), +// Value::from(3_usize), +// ); +// test_case_insert( +// vec![], +// vec![Value::from(27_usize)], +// Value::from(27_usize), +// Value::from(0_usize), +// ); +// } + +// #[test] +// fn test_slice_remove_operation() { +// fn test_case_remove( +// array: Vec, +// expected_mem: Vec, +// index: Value, +// expected_removed_item: Value, +// ) { +// let arguments = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), +// BrilligParameter::Simple, +// ]; +// let returns = vec![ +// BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), +// BrilligParameter::Simple, +// BrilligParameter::Simple, +// ]; + +// let (_, mut function_context, mut context) = create_test_environment(); + +// // Allocate the parameters +// let array_pointer = context.allocate_register(); +// let index_to_insert = context.allocate_register(); + +// // Cast the source array to a vector +// let array_size = context.make_constant(array.len().into()); + +// // Allocate the results +// let copied_array_pointer = context.allocate_register(); +// let removed_item = context.allocate_register(); + +// let copied_array_size = context.allocate_register(); + +// let mut block = create_brillig_block(&mut function_context, &mut context); + +// block.slice_remove_operation( +// HeapVector { pointer: copied_array_pointer, size: copied_array_size }, +// HeapVector { pointer: array_pointer, size: array_size }, +// index_to_insert, +// &[RegisterOrMemory::RegisterIndex(removed_item)], +// ); + +// context.return_instruction(&[copied_array_pointer, copied_array_size, removed_item]); + +// let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; +// let vm = create_and_run_vm(array.clone(), vec![Value::from(0_usize), index], &bytecode); + +// assert_eq!(vm.get_memory(), &expected_mem); + +// assert_eq!(vm.get_registers().get(RegisterIndex(0)), Value::from(array.len())); +// assert_eq!(vm.get_registers().get(RegisterIndex(1)), Value::from(array.len() - 1)); +// assert_eq!(vm.get_registers().get(RegisterIndex(2)), expected_removed_item); +// } + +// test_case_remove( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// ], +// Value::from(0_usize), +// Value::from(1_usize), +// ); + +// test_case_remove( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(3_usize), +// ], +// Value::from(1_usize), +// Value::from(2_usize), +// ); + +// test_case_remove( +// vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], +// vec![ +// Value::from(1_usize), +// Value::from(2_usize), +// Value::from(3_usize), +// Value::from(1_usize), +// Value::from(2_usize), +// ], +// Value::from(2_usize), +// Value::from(3_usize), +// ); +// test_case_remove( +// vec![Value::from(1_usize)], +// vec![Value::from(1_usize)], +// Value::from(0_usize), +// Value::from(1_usize), +// ); +// } +// } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 591346e5b4d..daaf88d2be4 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -5,6 +5,7 @@ //! ssa types and types in this module. //! A similar paradigm can be seen with the `acir_ir` module. pub(crate) mod artifact; +pub(crate) mod brillig_variable; pub(crate) mod debug_show; pub(crate) mod registers; @@ -14,6 +15,7 @@ use crate::ssa::ir::dfg::CallStack; use self::{ artifact::{BrilligArtifact, UnresolvedJumpLocation}, + brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}, registers::BrilligRegistersContext, }; use acvm::{ @@ -166,8 +168,8 @@ impl BrilligContext { /// pointer to the array in `pointer_register` pub(crate) fn allocate_variable_instruction(&mut self, pointer_register: RegisterIndex) { self.debug_show.allocate_instruction(pointer_register); - // A variable can be stored in up to two values, so we reserve two values for that. - let size_register = self.make_constant(2_u128.into()); + // A variable can be stored in up to three values, so we reserve three values for that. + let size_register = self.make_constant(3_u128.into()); self.push_opcode(BrilligOpcode::Mov { destination: pointer_register, source: ReservedRegisters::stack_pointer(), @@ -567,17 +569,24 @@ impl BrilligContext { /// Loads a variable stored previously pub(crate) fn load_variable_instruction( &mut self, - destination: RegisterOrMemory, + destination: BrilligVariable, variable_pointer: RegisterIndex, ) { match destination { - RegisterOrMemory::RegisterIndex(register_index) => { + BrilligVariable::Simple(register_index) => { self.load_instruction(register_index, variable_pointer); } - RegisterOrMemory::HeapArray(HeapArray { pointer, .. }) => { + BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { self.load_instruction(pointer, variable_pointer); + + let rc_pointer = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); + + self.load_instruction(rc, rc_pointer); + self.deallocate_register(rc_pointer); } - RegisterOrMemory::HeapVector(HeapVector { pointer, size }) => { + BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { self.load_instruction(pointer, variable_pointer); let size_pointer = self.allocate_register(); @@ -586,6 +595,13 @@ impl BrilligContext { self.load_instruction(size, size_pointer); self.deallocate_register(size_pointer); + + let rc_pointer = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); + + self.load_instruction(rc, rc_pointer); + self.deallocate_register(rc_pointer); } } } @@ -604,32 +620,39 @@ impl BrilligContext { pub(crate) fn store_variable_instruction( &mut self, variable_pointer: RegisterIndex, - source: RegisterOrMemory, + source: BrilligVariable, ) { let size_pointer = self.allocate_register(); self.mov_instruction(size_pointer, variable_pointer); self.usize_op_in_place(size_pointer, BinaryIntOp::Add, 1_usize); + let rc_pointer = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); match source { - RegisterOrMemory::RegisterIndex(register_index) => { + BrilligVariable::Simple(register_index) => { self.store_instruction(variable_pointer, register_index); let size_constant = self.make_constant(Value::from(1_usize)); self.store_instruction(size_pointer, size_constant); self.deallocate_register(size_constant); } - RegisterOrMemory::HeapArray(HeapArray { pointer, size }) => { + BrilligVariable::BrilligArray(BrilligArray { pointer, size, rc }) => { self.store_instruction(variable_pointer, pointer); let size_constant = self.make_constant(Value::from(size)); self.store_instruction(size_pointer, size_constant); self.deallocate_register(size_constant); + self.store_instruction(size_pointer, size_constant); + self.store_instruction(rc_pointer, rc); } - RegisterOrMemory::HeapVector(HeapVector { pointer, size }) => { + BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { self.store_instruction(variable_pointer, pointer); self.store_instruction(size_pointer, size); + self.store_instruction(rc_pointer, rc); } } self.deallocate_register(size_pointer); + self.deallocate_register(rc_pointer); } /// Emits a truncate instruction. @@ -764,14 +787,14 @@ impl BrilligContext { } /// Saves all of the registers that have been used up until this point. - fn save_registers_of_vars(&mut self, vars: &[RegisterOrMemory]) -> Vec { + fn save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { // Save all of the used registers at this point in memory // because the function call will/may overwrite them. // // Note that here it is important that the stack pointer register is at register 0, // as after the first register save we add to the pointer. let mut used_registers: Vec<_> = - vars.iter().flat_map(|var| extract_registers(*var)).collect(); + vars.iter().flat_map(|var| var.extract_registers()).collect(); // Also dump the previous stack pointer used_registers.push(ReservedRegisters::previous_stack_pointer()); @@ -850,7 +873,7 @@ impl BrilligContext { pub(crate) fn pre_call_save_registers_prep_args( &mut self, arguments: &[RegisterIndex], - variables_to_save: &[RegisterOrMemory], + variables_to_save: &[BrilligVariable], ) -> Vec { // Save all the registers we have used to the stack. let saved_registers = self.save_registers_of_vars(variables_to_save); @@ -891,9 +914,9 @@ impl BrilligContext { } /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. - pub(crate) fn array_to_vector(&mut self, array: &HeapArray) -> HeapVector { + pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { let size_register = self.make_constant(array.size.into()); - HeapVector { size: size_register, pointer: array.pointer } + BrilligVector { size: size_register, pointer: array.pointer, rc: array.rc } } /// Issues a blackbox operation. @@ -907,7 +930,7 @@ impl BrilligContext { pub(crate) fn radix_instruction( &mut self, source: RegisterIndex, - target_vector: HeapVector, + target_vector: BrilligVector, radix: RegisterIndex, limb_count: RegisterIndex, big_endian: bool, @@ -953,7 +976,7 @@ impl BrilligContext { } /// This instruction will reverse the order of the elements in a vector. - pub(crate) fn reverse_vector_in_place_instruction(&mut self, vector: HeapVector) { + pub(crate) fn reverse_vector_in_place_instruction(&mut self, vector: BrilligVector) { let iteration_count = self.allocate_register(); self.usize_op(vector.size, iteration_count, BinaryIntOp::UnsignedDiv, 2); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs new file mode 100644 index 00000000000..f182e3c61c2 --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -0,0 +1,80 @@ +use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +pub struct BrilligArray { + pub pointer: RegisterIndex, + pub size: usize, + pub rc: RegisterIndex, +} + +impl BrilligArray { + pub(crate) fn to_heap_array(self) -> HeapArray { + HeapArray { pointer: self.pointer, size: self.size } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +pub struct BrilligVector { + pub pointer: RegisterIndex, + pub size: RegisterIndex, + pub rc: RegisterIndex, +} + +impl BrilligVector { + pub(crate) fn to_heap_vector(self) -> HeapVector { + HeapVector { pointer: self.pointer, size: self.size } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +pub enum BrilligVariable { + Simple(RegisterIndex), + BrilligArray(BrilligArray), + BrilligVector(BrilligVector), +} + +impl BrilligVariable { + pub(crate) fn extract_register(self) -> RegisterIndex { + match self { + BrilligVariable::Simple(register_index) => register_index, + _ => unreachable!("ICE: Expected register, got {self:?}"), + } + } + + pub(crate) fn extract_array(self) -> BrilligArray { + match self { + BrilligVariable::BrilligArray(array) => array, + _ => unreachable!("ICE: Expected array, got {self:?}"), + } + } + + pub(crate) fn extract_vector(self) -> BrilligVector { + match self { + BrilligVariable::BrilligVector(vector) => vector, + _ => unreachable!("ICE: Expected vector, got {self:?}"), + } + } + + pub(crate) fn extract_registers(self) -> Vec { + match self { + BrilligVariable::Simple(register_index) => vec![register_index], + BrilligVariable::BrilligArray(array) => vec![array.pointer, array.rc], + BrilligVariable::BrilligVector(vector) => vec![vector.pointer, vector.size, vector.rc], + } + } + + pub(crate) fn to_register_or_memory(self) -> RegisterOrMemory { + match self { + BrilligVariable::Simple(register_index) => { + RegisterOrMemory::RegisterIndex(register_index) + } + BrilligVariable::BrilligArray(array) => { + RegisterOrMemory::HeapArray(array.to_heap_array()) + } + BrilligVariable::BrilligVector(vector) => { + RegisterOrMemory::HeapVector(vector.to_heap_vector()) + } + } + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 185be980d15..5d0cfac99f5 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -2,6 +2,7 @@ use crate::brillig::brillig_ir::ReservedRegisters; use super::{ artifact::{BrilligArtifact, BrilligParameter}, + brillig_variable::{BrilligArray, BrilligVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, BrilligContext, @@ -36,15 +37,35 @@ impl BrilligContext { /// /// And sets the starting value of the reserved registers fn entry_point_instruction(&mut self, arguments: Vec) { - // Translate the inputs by the reserved registers offset - for i in (0..arguments.len()).rev() { - self.push_opcode(BrilligOpcode::Mov { - destination: ReservedRegisters::user_register_index(i), - source: RegisterIndex::from(i), - }); - // Make sure we don't overwrite the arguments - self.allocate_register(); - } + let preallocated_registers: Vec<_> = + arguments.iter().enumerate().map(|(i, _)| RegisterIndex::from(i)).collect(); + self.set_allocated_registers(preallocated_registers.clone()); + + let argument_variables: Vec<_> = arguments + .iter() + .zip(preallocated_registers) + .map(|(argument, param_register)| { + match argument { + BrilligParameter::Simple => { + let variable_register = self.allocate_register(); + self.mov_instruction(variable_register, param_register); + BrilligVariable::Simple(variable_register) + } + BrilligParameter::Array(..) => { + let pointer_register = self.allocate_register(); + let rc_register = self.allocate_register(); + self.mov_instruction(pointer_register, param_register); + self.const_instruction(rc_register, 1_usize.into()); + BrilligVariable::BrilligArray(BrilligArray { + pointer: pointer_register, + size: 0, // TODO + rc: rc_register, + }) + } + BrilligParameter::Slice(_) => unimplemented!("Unsupported slices as parameter"), + } + }) + .collect(); // Calculate the initial value for the stack pointer register let size_arguments_memory: usize = arguments @@ -66,16 +87,23 @@ impl BrilligContext { value: 0_usize.into(), }); - for (index, parameter) in arguments.iter().enumerate() { + for (parameter, assigned_variable) in arguments.iter().zip(&argument_variables) { if let BrilligParameter::Array(item_type, item_count) = parameter { if item_type.iter().any(|param| !matches!(param, BrilligParameter::Simple)) { - let pointer_register = ReservedRegisters::user_register_index(index); + let pointer_register = assigned_variable.extract_array().pointer; let deflattened_register = self.deflatten_array(item_type, *item_count, pointer_register); self.mov_instruction(pointer_register, deflattened_register); } } } + + // Move the parameters to the first user defined registers + for (i, register) in + argument_variables.into_iter().flat_map(|arg| arg.extract_registers()).enumerate() + { + self.mov_instruction(ReservedRegisters::user_register_index(i), register); + } } /// Computes the size of a parameter if it was flattened @@ -93,6 +121,7 @@ impl BrilligContext { } /// Deflatten an array by recursively allocating nested arrays and copying the plain values. + /// Returns the pointer to the deflattened items. fn deflatten_array( &mut self, item_type: &[BrilligParameter], @@ -140,13 +169,25 @@ impl BrilligContext { *nested_array_item_count, nested_array_pointer, ); - self.array_set( - deflattened_array_pointer, - target_index, - deflattened_nested_array_pointer, + let reference = self.allocate_register(); + let rc = self.allocate_register(); + self.const_instruction(rc, 1_usize.into()); + + self.allocate_variable_instruction(reference); + self.store_variable_instruction( + reference, + BrilligVariable::BrilligArray(BrilligArray { + pointer: deflattened_nested_array_pointer, + size: 0, // TODO + rc, + }), ); + self.array_set(deflattened_array_pointer, target_index, reference); + self.deallocate_register(nested_array_pointer); + self.deallocate_register(reference); + self.deallocate_register(rc); source_offset += BrilligContext::flattened_size(subitem); } @@ -165,20 +206,33 @@ impl BrilligContext { /// Adds the instructions needed to handle return parameters fn exit_point_instruction(&mut self, return_parameters: Vec) { - // Make sure we don't overwrite the return parameters - return_parameters.iter().for_each(|_| { - self.allocate_register(); - }); + self.set_allocated_registers(vec![]); + let returned_variables: Vec<_> = return_parameters + .iter() + .map(|return_parameter| { + match return_parameter { + BrilligParameter::Simple => BrilligVariable::Simple(self.allocate_register()), + BrilligParameter::Array(..) => { + BrilligVariable::BrilligArray(BrilligArray { + pointer: self.allocate_register(), + size: 0, // TODO + rc: self.allocate_register(), + }) + } + BrilligParameter::Slice(..) => unreachable!("ICE: Cannot return slices"), + } + }) + .collect(); - for (index, ret) in return_parameters.iter().enumerate() { - if let BrilligParameter::Array(item_type, item_count) = ret { + for (return_param, returned_variable) in return_parameters.iter().zip(&returned_variables) { + if let BrilligParameter::Array(item_type, item_count) = return_param { if item_type.iter().any(|item| !matches!(item, BrilligParameter::Simple)) { - let returned_pointer = ReservedRegisters::user_register_index(index); + let returned_pointer = returned_variable.extract_array().pointer; let flattened_array_pointer = self.allocate_register(); self.allocate_fixed_length_array( flattened_array_pointer, - BrilligContext::flattened_size(ret), + BrilligContext::flattened_size(return_param), ); self.flatten_array( @@ -197,11 +251,13 @@ impl BrilligContext { // to the first `n` registers once completed. // Move the results to registers 0..n - for i in 0..return_parameters.len() { - self.push_opcode(BrilligOpcode::Mov { - destination: i.into(), - source: ReservedRegisters::user_register_index(i), - }); + for (i, returned_variable) in returned_variables.into_iter().enumerate() { + let register = match returned_variable { + BrilligVariable::Simple(register) => register, + BrilligVariable::BrilligArray(array) => array.pointer, + BrilligVariable::BrilligVector(vector) => vector.pointer, + }; + self.push_opcode(BrilligOpcode::Mov { destination: i.into(), source: register }); } self.push_opcode(BrilligOpcode::Stop); } @@ -238,11 +294,22 @@ impl BrilligContext { target_offset += 1; } BrilligParameter::Array(nested_array_item_type, nested_array_item_count) => { - let nested_array_pointer = self.allocate_register(); + let nested_array_reference = self.allocate_register(); self.array_get( deflattened_array_pointer, source_index, - nested_array_pointer, + nested_array_reference, + ); + + let nested_array_variable = BrilligVariable::BrilligArray(BrilligArray { + pointer: self.allocate_register(), + size: 0, // TODO + rc: self.allocate_register(), + }); + + self.load_variable_instruction( + nested_array_variable, + nested_array_reference, ); let flattened_nested_array_pointer = self.allocate_register(); @@ -263,11 +330,15 @@ impl BrilligContext { nested_array_item_type, *nested_array_item_count, flattened_nested_array_pointer, - nested_array_pointer, + nested_array_variable.extract_array().pointer, ); - self.deallocate_register(nested_array_pointer); + self.deallocate_register(nested_array_reference); self.deallocate_register(flattened_nested_array_pointer); + nested_array_variable + .extract_registers() + .into_iter() + .for_each(|register| self.deallocate_register(register)); target_offset += BrilligContext::flattened_size(subitem); }