|
| 1 | +use std::vec; |
| 2 | + |
| 3 | +use acvm::{acir::brillig::MemoryAddress, AcirField}; |
| 4 | + |
| 5 | +use super::ProcedureId; |
| 6 | +use crate::brillig::brillig_ir::{ |
| 7 | + brillig_variable::{BrilligVector, SingleAddrVariable}, |
| 8 | + debug_show::DebugToString, |
| 9 | + registers::{RegisterAllocator, ScratchSpace}, |
| 10 | + BrilligBinaryOp, BrilligContext, |
| 11 | +}; |
| 12 | + |
| 13 | +impl<F: AcirField + DebugToString, Registers: RegisterAllocator> BrilligContext<F, Registers> { |
| 14 | + /// It prepares a vector for a insert operation, leaving a hole at the index position which is returned as the write_pointer. |
| 15 | + pub(crate) fn call_prepare_vector_insert_procedure( |
| 16 | + &mut self, |
| 17 | + source_vector: BrilligVector, |
| 18 | + destination_vector: BrilligVector, |
| 19 | + index: SingleAddrVariable, |
| 20 | + write_pointer: MemoryAddress, |
| 21 | + item_count: usize, |
| 22 | + ) { |
| 23 | + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); |
| 24 | + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); |
| 25 | + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); |
| 26 | + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); |
| 27 | + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); |
| 28 | + |
| 29 | + self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); |
| 30 | + self.mov_instruction(index_arg, index.address); |
| 31 | + self.usize_const_instruction(item_count_arg, item_count.into()); |
| 32 | + |
| 33 | + self.add_procedure_call_instruction(ProcedureId::PrepareVectorInsert); |
| 34 | + |
| 35 | + self.mov_instruction(destination_vector.pointer, new_vector_pointer_return); |
| 36 | + self.mov_instruction(write_pointer, write_pointer_return); |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +pub(super) fn compile_prepare_vector_insert_procedure<F: AcirField + DebugToString>( |
| 41 | + brillig_context: &mut BrilligContext<F, ScratchSpace>, |
| 42 | +) { |
| 43 | + let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); |
| 44 | + let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); |
| 45 | + let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); |
| 46 | + let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); |
| 47 | + let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); |
| 48 | + |
| 49 | + brillig_context.set_allocated_registers(vec![ |
| 50 | + source_vector_pointer_arg, |
| 51 | + index_arg, |
| 52 | + item_count_arg, |
| 53 | + new_vector_pointer_return, |
| 54 | + write_pointer_return, |
| 55 | + ]); |
| 56 | + |
| 57 | + let source_vector = BrilligVector { pointer: source_vector_pointer_arg }; |
| 58 | + let target_vector = BrilligVector { pointer: new_vector_pointer_return }; |
| 59 | + let index = SingleAddrVariable::new_usize(index_arg); |
| 60 | + |
| 61 | + // First we need to allocate the target vector incrementing the size by items.len() |
| 62 | + let source_size = brillig_context.codegen_make_vector_length(source_vector); |
| 63 | + |
| 64 | + let target_size = SingleAddrVariable::new_usize(brillig_context.allocate_register()); |
| 65 | + brillig_context.memory_op_instruction( |
| 66 | + source_size.address, |
| 67 | + item_count_arg, |
| 68 | + target_size.address, |
| 69 | + BrilligBinaryOp::Add, |
| 70 | + ); |
| 71 | + |
| 72 | + brillig_context.codegen_initialize_vector(target_vector, target_size); |
| 73 | + |
| 74 | + // Copy the elements to the left of the index |
| 75 | + let source_vector_items_pointer = |
| 76 | + brillig_context.codegen_make_vector_items_pointer(source_vector); |
| 77 | + let target_vector_items_pointer = |
| 78 | + brillig_context.codegen_make_vector_items_pointer(target_vector); |
| 79 | + |
| 80 | + brillig_context.codegen_mem_copy( |
| 81 | + source_vector_items_pointer, |
| 82 | + target_vector_items_pointer, |
| 83 | + index, |
| 84 | + ); |
| 85 | + |
| 86 | + // Compute the source pointer just at the index |
| 87 | + let source_pointer_at_index = brillig_context.allocate_register(); |
| 88 | + brillig_context.memory_op_instruction( |
| 89 | + source_vector_items_pointer, |
| 90 | + index_arg, |
| 91 | + source_pointer_at_index, |
| 92 | + BrilligBinaryOp::Add, |
| 93 | + ); |
| 94 | + |
| 95 | + // Compute the target pointer after the inserted elements |
| 96 | + brillig_context.memory_op_instruction( |
| 97 | + target_vector_items_pointer, |
| 98 | + index.address, |
| 99 | + write_pointer_return, |
| 100 | + BrilligBinaryOp::Add, |
| 101 | + ); |
| 102 | + let target_pointer_after_index = brillig_context.allocate_register(); |
| 103 | + |
| 104 | + brillig_context.memory_op_instruction( |
| 105 | + write_pointer_return, |
| 106 | + item_count_arg, |
| 107 | + target_pointer_after_index, |
| 108 | + BrilligBinaryOp::Add, |
| 109 | + ); |
| 110 | + |
| 111 | + // Compute the number of elements to the right of the index |
| 112 | + let item_count = brillig_context.allocate_register(); |
| 113 | + brillig_context.memory_op_instruction( |
| 114 | + source_size.address, |
| 115 | + index.address, |
| 116 | + item_count, |
| 117 | + BrilligBinaryOp::Sub, |
| 118 | + ); |
| 119 | + |
| 120 | + // Copy the elements to the right of the index |
| 121 | + brillig_context.codegen_mem_copy( |
| 122 | + source_pointer_at_index, |
| 123 | + target_pointer_after_index, |
| 124 | + SingleAddrVariable::new_usize(item_count), |
| 125 | + ); |
| 126 | + |
| 127 | + brillig_context.deallocate_register(source_pointer_at_index); |
| 128 | + brillig_context.deallocate_register(target_pointer_after_index); |
| 129 | + brillig_context.deallocate_register(item_count); |
| 130 | + brillig_context.deallocate_single_addr(source_size); |
| 131 | + brillig_context.deallocate_single_addr(target_size); |
| 132 | + brillig_context.deallocate_register(source_vector_items_pointer); |
| 133 | + brillig_context.deallocate_register(target_vector_items_pointer); |
| 134 | +} |
0 commit comments