Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Extract brillig slice ops to reusable procedures #6002

Merged
merged 2 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
418 changes: 73 additions & 345 deletions compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs

Large diffs are not rendered by default.

23 changes: 12 additions & 11 deletions compiler/noirc_evaluator/src/brillig/brillig_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ impl<F: AcirField + DebugToString> BrilligContext<F, Stack> {
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
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -237,13 +234,17 @@ pub(crate) mod tests {
returns: Vec<BrilligParameter>,
) -> GeneratedBrillig<FieldElement> {
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()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@
arguments: Vec<BrilligParameter>,
return_parameters: Vec<BrilligParameter>,
target_function: FunctionId,
disable_procedures: bool,
) -> BrilligArtifact<F> {
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);
Expand Down Expand Up @@ -161,7 +158,7 @@
}

for (i, bit_size) in arguments.iter().flat_map(flat_bit_sizes).enumerate() {
// Calldatacopy tags everything with field type, so when downcast when necessary

Check warning on line 161 in compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Calldatacopy)
if bit_size < F::max_num_bits() {
self.cast_instruction(
SingleAddrVariable::new(
Expand Down
22 changes: 22 additions & 0 deletions compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -25,6 +33,10 @@ pub(crate) enum ProcedureId {
ArrayReverse,
VectorCopy,
MemCopy,
PrepareVectorPush(bool),
VectorPop(bool),
PrepareVectorInsert,
VectorRemove,
}

pub(crate) fn compile_procedure<F: AcirField + DebugToString>(
Expand All @@ -38,6 +50,16 @@ pub(crate) fn compile_procedure<F: AcirField + DebugToString>(
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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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<F: AcirField + DebugToString, Registers: RegisterAllocator> BrilligContext<F, Registers> {
/// 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<F: AcirField + DebugToString>(
brillig_context: &mut BrilligContext<F, ScratchSpace>,
) {
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);
}
Original file line number Diff line number Diff line change
@@ -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<F: AcirField + DebugToString, Registers: RegisterAllocator> BrilligContext<F, Registers> {
/// 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<F: AcirField + DebugToString>(
brillig_context: &mut BrilligContext<F, ScratchSpace>,
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);
}
Loading
Loading