diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index 39e73eff7bb..39a012f2d3c 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -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() +} diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index ca5a0748eed..af25f2945ad 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -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::{ @@ -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") @@ -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( @@ -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, }, ); } @@ -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 diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir.rs b/crates/noirc_evaluator/src/brillig/brillig_ir.rs index cc83f657a7f..9886981d49a 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_ir.rs @@ -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, @@ -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. @@ -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, @@ -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); @@ -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, }); } @@ -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, }, ); @@ -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, }, ); @@ -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 } diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir/memory.rs b/crates/noirc_evaluator/src/brillig/brillig_ir/memory.rs deleted file mode 100644 index 099dbfb7704..00000000000 --- a/crates/noirc_evaluator/src/brillig/brillig_ir/memory.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// Simple memory allocator for brillig -/// For now it just tracks a free memory pointer -/// Will probably get smarter in the future -#[derive(Default)] -pub(crate) struct BrilligMemory { - free_mem_pointer: usize, -} - -impl BrilligMemory { - pub(crate) fn allocate(&mut self, size: usize) -> usize { - let start = self.free_mem_pointer; - self.free_mem_pointer += size; - start - } -} diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs index 50fce089556..31a562d7c2a 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs @@ -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}, @@ -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 = vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into());