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 36a3b34aeb0..85db1bd8b96 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,3 +1,5 @@ +use acvm::acir::brillig::MemoryAddress; + use crate::brillig::brillig_ir::{ brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, BrilligBinaryOp, @@ -6,57 +8,37 @@ use crate::brillig::brillig_ir::{ use super::brillig_block::BrilligBlock; impl<'block> BrilligBlock<'block> { + fn write_variables(&mut self, write_pointer: MemoryAddress, variables: &[BrilligVariable]) { + for (index, variable) in variables.iter().enumerate() { + self.brillig_context.store_instruction(write_pointer, variable.extract_register()); + if index != variables.len() - 1 { + self.brillig_context.codegen_usize_op_in_place( + write_pointer, + BrilligBinaryOp::Add, + 1, + ); + } + } + } + pub(crate) fn slice_push_back_operation( &mut self, 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() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Add, + let write_pointer = self.brillig_context.allocate_register(); + self.brillig_context.call_prepare_vector_push_procedure( + source_vector, + target_vector, + write_pointer, variables_to_insert.len(), + true, ); - self.brillig_context.codegen_initialize_vector(target_vector, target_size); + self.write_variables(write_pointer, variables_to_insert); - // Now we copy the source vector into the target vector - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); - - self.brillig_context.codegen_mem_copy( - source_vector_items_pointer, - target_vector_items_pointer, - source_size, - ); - - for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); - self.brillig_context.memory_op_instruction( - target_index.address, - source_size.address, - target_index.address, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_store_with_offset( - target_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); - } - - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); + self.brillig_context.deallocate_register(write_pointer); } pub(crate) fn slice_push_front_operation( @@ -65,56 +47,30 @@ impl<'block> BrilligBlock<'block> { source_vector: BrilligVector, variables_to_insert: &[BrilligVariable], ) { - // First we need to allocate the target vector incrementing the size by variables_to_insert.len() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Add, - variables_to_insert.len(), - ); - - self.brillig_context.codegen_initialize_vector(target_vector, target_size); - - // Now we offset the target pointer by variables_to_insert.len() - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); - - let destination_copy_pointer = self.brillig_context.allocate_register(); - self.brillig_context.codegen_usize_op( - target_vector_items_pointer, - destination_copy_pointer, - BrilligBinaryOp::Add, + let write_pointer = self.brillig_context.allocate_register(); + self.brillig_context.call_prepare_vector_push_procedure( + source_vector, + target_vector, + write_pointer, variables_to_insert.len(), + false, ); - // Now we copy the source vector into the target vector starting at index variables_to_insert.len() - self.brillig_context.codegen_mem_copy( - source_vector_items_pointer, - destination_copy_pointer, - source_size, - ); + self.write_variables(write_pointer, variables_to_insert); + self.brillig_context.deallocate_register(write_pointer); + } - // Then we write the items to insert at the start - for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); - self.brillig_context.codegen_store_with_offset( - target_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); + fn read_variables(&mut self, read_pointer: MemoryAddress, variables: &[BrilligVariable]) { + for (index, variable) in variables.iter().enumerate() { + self.brillig_context.load_instruction(variable.extract_register(), read_pointer); + if index != variables.len() - 1 { + self.brillig_context.codegen_usize_op_in_place( + read_pointer, + BrilligBinaryOp::Add, + 1, + ); + } } - - self.brillig_context.deallocate_register(destination_copy_pointer); - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); } pub(crate) fn slice_pop_front_operation( @@ -123,55 +79,17 @@ impl<'block> BrilligBlock<'block> { source_vector: BrilligVector, removed_items: &[BrilligVariable], ) { - // First we need to allocate the target vector decrementing the size by removed_items.len() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Sub, + let read_pointer = self.brillig_context.allocate_register(); + self.brillig_context.call_vector_pop_procedure( + source_vector, + target_vector, + read_pointer, removed_items.len(), + false, ); - self.brillig_context.codegen_initialize_vector(target_vector, target_size); - - // Now we offset the source pointer by removed_items.len() - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); - - let source_copy_pointer = self.brillig_context.allocate_register(); - self.brillig_context.codegen_usize_op( - source_vector_items_pointer, - source_copy_pointer, - BrilligBinaryOp::Add, - removed_items.len(), - ); - - // Now we copy the source vector starting at index removed_items.len() into the target vector - self.brillig_context.codegen_mem_copy( - source_copy_pointer, - target_vector_items_pointer, - target_size, - ); - - for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); - self.brillig_context.codegen_load_with_offset( - source_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); - } - - self.brillig_context.deallocate_register(source_copy_pointer); - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); + self.read_variables(read_pointer, removed_items); + self.brillig_context.deallocate_register(read_pointer); } pub(crate) fn slice_pop_back_operation( @@ -180,50 +98,17 @@ impl<'block> BrilligBlock<'block> { source_vector: BrilligVector, removed_items: &[BrilligVariable], ) { - // First we need to allocate the target vector decrementing the size by removed_items.len() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Sub, + let read_pointer = self.brillig_context.allocate_register(); + self.brillig_context.call_vector_pop_procedure( + source_vector, + target_vector, + read_pointer, removed_items.len(), + true, ); - self.brillig_context.codegen_initialize_vector(target_vector, target_size); - - // Now we copy all elements except the last items into the target vector - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); - - self.brillig_context.codegen_mem_copy( - source_vector_items_pointer, - target_vector_items_pointer, - target_size, - ); - - for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); - self.brillig_context.memory_op_instruction( - target_index.address, - target_size.address, - target_index.address, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_load_with_offset( - source_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); - } - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); + self.read_variables(read_pointer, removed_items); + self.brillig_context.deallocate_register(read_pointer); } pub(crate) fn slice_insert_operation( @@ -233,95 +118,18 @@ impl<'block> BrilligBlock<'block> { index: SingleAddrVariable, items: &[BrilligVariable], ) { - // First we need to allocate the target vector incrementing the size by items.len() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Add, - items.len(), - ); - - self.brillig_context.codegen_initialize_vector(target_vector, target_size); - - // Copy the elements to the left of the index - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); + let write_pointer = self.brillig_context.allocate_register(); - self.brillig_context.codegen_mem_copy( - source_vector_items_pointer, - target_vector_items_pointer, + self.brillig_context.call_prepare_vector_insert_procedure( + source_vector, + target_vector, index, - ); - - // Compute the source pointer just at the index - let source_pointer_at_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - source_vector_items_pointer, - index.address, - source_pointer_at_index, - BrilligBinaryOp::Add, - ); - - // Compute the target pointer after the inserted elements - let target_pointer_after_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - target_vector_items_pointer, - index.address, - target_pointer_after_index, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_usize_op_in_place( - target_pointer_after_index, - BrilligBinaryOp::Add, + write_pointer, items.len(), ); - // Compute the number of elements to the right of the index - let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - source_size.address, - index.address, - item_count, - BrilligBinaryOp::Sub, - ); - - // Copy the elements to the right of the index - self.brillig_context.codegen_mem_copy( - source_pointer_at_index, - target_pointer_after_index, - SingleAddrVariable::new_usize(item_count), - ); - - // Write the items to insert starting at the index - for (subitem_index, variable) in items.iter().enumerate() { - let target_index = - self.brillig_context.make_usize_constant_instruction(subitem_index.into()); - self.brillig_context.memory_op_instruction( - target_index.address, - index.address, - target_index.address, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_store_with_offset( - target_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); - } - - self.brillig_context.deallocate_register(source_pointer_at_index); - self.brillig_context.deallocate_register(target_pointer_after_index); - self.brillig_context.deallocate_register(item_count); - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); + self.write_variables(write_pointer, items); + self.brillig_context.deallocate_register(write_pointer); } pub(crate) fn slice_remove_operation( @@ -331,100 +139,21 @@ impl<'block> BrilligBlock<'block> { index: SingleAddrVariable, removed_items: &[BrilligVariable], ) { - // First we need to allocate the target vector decrementing the size by removed_items.len() - let source_size = self.brillig_context.codegen_make_vector_length(source_vector); - - let target_size = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - self.brillig_context.codegen_usize_op( - source_size.address, - target_size.address, - BrilligBinaryOp::Sub, - removed_items.len(), - ); - - self.brillig_context.codegen_initialize_vector(target_vector, target_size); - - // Copy the elements to the left of the index - let source_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(source_vector); - let target_vector_items_pointer = - self.brillig_context.codegen_make_vector_items_pointer(target_vector); - - self.brillig_context.codegen_mem_copy( - source_vector_items_pointer, - target_vector_items_pointer, - index, - ); - - // Compute the source pointer after the removed items - let source_pointer_after_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - source_vector_items_pointer, - index.address, - source_pointer_after_index, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_usize_op_in_place( - source_pointer_after_index, - BrilligBinaryOp::Add, - removed_items.len(), - ); - - // Compute the target pointer at the index - let target_pointer_at_index = self.brillig_context.allocate_register(); + let read_pointer = self.brillig_context.codegen_make_vector_items_pointer(source_vector); self.brillig_context.memory_op_instruction( - target_vector_items_pointer, + read_pointer, index.address, - target_pointer_at_index, + read_pointer, BrilligBinaryOp::Add, ); + self.read_variables(read_pointer, removed_items); - // Compute the number of elements to the right of the index - let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - source_size.address, - index.address, - item_count, - BrilligBinaryOp::Sub, - ); - self.brillig_context.codegen_usize_op_in_place( - item_count, - BrilligBinaryOp::Sub, + self.brillig_context.call_vector_remove_procedure( + source_vector, + target_vector, + index, removed_items.len(), ); - - // Copy the elements to the right of the index - self.brillig_context.codegen_mem_copy( - source_pointer_after_index, - target_pointer_at_index, - SingleAddrVariable::new_usize(item_count), - ); - - // Get the removed items - for (subitem_index, variable) in removed_items.iter().enumerate() { - let target_index = - self.brillig_context.make_usize_constant_instruction(subitem_index.into()); - self.brillig_context.memory_op_instruction( - target_index.address, - index.address, - target_index.address, - BrilligBinaryOp::Add, - ); - self.brillig_context.codegen_load_with_offset( - source_vector_items_pointer, - target_index, - variable.extract_register(), - ); - self.brillig_context.deallocate_single_addr(target_index); - } - - self.brillig_context.deallocate_register(source_pointer_after_index); - self.brillig_context.deallocate_register(target_pointer_at_index); - self.brillig_context.deallocate_register(item_count); - self.brillig_context.deallocate_single_addr(source_size); - self.brillig_context.deallocate_single_addr(target_size); - self.brillig_context.deallocate_register(source_vector_items_pointer); - self.brillig_context.deallocate_register(target_vector_items_pointer); } } @@ -458,7 +187,6 @@ mod tests { let ssa = builder.finish(); let mut brillig_context = create_context(ssa.main_id); brillig_context.enter_context(Label::block(ssa.main_id, Id::test_new(0))); - brillig_context.disable_procedures(); let function_context = FunctionContext::new(ssa.main()); (ssa, function_context, brillig_context) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index b52b239e6b9..d8065294b0c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -112,10 +112,6 @@ impl BrilligContext { can_call_procedures: true, } } - /// Allows disabling procedures so tests don't need a linking pass - pub(crate) fn disable_procedures(&mut self) { - self.can_call_procedures = false; - } } /// Special brillig context to codegen compiler intrinsic shared procedures @@ -165,7 +161,8 @@ pub(crate) mod tests { use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; use crate::ssa::ir::function::FunctionId; - use super::artifact::{BrilligParameter, GeneratedBrillig, Label}; + use super::artifact::{BrilligParameter, GeneratedBrillig, Label, LabelType}; + use super::procedures::compile_procedure; use super::registers::Stack; use super::{BrilligOpcode, ReservedRegisters}; @@ -237,13 +234,17 @@ pub(crate) mod tests { returns: Vec, ) -> GeneratedBrillig { let artifact = context.artifact(); - let mut entry_point_artifact = BrilligContext::new_entry_point_artifact( - arguments, - returns, - FunctionId::test_new(0), - true, - ); + let mut entry_point_artifact = + BrilligContext::new_entry_point_artifact(arguments, returns, FunctionId::test_new(0)); entry_point_artifact.link_with(&artifact); + while let Some(unresolved_fn_label) = entry_point_artifact.first_unresolved_function_call() + { + let LabelType::Procedure(procedure_id) = unresolved_fn_label.label_type else { + panic!("Test functions cannot be linked with other functions"); + }; + let procedure_artifact = compile_procedure(procedure_id); + entry_point_artifact.link_with(&procedure_artifact); + } entry_point_artifact.finish() } 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 bde128d0b6b..ff9b5ea67eb 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -18,12 +18,9 @@ impl BrilligContext { arguments: Vec, return_parameters: Vec, target_function: FunctionId, - disable_procedures: bool, ) -> BrilligArtifact { let mut context = BrilligContext::new(false); - if disable_procedures { - context.disable_procedures(); - } + context.codegen_entry_point(&arguments, &return_parameters); context.add_external_call_instruction(target_function); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs index d2a011f8aa5..32fe6725e56 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs @@ -1,12 +1,20 @@ mod array_copy; mod array_reverse; mod mem_copy; +mod prepare_vector_insert; +mod prepare_vector_push; mod vector_copy; +mod vector_pop; +mod vector_remove; use array_copy::compile_array_copy_procedure; use array_reverse::compile_array_reverse_procedure; use mem_copy::compile_mem_copy_procedure; +use prepare_vector_insert::compile_prepare_vector_insert_procedure; +use prepare_vector_push::compile_prepare_vector_push_procedure; use vector_copy::compile_vector_copy_procedure; +use vector_pop::compile_vector_pop_procedure; +use vector_remove::compile_vector_remove_procedure; use crate::brillig::brillig_ir::AcirField; @@ -25,6 +33,10 @@ pub(crate) enum ProcedureId { ArrayReverse, VectorCopy, MemCopy, + PrepareVectorPush(bool), + VectorPop(bool), + PrepareVectorInsert, + VectorRemove, } pub(crate) fn compile_procedure( @@ -38,6 +50,16 @@ pub(crate) fn compile_procedure( ProcedureId::ArrayCopy => compile_array_copy_procedure(&mut brillig_context), ProcedureId::ArrayReverse => compile_array_reverse_procedure(&mut brillig_context), ProcedureId::VectorCopy => compile_vector_copy_procedure(&mut brillig_context), + ProcedureId::PrepareVectorPush(push_back) => { + compile_prepare_vector_push_procedure(&mut brillig_context, push_back); + } + ProcedureId::VectorPop(pop_back) => { + compile_vector_pop_procedure(&mut brillig_context, pop_back); + } + ProcedureId::PrepareVectorInsert => { + compile_prepare_vector_insert_procedure(&mut brillig_context); + } + ProcedureId::VectorRemove => compile_vector_remove_procedure(&mut brillig_context), }; brillig_context.stop_instruction(); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs new file mode 100644 index 00000000000..d3a6855fa0f --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs @@ -0,0 +1,134 @@ +use std::vec; + +use acvm::{acir::brillig::MemoryAddress, AcirField}; + +use super::ProcedureId; +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, + registers::{RegisterAllocator, ScratchSpace}, + BrilligBinaryOp, BrilligContext, +}; + +impl BrilligContext { + /// It prepares a vector for a insert operation, leaving a hole at the index position which is returned as the write_pointer. + pub(crate) fn call_prepare_vector_insert_procedure( + &mut self, + source_vector: BrilligVector, + destination_vector: BrilligVector, + index: SingleAddrVariable, + write_pointer: MemoryAddress, + item_count: usize, + ) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); + + self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); + self.mov_instruction(index_arg, index.address); + self.usize_const_instruction(item_count_arg, item_count.into()); + + self.add_procedure_call_instruction(ProcedureId::PrepareVectorInsert); + + self.mov_instruction(destination_vector.pointer, new_vector_pointer_return); + self.mov_instruction(write_pointer, write_pointer_return); + } +} + +pub(super) fn compile_prepare_vector_insert_procedure( + brillig_context: &mut BrilligContext, +) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); + + brillig_context.set_allocated_registers(vec![ + source_vector_pointer_arg, + index_arg, + item_count_arg, + new_vector_pointer_return, + write_pointer_return, + ]); + + let source_vector = BrilligVector { pointer: source_vector_pointer_arg }; + let target_vector = BrilligVector { pointer: new_vector_pointer_return }; + let index = SingleAddrVariable::new_usize(index_arg); + + // First we need to allocate the target vector incrementing the size by items.len() + let source_size = brillig_context.codegen_make_vector_length(source_vector); + + let target_size = SingleAddrVariable::new_usize(brillig_context.allocate_register()); + brillig_context.memory_op_instruction( + source_size.address, + item_count_arg, + target_size.address, + BrilligBinaryOp::Add, + ); + + brillig_context.codegen_initialize_vector(target_vector, target_size); + + // Copy the elements to the left of the index + let source_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(source_vector); + let target_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(target_vector); + + brillig_context.codegen_mem_copy( + source_vector_items_pointer, + target_vector_items_pointer, + index, + ); + + // Compute the source pointer just at the index + let source_pointer_at_index = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_vector_items_pointer, + index_arg, + source_pointer_at_index, + BrilligBinaryOp::Add, + ); + + // Compute the target pointer after the inserted elements + brillig_context.memory_op_instruction( + target_vector_items_pointer, + index.address, + write_pointer_return, + BrilligBinaryOp::Add, + ); + let target_pointer_after_index = brillig_context.allocate_register(); + + brillig_context.memory_op_instruction( + write_pointer_return, + item_count_arg, + target_pointer_after_index, + BrilligBinaryOp::Add, + ); + + // Compute the number of elements to the right of the index + let item_count = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_size.address, + index.address, + item_count, + BrilligBinaryOp::Sub, + ); + + // Copy the elements to the right of the index + brillig_context.codegen_mem_copy( + source_pointer_at_index, + target_pointer_after_index, + SingleAddrVariable::new_usize(item_count), + ); + + brillig_context.deallocate_register(source_pointer_at_index); + brillig_context.deallocate_register(target_pointer_after_index); + brillig_context.deallocate_register(item_count); + brillig_context.deallocate_single_addr(source_size); + brillig_context.deallocate_single_addr(target_size); + brillig_context.deallocate_register(source_vector_items_pointer); + brillig_context.deallocate_register(target_vector_items_pointer); +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs new file mode 100644 index 00000000000..8af75712374 --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs @@ -0,0 +1,111 @@ +use std::vec; + +use acvm::{acir::brillig::MemoryAddress, AcirField}; + +use super::ProcedureId; +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, + registers::{RegisterAllocator, ScratchSpace}, + BrilligBinaryOp, BrilligContext, +}; + +impl BrilligContext { + /// Prepares a vector for a push operation, allocating a larger vector and copying the source vector into the destination vector. + /// It returns the write pointer to where to put the new items. + pub(crate) fn call_prepare_vector_push_procedure( + &mut self, + source_vector: BrilligVector, + destination_vector: BrilligVector, + write_pointer: MemoryAddress, + item_push_count: usize, + back: bool, + ) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let item_push_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); + self.usize_const_instruction(item_push_count_arg, item_push_count.into()); + + self.add_procedure_call_instruction(ProcedureId::PrepareVectorPush(back)); + + self.mov_instruction(destination_vector.pointer, new_vector_pointer_return); + self.mov_instruction(write_pointer, write_pointer_return); + } +} + +pub(super) fn compile_prepare_vector_push_procedure( + brillig_context: &mut BrilligContext, + push_back: bool, +) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let item_push_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + brillig_context.set_allocated_registers(vec![ + source_vector_pointer_arg, + item_push_count_arg, + new_vector_pointer_return, + write_pointer_return, + ]); + + let source_vector = BrilligVector { pointer: source_vector_pointer_arg }; + let target_vector = BrilligVector { pointer: new_vector_pointer_return }; + + // First we need to allocate the target vector incrementing the size by item_push_count_arg + let source_size = brillig_context.codegen_make_vector_length(source_vector); + + let target_size = SingleAddrVariable::new_usize(brillig_context.allocate_register()); + brillig_context.memory_op_instruction( + source_size.address, + item_push_count_arg, + target_size.address, + BrilligBinaryOp::Add, + ); + + brillig_context.codegen_initialize_vector(target_vector, target_size); + + // Now we copy the source vector into the target vector + let source_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(source_vector); + let target_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(target_vector); + + if push_back { + brillig_context.codegen_mem_copy( + source_vector_items_pointer, + target_vector_items_pointer, + source_size, + ); + + brillig_context.memory_op_instruction( + target_vector_items_pointer, + source_size.address, + write_pointer_return, + BrilligBinaryOp::Add, + ); + } else { + brillig_context.mov_instruction(write_pointer_return, target_vector_items_pointer); + + brillig_context.memory_op_instruction( + target_vector_items_pointer, + item_push_count_arg, + target_vector_items_pointer, + BrilligBinaryOp::Add, + ); + + brillig_context.codegen_mem_copy( + source_vector_items_pointer, + target_vector_items_pointer, + source_size, + ); + } + + brillig_context.deallocate_single_addr(source_size); + brillig_context.deallocate_single_addr(target_size); + brillig_context.deallocate_register(source_vector_items_pointer); + brillig_context.deallocate_register(target_vector_items_pointer); +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs new file mode 100644 index 00000000000..bb14ffac6be --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs @@ -0,0 +1,113 @@ +use std::vec; + +use acvm::{acir::brillig::MemoryAddress, AcirField}; + +use super::ProcedureId; +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, + registers::{RegisterAllocator, ScratchSpace}, + BrilligBinaryOp, BrilligContext, +}; + +impl BrilligContext { + /// Pops items from the vector, returning the new vector and the pointer to the popped items in read_pointer. + pub(crate) fn call_vector_pop_procedure( + &mut self, + source_vector: BrilligVector, + destination_vector: BrilligVector, + read_pointer: MemoryAddress, + item_pop_count: usize, + back: bool, + ) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let item_pop_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let read_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); + self.usize_const_instruction(item_pop_count_arg, item_pop_count.into()); + + self.add_procedure_call_instruction(ProcedureId::VectorPop(back)); + + self.mov_instruction(destination_vector.pointer, new_vector_pointer_return); + self.mov_instruction(read_pointer, read_pointer_return); + } +} + +pub(super) fn compile_vector_pop_procedure( + brillig_context: &mut BrilligContext, + pop_back: bool, +) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let item_pop_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let read_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + brillig_context.set_allocated_registers(vec![ + source_vector_pointer_arg, + item_pop_count_arg, + new_vector_pointer_return, + read_pointer_return, + ]); + + let source_vector = BrilligVector { pointer: source_vector_pointer_arg }; + let target_vector = BrilligVector { pointer: new_vector_pointer_return }; + + // First we need to allocate the target vector decrementing the size by removed_items.len() + let source_size = brillig_context.codegen_make_vector_length(source_vector); + + let target_size = SingleAddrVariable::new_usize(brillig_context.allocate_register()); + brillig_context.memory_op_instruction( + source_size.address, + item_pop_count_arg, + target_size.address, + BrilligBinaryOp::Sub, + ); + + brillig_context.codegen_initialize_vector(target_vector, target_size); + + // Now we offset the source pointer by removed_items.len() + let source_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(source_vector); + let target_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(target_vector); + + if pop_back { + // Now we copy the source vector starting at index 0 into the target vector + brillig_context.codegen_mem_copy( + source_vector_items_pointer, + target_vector_items_pointer, + target_size, + ); + brillig_context.memory_op_instruction( + source_vector_items_pointer, + target_size.address, + read_pointer_return, + BrilligBinaryOp::Add, + ); + } else { + let source_copy_pointer = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_vector_items_pointer, + item_pop_count_arg, + source_copy_pointer, + BrilligBinaryOp::Add, + ); + + // Now we copy the source vector starting at index removed_items.len() into the target vector + brillig_context.codegen_mem_copy( + source_copy_pointer, + target_vector_items_pointer, + target_size, + ); + brillig_context.mov_instruction(read_pointer_return, source_vector_items_pointer); + + brillig_context.deallocate_register(source_copy_pointer); + } + + brillig_context.deallocate_single_addr(source_size); + brillig_context.deallocate_single_addr(target_size); + brillig_context.deallocate_register(source_vector_items_pointer); + brillig_context.deallocate_register(target_vector_items_pointer); +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs new file mode 100644 index 00000000000..d4a7217677f --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs @@ -0,0 +1,134 @@ +use std::vec; + +use acvm::{acir::brillig::MemoryAddress, AcirField}; + +use super::ProcedureId; +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVector, SingleAddrVariable}, + debug_show::DebugToString, + registers::{RegisterAllocator, ScratchSpace}, + BrilligBinaryOp, BrilligContext, +}; + +impl BrilligContext { + /// Removes items from the vector, returning the new vector. + pub(crate) fn call_vector_remove_procedure( + &mut self, + source_vector: BrilligVector, + destination_vector: BrilligVector, + index: SingleAddrVariable, + item_count: usize, + ) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); + self.mov_instruction(index_arg, index.address); + self.usize_const_instruction(item_count_arg, item_count.into()); + + self.add_procedure_call_instruction(ProcedureId::VectorRemove); + + self.mov_instruction(destination_vector.pointer, new_vector_pointer_return); + } +} + +pub(super) fn compile_vector_remove_procedure( + brillig_context: &mut BrilligContext, +) { + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + + brillig_context.set_allocated_registers(vec![ + source_vector_pointer_arg, + index_arg, + item_count_arg, + new_vector_pointer_return, + ]); + + let source_vector = BrilligVector { pointer: source_vector_pointer_arg }; + let target_vector = BrilligVector { pointer: new_vector_pointer_return }; + let index = SingleAddrVariable::new_usize(index_arg); + + // First we need to allocate the target vector decrementing the size by removed_items.len() + let source_size = brillig_context.codegen_make_vector_length(source_vector); + + let target_size = SingleAddrVariable::new_usize(brillig_context.allocate_register()); + brillig_context.memory_op_instruction( + source_size.address, + item_count_arg, + target_size.address, + BrilligBinaryOp::Sub, + ); + + brillig_context.codegen_initialize_vector(target_vector, target_size); + + // Copy the elements to the left of the index + let source_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(source_vector); + let target_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(target_vector); + + brillig_context.codegen_mem_copy( + source_vector_items_pointer, + target_vector_items_pointer, + index, + ); + + // Compute the source pointer after the removed items + let source_pointer_after_index = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_vector_items_pointer, + index.address, + source_pointer_after_index, + BrilligBinaryOp::Add, + ); + brillig_context.memory_op_instruction( + source_pointer_after_index, + item_count_arg, + source_pointer_after_index, + BrilligBinaryOp::Add, + ); + + // Compute the target pointer at the index + let target_pointer_at_index = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + target_vector_items_pointer, + index.address, + target_pointer_at_index, + BrilligBinaryOp::Add, + ); + + // Compute the number of elements to the right of the index + let item_count = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_size.address, + index.address, + item_count, + BrilligBinaryOp::Sub, + ); + brillig_context.memory_op_instruction( + item_count, + item_count_arg, + item_count, + BrilligBinaryOp::Sub, + ); + + // Copy the elements to the right of the index + brillig_context.codegen_mem_copy( + source_pointer_after_index, + target_pointer_at_index, + SingleAddrVariable::new_usize(item_count), + ); + + brillig_context.deallocate_register(source_pointer_after_index); + brillig_context.deallocate_register(target_pointer_at_index); + brillig_context.deallocate_register(item_count); + brillig_context.deallocate_single_addr(source_size); + brillig_context.deallocate_single_addr(target_size); + brillig_context.deallocate_register(source_vector_items_pointer); + brillig_context.deallocate_register(target_vector_items_pointer); +} diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 5091854a2ed..15b44fde65d 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -960,7 +960,6 @@ impl<'a> Context<'a> { arguments, BrilligFunctionContext::return_values(func), func.id(), - false, ); entry_point.name = func.name().to_string();