Skip to content

Commit

Permalink
feat(brillig): runtime memory allocation (#1732)
Browse files Browse the repository at this point in the history
* feat: use dynamic memory allocation

* docs: update comments

* refactor: rename allocation methods

* docs: updated comment

* refactor: changes from peer review
  • Loading branch information
sirasistant authored Jun 16, 2023
1 parent 6f49402 commit 7b999e8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 37 deletions.
7 changes: 7 additions & 0 deletions crates/noirc_evaluator/src/brillig/brillig_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ pub(crate) fn convert_ssa_function(func: &Function) -> BrilligArtifact {

brillig_context.artifact()
}

/// Creates an entry point artifact, that will be linked with the brillig functions being called
pub(crate) fn create_entry_point_function(num_arguments: usize) -> BrilligArtifact {
let mut brillig_context = BrilligContext::default();
brillig_context.entry_point_instruction(num_arguments);
brillig_context.artifact()
}
12 changes: 6 additions & 6 deletions crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::brillig::brillig_ir::{
BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE,
BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
};
use crate::ssa_refactor::ir::types::CompositeType;
use crate::ssa_refactor::ir::{
Expand Down Expand Up @@ -113,7 +113,7 @@ impl<'block> BrilligBlock<'block> {
let pointer_register = self
.function_context
.get_or_create_register(self.brillig_context, *param_id);
self.brillig_context.allocate_array(pointer_register, *size as u32);
self.brillig_context.allocate_fixed_length_array(pointer_register, *size);
}
_ => {
todo!("ICE: Param type not supported")
Expand Down Expand Up @@ -228,7 +228,7 @@ impl<'block> BrilligBlock<'block> {

// First issue a array copy to the destination
let array_size = compute_size_of_type(&dfg.type_of_value(*array));
self.brillig_context.allocate_array(destination, array_size as u32);
self.brillig_context.allocate_fixed_length_array(destination, array_size);
let source_array_register: RegisterIndex = self.convert_ssa_value(*array, dfg);
let size_register = self.brillig_context.make_constant(array_size.into());
self.brillig_context.copy_array_instruction(
Expand Down Expand Up @@ -281,7 +281,7 @@ impl<'block> BrilligBlock<'block> {
iterator_register,
BrilligBinaryOp::Integer {
op: BinaryIntOp::Add,
bit_size: BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE,
bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
},
);
}
Expand Down Expand Up @@ -369,9 +369,9 @@ impl<'block> BrilligBlock<'block> {
}
Value::Array { .. } => {
let address_register = self.brillig_context.create_register();
self.brillig_context.allocate_array(
self.brillig_context.allocate_fixed_length_array(
address_register,
compute_size_of_type(&dfg.type_of_value(value_id)) as u32,
compute_size_of_type(&dfg.type_of_value(value_id)),
);
self.store_in_memory(address_register, value_id, dfg);
address_register
Expand Down
79 changes: 65 additions & 14 deletions crates/noirc_evaluator/src/brillig/brillig_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@
//! 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 memory;

use self::{
artifact::{BrilligArtifact, UnresolvedJumpLocation},
memory::BrilligMemory,
};
use self::artifact::{BrilligArtifact, UnresolvedJumpLocation};
use acvm::{
acir::brillig_vm::{
BinaryFieldOp, BinaryIntOp, Opcode as BrilligOpcode, RegisterIndex, RegisterValueOrArray,
Expand All @@ -30,6 +26,27 @@ use acvm::{
/// would mean that unconstrained functions will differ from
/// constrained functions in terms of syntax compatibility.
pub(crate) const BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE: u32 = 127;
pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64;

// Registers reserved in runtime for special purposes.
pub(crate) enum ReservedRegisters {
/// This register stores the stack pointer. Allocations must be done after this pointer.
StackPointer = 0,
/// Number of reserved registers
Len = 1,
}

impl ReservedRegisters {
/// Returns the length of the reserved registers
pub(crate) fn len() -> usize {
ReservedRegisters::Len as usize
}

/// Returns the stack pointer register. This will get used to allocate memory in runtime.
pub(crate) fn stack_pointer() -> RegisterIndex {
RegisterIndex::from(ReservedRegisters::StackPointer as usize)
}
}

/// Brillig context object that is used while constructing the
/// Brillig bytecode.
Expand All @@ -38,8 +55,6 @@ pub(crate) struct BrilligContext {
obj: BrilligArtifact,
/// A usize indicating the latest un-used register.
latest_register: usize,
/// Tracks memory allocations
memory: BrilligMemory,
/// Context label, must be unique with respect to the function
/// being linked.
context_label: String,
Expand All @@ -48,6 +63,17 @@ pub(crate) struct BrilligContext {
}

impl BrilligContext {
/// Adds the instructions needed to handle entry point parameters
/// And sets the starting value of the reserved registers
pub(crate) fn entry_point_instruction(&mut self, num_arguments: usize) {
// Translate the inputs by the reserved registers offset
for i in (0..num_arguments).into_iter().rev() {
self.mov_instruction(self.user_register_index(i), RegisterIndex::from(i));
}
// Set the initial value of the stack pointer register
self.const_instruction(ReservedRegisters::stack_pointer(), Value::from(0_usize));
}

/// Adds a brillig instruction to the brillig byte code
pub(crate) fn push_opcode(&mut self, opcode: BrilligOpcode) {
self.obj.byte_code.push(opcode);
Expand All @@ -60,12 +86,32 @@ impl BrilligContext {

/// Allocates an array of size `size` and stores the pointer to the array
/// in `pointer_register`
pub(crate) fn allocate_array(&mut self, pointer_register: RegisterIndex, size: u32) {
let allocation = self.memory.allocate(size as usize);
pub(crate) fn allocate_fixed_length_array(
&mut self,
pointer_register: RegisterIndex,
size: usize,
) {
let size_register = self.make_constant(size.into());
self.allocate_array_instruction(pointer_register, size_register);
}

self.push_opcode(BrilligOpcode::Const {
/// Allocates an array of size contained in size_register and stores the
/// pointer to the array in `pointer_register`
pub(crate) fn allocate_array_instruction(
&mut self,
pointer_register: RegisterIndex,
size_register: RegisterIndex,
) {
self.push_opcode(BrilligOpcode::Mov {
destination: pointer_register,
value: Value::from(allocation),
source: ReservedRegisters::stack_pointer(),
});
self.push_opcode(BrilligOpcode::BinaryIntOp {
destination: ReservedRegisters::stack_pointer(),
op: BinaryIntOp::Add,
bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
lhs: ReservedRegisters::stack_pointer(),
rhs: size_register,
});
}

Expand Down Expand Up @@ -130,7 +176,7 @@ impl BrilligContext {
index_less_than_array_len,
BrilligBinaryOp::Integer {
op: BinaryIntOp::LessThan,
bit_size: BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE,
bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
},
);

Expand All @@ -152,7 +198,7 @@ impl BrilligContext {
index,
BrilligBinaryOp::Integer {
op: BinaryIntOp::Add,
bit_size: BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE,
bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
},
);

Expand Down Expand Up @@ -221,9 +267,14 @@ impl BrilligContext {
self.obj.add_unresolved_jump(jmp_instruction, destination);
}

/// Returns a user defined (non-reserved) register index.
fn user_register_index(&self, index: usize) -> RegisterIndex {
RegisterIndex::from(index + ReservedRegisters::len())
}

/// Creates a new register.
pub(crate) fn create_register(&mut self) -> RegisterIndex {
let register = RegisterIndex::from(self.latest_register);
let register = self.user_register_index(self.latest_register);
self.latest_register += 1;
register
}
Expand Down
15 changes: 0 additions & 15 deletions crates/noirc_evaluator/src/brillig/brillig_ir/memory.rs

This file was deleted.

4 changes: 2 additions & 2 deletions crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::collections::HashMap;

use crate::brillig::{brillig_ir::artifact::BrilligArtifact, Brillig};
use crate::brillig::{brillig_gen::create_entry_point_function, Brillig};

use self::acir_ir::{
acir_variable::{AcirContext, AcirType, AcirVar},
Expand Down Expand Up @@ -183,7 +183,7 @@ impl Context {
let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg));

// Generate the brillig code of the function
let code = BrilligArtifact::default().link(&brillig[*id]);
let code = create_entry_point_function(arguments.len()).link(&brillig[*id]);

let outputs: Vec<AcirType> = vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into());

Expand Down

0 comments on commit 7b999e8

Please sign in to comment.