Skip to content

Commit

Permalink
Merge d90ba66 into 51eb295
Browse files Browse the repository at this point in the history
  • Loading branch information
sirasistant authored Oct 28, 2024
2 parents 51eb295 + d90ba66 commit e153d26
Show file tree
Hide file tree
Showing 14 changed files with 768 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use acvm::{

use crate::brillig::brillig_ir::{
brillig_variable::BrilligVariable, debug_show::DebugToString, registers::RegisterAllocator,
BrilligBinaryOp, BrilligContext,
BrilligContext,
};

/// Transforms SSA's black box function calls into the corresponding brillig instructions
Expand Down Expand Up @@ -395,19 +395,8 @@ pub(crate) fn convert_black_box_call<F: AcirField + DebugToString, Registers: Re

brillig_context.mov_instruction(out_len.address, outputs_vector.size);
// Returns slice, so we need to allocate memory for it after the fact
brillig_context.codegen_usize_op_in_place(
outputs_vector.size,
BrilligBinaryOp::Add,
2_usize,
);
brillig_context.increase_free_memory_pointer_instruction(outputs_vector.size);
// We also need to write the size of the vector to the memory
brillig_context.codegen_usize_op_in_place(
outputs_vector.pointer,
BrilligBinaryOp::Sub,
1_usize,
);
brillig_context.store_instruction(outputs_vector.pointer, out_len.address);

brillig_context.initialize_externally_returned_vector(*outputs, outputs_vector);

brillig_context.deallocate_heap_vector(inputs);
brillig_context.deallocate_heap_vector(outputs_vector);
Expand Down
44 changes: 9 additions & 35 deletions compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,34 +374,10 @@ impl<'block> BrilligBlock<'block> {
match output_register {
// Returned vectors need to emit some bytecode to format the result as a BrilligVector
ValueOrArray::HeapVector(heap_vector) => {
// Update the stack pointer so that we do not overwrite
// dynamic memory returned from other external calls
// Single values and allocation of fixed sized arrays has already been handled
// inside of `allocate_external_call_result`
let total_size = self.brillig_context.allocate_register();
self.brillig_context.codegen_usize_op(
heap_vector.size,
total_size,
BrilligBinaryOp::Add,
2, // RC and Length
self.brillig_context.initialize_externally_returned_vector(
output_variable.extract_vector(),
*heap_vector,
);

self.brillig_context
.increase_free_memory_pointer_instruction(total_size);
let brillig_vector = output_variable.extract_vector();
let size_pointer = self.brillig_context.allocate_register();

self.brillig_context.codegen_usize_op(
brillig_vector.pointer,
size_pointer,
BrilligBinaryOp::Add,
1_usize, // Slices are [RC, Size, ...items]
);
self.brillig_context
.store_instruction(size_pointer, heap_vector.size);
self.brillig_context.deallocate_register(size_pointer);
self.brillig_context.deallocate_register(total_size);

// Update the dynamic slice length maintained in SSA
if let ValueOrArray::MemoryAddress(len_index) = output_values[i - 1]
{
Expand Down Expand Up @@ -515,8 +491,11 @@ impl<'block> BrilligBlock<'block> {
element_size,
);

self.brillig_context
.codegen_initialize_vector(destination_vector, source_size_register);
self.brillig_context.codegen_initialize_vector(
destination_vector,
source_size_register,
None,
);

// Items
let vector_items_pointer =
Expand Down Expand Up @@ -1551,7 +1530,7 @@ impl<'block> BrilligBlock<'block> {
let size = self
.brillig_context
.make_usize_constant_instruction(array.len().into());
self.brillig_context.codegen_initialize_vector(vector, size);
self.brillig_context.codegen_initialize_vector(vector, size, None);
self.brillig_context.deallocate_single_addr(size);
}
_ => unreachable!(
Expand Down Expand Up @@ -1797,11 +1776,6 @@ impl<'block> BrilligBlock<'block> {
// 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.load_free_memory_pointer_instruction(vector.pointer);
self.brillig_context.indirect_const_instruction(
vector.pointer,
BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
1_usize.into(),
);

variable
}
Expand Down
152 changes: 89 additions & 63 deletions compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,15 @@ impl<'block> BrilligBlock<'block> {
source_vector: BrilligVector,
removed_items: &[BrilligVariable],
) {
let read_pointer = self.brillig_context.allocate_register();
self.brillig_context.call_vector_pop_procedure(
let read_pointer = self.brillig_context.codegen_make_vector_items_pointer(source_vector);
self.read_variables(read_pointer, removed_items);
self.brillig_context.deallocate_register(read_pointer);

self.brillig_context.call_vector_pop_front_procedure(
source_vector,
target_vector,
read_pointer,
removed_items.len(),
false,
);

self.read_variables(read_pointer, removed_items);
self.brillig_context.deallocate_register(read_pointer);
}

pub(crate) fn slice_pop_back_operation(
Expand All @@ -99,12 +97,11 @@ impl<'block> BrilligBlock<'block> {
removed_items: &[BrilligVariable],
) {
let read_pointer = self.brillig_context.allocate_register();
self.brillig_context.call_vector_pop_procedure(
self.brillig_context.call_vector_pop_back_procedure(
source_vector,
target_vector,
read_pointer,
removed_items.len(),
true,
);

self.read_variables(read_pointer, removed_items);
Expand Down Expand Up @@ -213,7 +210,7 @@ mod tests {
push_back: bool,
array: Vec<FieldElement>,
item_to_push: FieldElement,
mut expected_return: Vec<FieldElement>,
expected_return: Vec<FieldElement>,
) {
let arguments = vec![
BrilligParameter::Slice(
Expand All @@ -223,11 +220,15 @@ mod tests {
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
];
let result_length = array.len() + 1;
assert_eq!(result_length, expected_return.len());
let result_length_with_metadata = result_length + 2; // Leading length and capacity

// Entry points don't support returning slices, so we implicitly cast the vector to an array
// With the metadata at the start.
let returns = vec![BrilligParameter::Array(
vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)],
result_length + 1, // Leading length since the we return a vector
result_length_with_metadata,
)];
expected_return.insert(0, FieldElement::from(result_length));

let (_, mut function_context, mut context) = create_test_environment();

Expand Down Expand Up @@ -262,14 +263,17 @@ mod tests {
let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code;
let (vm, return_data_offset, return_data_size) =
create_and_run_vm(array.into_iter().chain(vec![item_to_push]).collect(), &bytecode);
assert_eq!(return_data_size, expected_return.len());
assert_eq!(
vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())]
.iter()
.map(|mem_val| mem_val.to_field())
.collect::<Vec<_>>(),
expected_return
);
assert_eq!(return_data_size, result_length_with_metadata);
let mut returned_vector: Vec<FieldElement> = vm.get_memory()
[return_data_offset..(return_data_offset + result_length_with_metadata)]
.iter()
.map(|mem_val| mem_val.to_field())
.collect();
let returned_size = returned_vector.remove(0);
assert_eq!(returned_size, result_length.into());
let _returned_capacity = returned_vector.remove(0);

assert_eq!(returned_vector, expected_return);
}

test_case_push(
Expand Down Expand Up @@ -321,23 +325,26 @@ mod tests {
fn test_case_pop(
pop_back: bool,
array: Vec<FieldElement>,
mut expected_return_array: Vec<FieldElement>,
expected_return_array: Vec<FieldElement>,
expected_return_item: FieldElement,
) {
let arguments = vec![BrilligParameter::Slice(
vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)],
array.len(),
)];
let result_length = array.len() - 1;
assert_eq!(result_length, expected_return_array.len());
let result_length_with_metadata = result_length + 2; // Leading length and capacity

// Entry points don't support returning slices, so we implicitly cast the vector to an array
// With the metadata at the start.
let returns = vec![
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
BrilligParameter::Array(
vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)],
result_length + 1,
result_length_with_metadata,
),
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
];
expected_return_array.insert(0, FieldElement::from(result_length));

let (_, mut function_context, mut context) = create_test_environment();

Expand Down Expand Up @@ -367,22 +374,28 @@ mod tests {
);
}

context.codegen_return(&[target_vector.pointer, removed_item.address]);
context.codegen_return(&[removed_item.address, target_vector.pointer]);

let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code;
let expected_return: Vec<_> =
expected_return_array.into_iter().chain(vec![expected_return_item]).collect();

let (vm, return_data_offset, return_data_size) =
create_and_run_vm(array.clone(), &bytecode);
assert_eq!(return_data_size, expected_return.len());

assert_eq!(
vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())]
.iter()
.map(|mem_val| mem_val.to_field())
.collect::<Vec<_>>(),
expected_return
);
// vector + removed item
assert_eq!(return_data_size, result_length_with_metadata + 1);

let mut return_data: Vec<FieldElement> = vm.get_memory()
[return_data_offset..(return_data_offset + return_data_size)]
.iter()
.map(|mem_val| mem_val.to_field())
.collect();
let returned_item = return_data.remove(0);
assert_eq!(returned_item, expected_return_item);

let returned_size = return_data.remove(0);
assert_eq!(returned_size, result_length.into());
let _returned_capacity = return_data.remove(0);

assert_eq!(return_data, expected_return_array);
}

test_case_pop(
Expand Down Expand Up @@ -414,7 +427,7 @@ mod tests {
array: Vec<FieldElement>,
item: FieldElement,
index: FieldElement,
mut expected_return: Vec<FieldElement>,
expected_return: Vec<FieldElement>,
) {
let arguments = vec![
BrilligParameter::Slice(
Expand All @@ -425,11 +438,15 @@ mod tests {
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
];
let result_length = array.len() + 1;
assert_eq!(result_length, expected_return.len());
let result_length_with_metadata = result_length + 2; // Leading length and capacity

// Entry points don't support returning slices, so we implicitly cast the vector to an array
// With the metadata at the start.
let returns = vec![BrilligParameter::Array(
vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)],
result_length + 1,
result_length_with_metadata,
)];
expected_return.insert(0, FieldElement::from(result_length));

let (_, mut function_context, mut context) = create_test_environment();

Expand Down Expand Up @@ -461,15 +478,18 @@ mod tests {

let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code;
let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata, &bytecode);
assert_eq!(return_data_size, expected_return.len());

assert_eq!(
vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())]
.iter()
.map(|mem_val| mem_val.to_field())
.collect::<Vec<_>>(),
expected_return
);
assert_eq!(return_data_size, result_length_with_metadata);

let mut returned_vector: Vec<FieldElement> = vm.get_memory()
[return_data_offset..(return_data_offset + result_length_with_metadata)]
.iter()
.map(|mem_val| mem_val.to_field())
.collect();
let returned_size = returned_vector.remove(0);
assert_eq!(returned_size, result_length.into());
let _returned_capacity = returned_vector.remove(0);

assert_eq!(returned_vector, expected_return);
}

test_case_insert(
Expand Down Expand Up @@ -546,7 +566,7 @@ mod tests {
fn test_case_remove(
array: Vec<FieldElement>,
index: FieldElement,
mut expected_array: Vec<FieldElement>,
expected_array: Vec<FieldElement>,
expected_removed_item: FieldElement,
) {
let arguments = vec![
Expand All @@ -557,15 +577,16 @@ mod tests {
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
];
let result_length = array.len() - 1;
assert_eq!(result_length, expected_array.len());
let result_length_with_metadata = result_length + 2; // Leading length and capacity

let returns = vec![
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
BrilligParameter::Array(
vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)],
result_length + 1,
result_length_with_metadata,
),
BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE),
];
expected_array.insert(0, FieldElement::from(result_length));

let (_, mut function_context, mut context) = create_test_environment();

Expand All @@ -592,24 +613,29 @@ mod tests {
&[BrilligVariable::SingleAddr(removed_item)],
);

context.codegen_return(&[target_vector.pointer, removed_item.address]);
context.codegen_return(&[removed_item.address, target_vector.pointer]);

let calldata: Vec<_> = array.into_iter().chain(vec![index]).collect();

let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code;
let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata, &bytecode);

let expected_return: Vec<_> =
expected_array.into_iter().chain(vec![expected_removed_item]).collect();
assert_eq!(return_data_size, expected_return.len());
// vector + removed item
assert_eq!(return_data_size, result_length_with_metadata + 1);

assert_eq!(
vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())]
.iter()
.map(|mem_val| mem_val.to_field())
.collect::<Vec<_>>(),
expected_return
);
let mut return_data: Vec<FieldElement> = vm.get_memory()
[return_data_offset..(return_data_offset + return_data_size)]
.iter()
.map(|mem_val| mem_val.to_field())
.collect();
let returned_item = return_data.remove(0);
assert_eq!(returned_item, expected_removed_item);

let returned_size = return_data.remove(0);
assert_eq!(returned_size, result_length.into());
let _returned_capacity = return_data.remove(0);

assert_eq!(return_data, expected_array);
}

test_case_remove(
Expand Down
Loading

0 comments on commit e153d26

Please sign in to comment.