diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 7330269fb4b..530b6dc69fc 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,7 +1,9 @@ use crate::brillig::brillig_ir::brillig_variable::{ type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, }; -use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; +use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, +}; use crate::ssa::ir::dfg::CallStack; use crate::ssa::ir::instruction::ConstrainError; use crate::ssa::ir::{ @@ -23,7 +25,7 @@ use num_bigint::BigUint; use super::brillig_black_box::convert_black_box_call; use super::brillig_block_variables::BlockVariables; -use super::brillig_fn::{get_bit_size_from_ssa_type, FunctionContext}; +use super::brillig_fn::FunctionContext; /// Generate the compilation artifacts for compiling a function into brillig bytecode. pub(crate) struct BrilligBlock<'block> { @@ -282,8 +284,8 @@ impl<'block> BrilligBlock<'block> { condition, ); - self.brillig_context.constrain_instruction(condition.address, assert_message); - self.brillig_context.deallocate_register(condition.address); + self.brillig_context.constrain_instruction(condition, assert_message); + self.brillig_context.deallocate_single_addr(condition); } Instruction::Allocate => { let result_value = dfg.instruction_results(instruction_id)[0]; @@ -496,10 +498,10 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.mov_instruction(target_len.address, limb_count.address); self.brillig_context.radix_instruction( - source.address, + source, target_vector, - radix.address, - limb_count.address, + radix, + limb_count, matches!(endianness, Endian::Big), ); } @@ -530,22 +532,20 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::SingleAddr(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self - .brillig_context - .make_constant(2_usize.into(), FieldElement::max_num_bits()); + let radix = self.brillig_context.make_constant(2_usize.into(), 32); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len.address, limb_count.address); self.brillig_context.radix_instruction( - source.address, + source, target_vector, radix, - limb_count.address, + limb_count, matches!(endianness, Endian::Big), ); - self.brillig_context.deallocate_register(radix); + self.brillig_context.deallocate_single_addr(radix); } _ => { unreachable!("unsupported function call type {:?}", dfg[*func]) @@ -597,7 +597,7 @@ impl<'block> BrilligBlock<'block> { self.validate_array_index(array_variable, index_variable); self.retrieve_variable_from_array( array_pointer, - index_variable.address, + index_variable, destination_variable, ); } @@ -641,22 +641,20 @@ impl<'block> BrilligBlock<'block> { ); // Check if lte max - let brillig_binary_op = BrilligBinaryOp::Integer { - op: BinaryIntOp::LessThanEquals, - bit_size: FieldElement::max_num_bits(), - }; - let condition = self.brillig_context.allocate_register(); + let brillig_binary_op = BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals); + let condition = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); self.brillig_context.binary_instruction( - left.address, + left, right, condition, brillig_binary_op, ); self.brillig_context.constrain_instruction(condition, assert_message.clone()); - self.brillig_context.deallocate_register(condition); - self.brillig_context.deallocate_register(left.address); - self.brillig_context.deallocate_register(right); + self.brillig_context.deallocate_single_addr(condition); + self.brillig_context.deallocate_single_addr(left); + self.brillig_context.deallocate_single_addr(right); } } Instruction::IncrementRc { value } => { @@ -751,16 +749,18 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { (self.brillig_context.make_usize_constant(size.into()), true) } - BrilligVariable::BrilligVector(BrilligVector { size, .. }) => (size, false), + BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { + (SingleAddrVariable::new_usize(size), false) + } _ => unreachable!("ICE: validate array index on non-array"), }; - let condition = self.brillig_context.allocate_register(); + let condition = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); self.brillig_context.memory_op( index_register.address, - size_as_register, - condition, + size_as_register.address, + condition.address, BinaryIntOp::LessThan, ); @@ -768,28 +768,28 @@ impl<'block> BrilligBlock<'block> { .constrain_instruction(condition, Some("Array index out of bounds".to_owned())); if should_deallocate_size { - self.brillig_context.deallocate_register(size_as_register); + self.brillig_context.deallocate_single_addr(size_as_register); } - self.brillig_context.deallocate_register(condition); + self.brillig_context.deallocate_single_addr(condition); } pub(crate) fn retrieve_variable_from_array( &mut self, array_pointer: MemoryAddress, - index_register: MemoryAddress, + index_var: SingleAddrVariable, destination_variable: BrilligVariable, ) { match destination_variable { BrilligVariable::SingleAddr(destination_register) => { self.brillig_context.array_get( array_pointer, - index_register, + index_var, destination_register.address, ); } BrilligVariable::BrilligArray(..) | BrilligVariable::BrilligVector(..) => { let reference = self.brillig_context.allocate_register(); - self.brillig_context.array_get(array_pointer, index_register, reference); + self.brillig_context.array_get(array_pointer, index_var, reference); self.brillig_context.load_variable_instruction(destination_variable, reference); self.brillig_context.deallocate_register(reference); } @@ -831,15 +831,9 @@ impl<'block> BrilligBlock<'block> { _ => unreachable!("ICE: array set on non-array"), }; - let one = self.brillig_context.make_usize_constant(1_usize.into()); let condition = self.brillig_context.allocate_register(); - self.brillig_context.binary_instruction( - reference_count, - one, - condition, - BrilligBinaryOp::Field { op: BinaryFieldOp::Equals }, - ); + self.brillig_context.usize_op(reference_count, condition, BinaryIntOp::Equals, 1_usize); self.brillig_context.branch_instruction(condition, |ctx, cond| { if cond { @@ -852,7 +846,10 @@ impl<'block> BrilligBlock<'block> { ctx.copy_array_instruction( source_pointer, destination_pointer, - source_size_as_register, + SingleAddrVariable::new( + source_size_as_register, + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + ), ); } }); @@ -873,17 +870,20 @@ impl<'block> BrilligBlock<'block> { } // Then set the value in the newly created array - self.store_variable_in_array(destination_pointer, index_register, value_variable); + self.store_variable_in_array( + destination_pointer, + SingleAddrVariable::new_usize(index_register), + value_variable, + ); self.brillig_context.deallocate_register(source_size_as_register); - self.brillig_context.deallocate_register(one); self.brillig_context.deallocate_register(condition); } pub(crate) fn store_variable_in_array_with_ctx( ctx: &mut BrilligContext, destination_pointer: MemoryAddress, - index_register: MemoryAddress, + index_register: SingleAddrVariable, value_variable: BrilligVariable, ) { match value_variable { @@ -910,13 +910,13 @@ impl<'block> BrilligBlock<'block> { pub(crate) fn store_variable_in_array( &mut self, destination_pointer: MemoryAddress, - index_register: MemoryAddress, + index_variable: SingleAddrVariable, value_variable: BrilligVariable, ) { Self::store_variable_in_array_with_ctx( self.brillig_context, destination_pointer, - index_register, + index_variable, value_variable, ); } @@ -1082,9 +1082,9 @@ impl<'block> BrilligBlock<'block> { let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( - converted_index, + converted_index.address, user_index.address, - converted_index, + converted_index.address, BinaryIntOp::Mul, ); @@ -1095,7 +1095,7 @@ impl<'block> BrilligBlock<'block> { self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); self.slice_insert_operation(target_vector, source_vector, converted_index, &items); - self.brillig_context.deallocate_register(converted_index); + self.brillig_context.deallocate_single_addr(converted_index); } Value::Intrinsic(Intrinsic::SliceRemove) => { let target_len = match self.variables.define_variable( @@ -1124,9 +1124,9 @@ impl<'block> BrilligBlock<'block> { let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( - converted_index, + converted_index.address, user_index.address, - converted_index, + converted_index.address, BinaryIntOp::Mul, ); @@ -1148,7 +1148,7 @@ impl<'block> BrilligBlock<'block> { &removed_items, ); - self.brillig_context.deallocate_register(converted_index); + self.brillig_context.deallocate_single_addr(converted_index); } _ => unreachable!("ICE: Slice operation not supported"), } @@ -1201,12 +1201,7 @@ impl<'block> BrilligBlock<'block> { let (brillig_binary_op, is_signed) = convert_ssa_binary_op_to_brillig_binary_op(binary.operator, &binary_type); - self.brillig_context.binary_instruction( - left.address, - right.address, - result_variable.address, - brillig_binary_op, - ); + self.brillig_context.binary_instruction(left, right, result_variable, brillig_binary_op); self.add_overflow_check(brillig_binary_op, left, right, result_variable, is_signed); } @@ -1219,77 +1214,83 @@ impl<'block> BrilligBlock<'block> { result: SingleAddrVariable, is_signed: bool, ) { - let (op, bit_size) = if let BrilligBinaryOp::Integer { op, bit_size } = binary_operation { - (op, bit_size) + let (op, bit_size) = if let BrilligBinaryOp::Integer(op) = binary_operation { + // Bit size is checked at compile time to be equal for left and right + (op, left.bit_size) } else { return; }; match (op, is_signed) { (BinaryIntOp::Add, false) => { - let condition = self.brillig_context.allocate_register(); + let condition = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); // Check that lhs <= result self.brillig_context.binary_instruction( - left.address, - result.address, + left, + result, condition, - BrilligBinaryOp::Integer { op: BinaryIntOp::LessThanEquals, bit_size }, + BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals), ); self.brillig_context.constrain_instruction( condition, Some("attempt to add with overflow".to_string()), ); - self.brillig_context.deallocate_register(condition); + self.brillig_context.deallocate_single_addr(condition); } (BinaryIntOp::Sub, false) => { - let condition = self.brillig_context.allocate_register(); + let condition = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); // Check that rhs <= lhs self.brillig_context.binary_instruction( - right.address, - left.address, + right, + left, condition, - BrilligBinaryOp::Integer { op: BinaryIntOp::LessThanEquals, bit_size }, + BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals), ); self.brillig_context.constrain_instruction( condition, Some("attempt to subtract with overflow".to_string()), ); - self.brillig_context.deallocate_register(condition); + self.brillig_context.deallocate_single_addr(condition); } (BinaryIntOp::Mul, false) => { // Multiplication overflow is only possible for bit sizes > 1 if bit_size > 1 { - let is_right_zero = self.brillig_context.allocate_register(); + let is_right_zero = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); let zero = self.brillig_context.make_constant(0_usize.into(), bit_size); self.brillig_context.binary_instruction( zero, - right.address, + right, is_right_zero, - BrilligBinaryOp::Integer { op: BinaryIntOp::Equals, bit_size }, + BrilligBinaryOp::Integer(BinaryIntOp::Equals), ); - self.brillig_context.if_not_instruction(is_right_zero, |ctx| { - let condition = ctx.allocate_register(); + self.brillig_context.if_not_instruction(is_right_zero.address, |ctx| { + let condition = SingleAddrVariable::new(ctx.allocate_register(), 1); + let division = SingleAddrVariable::new(ctx.allocate_register(), bit_size); // Check that result / rhs == lhs ctx.binary_instruction( - result.address, - right.address, - condition, - BrilligBinaryOp::Integer { op: BinaryIntOp::UnsignedDiv, bit_size }, + result, + right, + division, + BrilligBinaryOp::Integer(BinaryIntOp::UnsignedDiv), ); ctx.binary_instruction( + division, + left, condition, - left.address, - condition, - BrilligBinaryOp::Integer { op: BinaryIntOp::Equals, bit_size }, + BrilligBinaryOp::Integer(BinaryIntOp::Equals), ); ctx.constrain_instruction( condition, Some("attempt to multiply with overflow".to_string()), ); - ctx.deallocate_register(condition); + ctx.deallocate_single_addr(condition); + ctx.deallocate_single_addr(division); }); - self.brillig_context.deallocate_register(is_right_zero); - self.brillig_context.deallocate_register(zero); + self.brillig_context.deallocate_single_addr(is_right_zero); + self.brillig_context.deallocate_single_addr(zero); } } _ => {} @@ -1307,7 +1308,7 @@ impl<'block> BrilligBlock<'block> { // converted to registers so we fetch from the cache. self.variables.get_allocation(self.function_context, value_id, dfg) } - Value::NumericConstant { constant, typ } => { + Value::NumericConstant { constant, .. } => { // Constants might have been converted previously or not, so we get or create and // (re)initialize the value inside. if let Some(variable) = self.variables.get_constant(value_id, dfg) { @@ -1315,13 +1316,9 @@ impl<'block> BrilligBlock<'block> { } else { let new_variable = self.variables.allocate_constant(self.brillig_context, value_id, dfg); - let register_index = new_variable.extract_single_addr(); - self.brillig_context.const_instruction( - register_index.address, - (*constant).into(), - get_bit_size_from_ssa_type(typ), - ); + self.brillig_context + .const_instruction(new_variable.extract_single_addr(), (*constant).into()); new_variable } } @@ -1366,13 +1363,13 @@ impl<'block> BrilligBlock<'block> { self.store_variable_in_array(pointer, iterator_register, element_variable); // Increment the iterator self.brillig_context.usize_op_in_place( - iterator_register, + iterator_register.address, BinaryIntOp::Add, 1, ); } - self.brillig_context.deallocate_register(iterator_register); + self.brillig_context.deallocate_single_addr(iterator_register); new_variable } @@ -1384,12 +1381,10 @@ impl<'block> BrilligBlock<'block> { // value. let new_variable = self.variables.allocate_constant(self.brillig_context, value_id, dfg); - let register_index = new_variable.extract_single_addr(); self.brillig_context.const_instruction( - register_index.address, + new_variable.extract_single_addr(), value_id.to_usize().into(), - 32, ); new_variable } @@ -1538,18 +1533,18 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( fn binary_op_to_field_op(op: BinaryOp) -> BrilligBinaryOp { match op { - BinaryOp::Add => BrilligBinaryOp::Field { op: BinaryFieldOp::Add }, - BinaryOp::Sub => BrilligBinaryOp::Field { op: BinaryFieldOp::Sub }, - BinaryOp::Mul => BrilligBinaryOp::Field { op: BinaryFieldOp::Mul }, - BinaryOp::Div => BrilligBinaryOp::Field { op: BinaryFieldOp::Div }, - BinaryOp::Eq => BrilligBinaryOp::Field { op: BinaryFieldOp::Equals }, + BinaryOp::Add => BrilligBinaryOp::Field(BinaryFieldOp::Add), + BinaryOp::Sub => BrilligBinaryOp::Field(BinaryFieldOp::Sub), + BinaryOp::Mul => BrilligBinaryOp::Field(BinaryFieldOp::Mul), + BinaryOp::Div => BrilligBinaryOp::Field(BinaryFieldOp::Div), + BinaryOp::Eq => BrilligBinaryOp::Field(BinaryFieldOp::Equals), _ => unreachable!( "Field type cannot be used with {op}. This should have been caught by the frontend" ), } } - fn binary_op_to_int_op(op: BinaryOp, bit_size: u32, is_signed: bool) -> BrilligBinaryOp { + fn binary_op_to_int_op(op: BinaryOp, is_signed: bool) -> BrilligBinaryOp { let operation = match op { BinaryOp::Add => BinaryIntOp::Add, BinaryOp::Sub => BinaryIntOp::Sub, @@ -1561,9 +1556,7 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( BinaryIntOp::UnsignedDiv } } - BinaryOp::Mod => { - return BrilligBinaryOp::Modulo { is_signed_integer: is_signed, bit_size } - } + BinaryOp::Mod => return BrilligBinaryOp::Modulo { is_signed_integer: is_signed }, BinaryOp::Eq => BinaryIntOp::Equals, BinaryOp::Lt => BinaryIntOp::LessThan, BinaryOp::And => BinaryIntOp::And, @@ -1573,14 +1566,12 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( BinaryOp::Shr => BinaryIntOp::Shr, }; - BrilligBinaryOp::Integer { op: operation, bit_size } + BrilligBinaryOp::Integer(operation) } // If bit size is available then it is a binary integer operation match bit_size_signedness { - Some((bit_size, is_signed)) => { - (binary_op_to_int_op(ssa_op, *bit_size, is_signed), is_signed) - } + Some((_, is_signed)) => (binary_op_to_int_op(ssa_op, is_signed), is_signed), None => (binary_op_to_field_op(ssa_op), false), } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index f463bd4de4d..dc9900daee3 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -3,7 +3,7 @@ use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ brillig::brillig_ir::{ brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, - BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + BrilligContext, }, ssa::ir::{ basic_block::BasicBlockId, @@ -13,7 +13,7 @@ use crate::{ }, }; -use super::brillig_fn::FunctionContext; +use super::brillig_fn::{get_bit_size_from_ssa_type, FunctionContext}; #[derive(Debug, Default)] pub(crate) struct BlockVariables { @@ -189,21 +189,10 @@ pub(crate) fn allocate_value( let typ = dfg.type_of_value(value_id); match typ { - Type::Numeric(numeric_type) => BrilligVariable::SingleAddr(SingleAddrVariable { - address: brillig_context.allocate_register(), - bit_size: numeric_type.bit_size(), - }), - Type::Reference(_) => BrilligVariable::SingleAddr(SingleAddrVariable { - address: brillig_context.allocate_register(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - }), - Type::Function => { - // NB. function references are converted to a constant when - // translating from SSA to Brillig (to allow for debugger - // instrumentation to work properly) + Type::Numeric(_) | Type::Reference(_) | Type::Function => { BrilligVariable::SingleAddr(SingleAddrVariable { address: brillig_context.allocate_register(), - bit_size: 32, + bit_size: get_bit_size_from_ssa_type(&typ), }) } Type::Array(item_typ, elem_count) => { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index b5da8296ba5..42765d10ce2 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -1,4 +1,3 @@ -use acvm::FieldElement; use iter_extended::vecmap; use crate::{ @@ -11,7 +10,7 @@ use crate::{ basic_block::BasicBlockId, function::{Function, FunctionId}, post_order::PostOrder, - types::{NumericType, Type}, + types::Type, value::ValueId, }, }; @@ -116,11 +115,12 @@ impl FunctionContext { pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { match typ { - Type::Numeric(num_type) => match num_type { - NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => *bit_size, - NumericType::NativeField => FieldElement::max_num_bits(), - }, + Type::Numeric(num_type) => num_type.bit_size(), Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - _ => unreachable!("ICE bitwise not on a non numeric type"), + // NB. function references are converted to a constant when + // translating from SSA to Brillig (to allow for debugger + // instrumentation to work properly) + Type::Function => 32, + _ => unreachable!("ICE bit size not on a non numeric type"), } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 3fc0e981165..969f95cff20 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -1,6 +1,8 @@ -use acvm::brillig_vm::brillig::{BinaryIntOp, MemoryAddress}; +use acvm::brillig_vm::brillig::BinaryIntOp; -use crate::brillig::brillig_ir::brillig_variable::{BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + BrilligVariable, BrilligVector, SingleAddrVariable, +}; use super::brillig_block::BrilligBlock; @@ -26,19 +28,19 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.copy_array_instruction( source_vector.pointer, target_vector.pointer, - source_vector.size, + SingleAddrVariable::new_usize(source_vector.size), ); for (index, variable) in variables_to_insert.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( - target_index, + target_index.address, source_vector.size, - target_index, + target_index.address, BinaryIntOp::Add, ); self.store_variable_in_array(target_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } } @@ -72,14 +74,14 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.copy_array_instruction( source_vector.pointer, destination_copy_pointer, - source_vector.size, + SingleAddrVariable::new_usize(source_vector.size), ); // Then we write the items to insert at the start for (index, variable) in variables_to_insert.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(index.into()); self.store_variable_in_array(target_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } self.brillig_context.deallocate_register(destination_copy_pointer); @@ -115,13 +117,13 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.copy_array_instruction( source_copy_pointer, target_vector.pointer, - target_vector.size, + SingleAddrVariable::new_usize(target_vector.size), ); for (index, variable) in removed_items.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(index.into()); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } self.brillig_context.deallocate_register(source_copy_pointer); @@ -148,19 +150,19 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.copy_array_instruction( source_vector.pointer, target_vector.pointer, - target_vector.size, + SingleAddrVariable::new_usize(target_vector.size), ); for (index, variable) in removed_items.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( - target_index, + target_index.address, target_vector.size, - target_index, + target_index.address, BinaryIntOp::Add, ); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } } @@ -168,7 +170,7 @@ impl<'block> BrilligBlock<'block> { &mut self, target_vector: BrilligVector, source_vector: BrilligVector, - index: MemoryAddress, + index: SingleAddrVariable, items: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by items.len() @@ -193,7 +195,7 @@ impl<'block> BrilligBlock<'block> { let source_pointer_at_index = self.brillig_context.allocate_register(); self.brillig_context.memory_op( source_vector.pointer, - index, + index.address, source_pointer_at_index, BinaryIntOp::Add, ); @@ -202,7 +204,7 @@ impl<'block> BrilligBlock<'block> { let target_pointer_after_index = self.brillig_context.allocate_register(); self.brillig_context.memory_op( target_vector.pointer, - index, + index.address, target_pointer_after_index, BinaryIntOp::Add, ); @@ -214,21 +216,31 @@ impl<'block> BrilligBlock<'block> { // Compute the number of elements to the right of the index let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op(source_vector.size, index, item_count, BinaryIntOp::Sub); + self.brillig_context.memory_op( + source_vector.size, + index.address, + item_count, + BinaryIntOp::Sub, + ); // Copy the elements to the right of the index self.brillig_context.copy_array_instruction( source_pointer_at_index, target_pointer_after_index, - item_count, + SingleAddrVariable::new_usize(item_count), ); // Write the items to insert starting at the index for (subitem_index, variable) in items.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); - self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); + self.brillig_context.memory_op( + target_index.address, + index.address, + target_index.address, + BinaryIntOp::Add, + ); self.store_variable_in_array(target_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } self.brillig_context.deallocate_register(source_pointer_at_index); @@ -240,7 +252,7 @@ impl<'block> BrilligBlock<'block> { &mut self, target_vector: BrilligVector, source_vector: BrilligVector, - index: MemoryAddress, + index: SingleAddrVariable, removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() @@ -265,7 +277,7 @@ impl<'block> BrilligBlock<'block> { let source_pointer_after_index = self.brillig_context.allocate_register(); self.brillig_context.memory_op( source_vector.pointer, - index, + index.address, source_pointer_after_index, BinaryIntOp::Add, ); @@ -279,29 +291,39 @@ impl<'block> BrilligBlock<'block> { let target_pointer_at_index = self.brillig_context.allocate_register(); self.brillig_context.memory_op( target_vector.pointer, - index, + index.address, target_pointer_at_index, BinaryIntOp::Add, ); // Compute the number of elements to the right of the index let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op(source_vector.size, index, item_count, BinaryIntOp::Sub); + self.brillig_context.memory_op( + source_vector.size, + index.address, + item_count, + BinaryIntOp::Sub, + ); self.brillig_context.usize_op_in_place(item_count, BinaryIntOp::Sub, removed_items.len()); // Copy the elements to the right of the index self.brillig_context.copy_array_instruction( source_pointer_after_index, target_pointer_at_index, - item_count, + SingleAddrVariable::new_usize(item_count), ); // Get the removed items for (subitem_index, variable) in removed_items.iter().enumerate() { let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); - self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); + self.brillig_context.memory_op( + target_index.address, + index.address, + target_index.address, + BinaryIntOp::Add, + ); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); - self.brillig_context.deallocate_register(target_index); + self.brillig_context.deallocate_single_addr(target_index); } self.brillig_context.deallocate_register(source_pointer_after_index); @@ -592,7 +614,10 @@ mod tests { address: context.allocate_register(), bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; - let index_to_insert = context.allocate_register(); + let index_to_insert = SingleAddrVariable::new( + context.allocate_register(), + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + ); // Cast the source array to a vector let source_vector = context.array_to_vector(&array_variable); @@ -710,7 +735,10 @@ mod tests { size: array.len(), rc: context.allocate_register(), }; - let index_to_insert = context.allocate_register(); + let index_to_insert = SingleAddrVariable::new( + context.allocate_register(), + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + ); // Cast the source array to a vector let source_vector = context.array_to_vector(&array_variable); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index f1a8f24ed03..1e53713dfe0 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -32,7 +32,7 @@ use num_bigint::BigUint; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -123,8 +123,8 @@ impl BrilligContext { ) { // debug_show handled by allocate_array_instruction let size_register = self.make_usize_constant(size.into()); - self.allocate_array_instruction(pointer_register, size_register); - self.deallocate_register(size_register); + self.allocate_array_instruction(pointer_register, size_register.address); + self.deallocate_single_addr(size_register); } /// Allocates an array of size contained in size_register and stores the @@ -172,11 +172,11 @@ impl BrilligContext { }); self.memory_op( ReservedRegisters::stack_pointer(), - size_register, + size_register.address, ReservedRegisters::stack_pointer(), BinaryIntOp::Add, ); - self.deallocate_register(size_register); + self.deallocate_single_addr(size_register); } pub(crate) fn allocate_single_addr_reference_instruction( @@ -207,18 +207,14 @@ impl BrilligContext { pub(crate) fn array_get( &mut self, array_ptr: MemoryAddress, - index: MemoryAddress, + index: SingleAddrVariable, result: MemoryAddress, ) { - self.debug_show.array_get(array_ptr, index, result); + assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + self.debug_show.array_get(array_ptr, index.address, result); // Computes array_ptr + index, ie array[index] let index_of_element_in_memory = self.allocate_register(); - self.binary_instruction( - array_ptr, - index, - index_of_element_in_memory, - BrilligBinaryOp::Field { op: BinaryFieldOp::Add }, - ); + self.memory_op(array_ptr, index.address, index_of_element_in_memory, BinaryIntOp::Add); self.load_instruction(result, index_of_element_in_memory); // Free up temporary register @@ -229,18 +225,14 @@ impl BrilligContext { pub(crate) fn array_set( &mut self, array_ptr: MemoryAddress, - index: MemoryAddress, + index: SingleAddrVariable, value: MemoryAddress, ) { - self.debug_show.array_set(array_ptr, index, value); + assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + self.debug_show.array_set(array_ptr, index.address, value); // Computes array_ptr + index, ie array[index] let index_of_element_in_memory = self.allocate_register(); - self.binary_instruction( - array_ptr, - index, - index_of_element_in_memory, - BrilligBinaryOp::Field { op: BinaryFieldOp::Add }, - ); + self.memory_op(array_ptr, index.address, index_of_element_in_memory, BinaryIntOp::Add); self.store_instruction(index_of_element_in_memory, value); // Free up temporary register @@ -253,17 +245,18 @@ impl BrilligContext { &mut self, source_pointer: MemoryAddress, destination_pointer: MemoryAddress, - num_elements_register: MemoryAddress, + num_elements_variable: SingleAddrVariable, ) { + assert!(num_elements_variable.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); self.debug_show.copy_array_instruction( source_pointer, destination_pointer, - num_elements_register, + num_elements_variable.address, ); let value_register = self.allocate_register(); - self.loop_instruction(num_elements_register, |ctx, iterator| { + self.loop_instruction(num_elements_variable.address, |ctx, iterator| { ctx.array_get(source_pointer, iterator, value_register); ctx.array_set(destination_pointer, iterator, value_register); }); @@ -275,7 +268,7 @@ impl BrilligContext { /// The body of the loop should be issued by the caller in the on_iteration closure. pub(crate) fn loop_instruction(&mut self, iteration_count: MemoryAddress, on_iteration: F) where - F: FnOnce(&mut BrilligContext, MemoryAddress), + F: FnOnce(&mut BrilligContext, SingleAddrVariable), { let iterator_register = self.make_usize_constant(0_u128.into()); @@ -289,7 +282,7 @@ impl BrilligContext { SingleAddrVariable { address: self.allocate_register(), bit_size: 1 }; self.memory_op( - iterator_register, + iterator_register.address, iteration_count, iterator_less_than_iterations.address, BinaryIntOp::LessThan, @@ -305,7 +298,7 @@ impl BrilligContext { on_iteration(self, iterator_register); // Increment the iterator register - self.usize_op_in_place(iterator_register, BinaryIntOp::Add, 1); + self.usize_op_in_place(iterator_register.address, BinaryIntOp::Add, 1); self.jump_instruction(loop_label); @@ -313,8 +306,8 @@ impl BrilligContext { self.enter_section(exit_loop_section); // Deallocate our temporary registers - self.deallocate_register(iterator_less_than_iterations.address); - self.deallocate_register(iterator_register); + self.deallocate_single_addr(iterator_less_than_iterations); + self.deallocate_single_addr(iterator_register); } /// This instruction will issue an if-then branch that will check if the condition is true @@ -430,11 +423,14 @@ impl BrilligContext { } /// Push a register to the deallocation list, ready for reuse. - /// TODO(AD): currently, register deallocation is only done with immediate values. - /// TODO(AD): See https://github.com/noir-lang/noir/issues/1720 pub(crate) fn deallocate_register(&mut self, register_index: MemoryAddress) { self.registers.deallocate_register(register_index); } + + /// Deallocates the address where the single address variable is stored + pub(crate) fn deallocate_single_addr(&mut self, var: SingleAddrVariable) { + self.deallocate_register(var.address); + } } impl BrilligContext { @@ -442,12 +438,16 @@ impl BrilligContext { /// is false. pub(crate) fn constrain_instruction( &mut self, - condition: MemoryAddress, + condition: SingleAddrVariable, assert_message: Option, ) { - self.debug_show.constrain_instruction(condition); + assert!(condition.bit_size == 1); + self.debug_show.constrain_instruction(condition.address); let (next_section, next_label) = self.reserve_next_section_label(); - self.add_unresolved_jump(BrilligOpcode::JumpIf { condition, location: 0 }, next_label); + self.add_unresolved_jump( + BrilligOpcode::JumpIf { condition: condition.address, location: 0 }, + next_label, + ); self.push_opcode(BrilligOpcode::Trap); if let Some(assert_message) = assert_message { self.obj.add_assert_message_to_last_opcode(assert_message); @@ -526,47 +526,81 @@ impl BrilligContext { }); } + fn binary_result_bit_size(operation: BrilligBinaryOp, arguments_bit_size: u32) -> u32 { + match operation { + BrilligBinaryOp::Field(BinaryFieldOp::Equals) + | BrilligBinaryOp::Integer(BinaryIntOp::Equals) + | BrilligBinaryOp::Integer(BinaryIntOp::LessThan) + | BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals) => 1, + _ => arguments_bit_size, + } + } + /// Processes a binary instruction according `operation`. /// /// This method will compute lhs rhs /// and store the result in the `result` register. pub(crate) fn binary_instruction( &mut self, - lhs: MemoryAddress, - rhs: MemoryAddress, - result: MemoryAddress, + lhs: SingleAddrVariable, + rhs: SingleAddrVariable, + result: SingleAddrVariable, operation: BrilligBinaryOp, ) { - self.debug_show.binary_instruction(lhs, rhs, result, operation); + assert!( + lhs.bit_size == rhs.bit_size, + "Not equal bit size for lhs and rhs: lhs {}, rhs {}", + lhs.bit_size, + rhs.bit_size + ); + let expected_result_bit_size = + BrilligContext::binary_result_bit_size(operation, lhs.bit_size); + assert!( + result.bit_size == expected_result_bit_size, + "Expected result bit size to be {}, got {} for operation {:?}", + expected_result_bit_size, + result.bit_size, + operation + ); + self.debug_show.binary_instruction(lhs.address, rhs.address, result.address, operation); match operation { - BrilligBinaryOp::Field { op } => { - let opcode = BrilligOpcode::BinaryFieldOp { op, destination: result, lhs, rhs }; + BrilligBinaryOp::Field(op) => { + let opcode = BrilligOpcode::BinaryFieldOp { + op, + destination: result.address, + lhs: lhs.address, + rhs: rhs.address, + }; self.push_opcode(opcode); } - BrilligBinaryOp::Integer { op, bit_size } => { - let opcode = - BrilligOpcode::BinaryIntOp { op, destination: result, bit_size, lhs, rhs }; + BrilligBinaryOp::Integer(op) => { + let opcode = BrilligOpcode::BinaryIntOp { + op, + destination: result.address, + bit_size: lhs.bit_size, + lhs: lhs.address, + rhs: rhs.address, + }; self.push_opcode(opcode); } - BrilligBinaryOp::Modulo { is_signed_integer, bit_size } => { - self.modulo_instruction(result, lhs, rhs, bit_size, is_signed_integer); + BrilligBinaryOp::Modulo { is_signed_integer } => { + self.modulo_instruction(result, lhs, rhs, is_signed_integer); } } } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction( - &mut self, - result: MemoryAddress, - constant: Value, - bit_size: u32, - ) { - self.debug_show.const_instruction(result, constant); - self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); + pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { + self.debug_show.const_instruction(result.address, constant); + self.push_opcode(BrilligOpcode::Const { + destination: result.address, + value: constant, + bit_size: result.bit_size, + }); } pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { - self.const_instruction(result, constant, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + self.const_instruction(SingleAddrVariable::new_usize(result), constant); } /// Processes a not instruction. @@ -583,15 +617,16 @@ impl BrilligContext { let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) - FieldElement::one(); let max = self.make_constant(Value::from(u_max), input.bit_size); + let opcode = BrilligOpcode::BinaryIntOp { destination: result.address, op: BinaryIntOp::Sub, bit_size: input.bit_size, - lhs: max, + lhs: max.address, rhs: input.address, }; self.push_opcode(opcode); - self.deallocate_register(max); + self.deallocate_single_addr(max); } /// Processes a foreign call instruction. @@ -750,13 +785,13 @@ impl BrilligContext { ); self.binary_instruction( - value_to_truncate.address, + value_to_truncate, mask_constant, - destination_of_truncated_value.address, - BrilligBinaryOp::Integer { op: BinaryIntOp::And, bit_size: value_to_truncate.bit_size }, + destination_of_truncated_value, + BrilligBinaryOp::Integer(BinaryIntOp::And), ); - self.deallocate_register(mask_constant); + self.deallocate_single_addr(mask_constant); } /// Emits a stop instruction @@ -766,17 +801,17 @@ impl BrilligContext { } /// Returns a register which holds the value of a constant - pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> MemoryAddress { - let register = self.allocate_register(); - self.const_instruction(register, constant, bit_size); - register + pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> SingleAddrVariable { + let var = SingleAddrVariable::new(self.allocate_register(), bit_size); + self.const_instruction(var, constant); + var } /// Returns a register which holds the value of an usize constant - pub(crate) fn make_usize_constant(&mut self, constant: Value) -> MemoryAddress { + pub(crate) fn make_usize_constant(&mut self, constant: Value) -> SingleAddrVariable { let register = self.allocate_register(); self.usize_const(register, constant); - register + SingleAddrVariable::new_usize(register) } /// Computes left % right by emitting the necessary Brillig opcodes. @@ -790,16 +825,22 @@ impl BrilligContext { /// to other binary instructions. pub(crate) fn modulo_instruction( &mut self, - result_register: MemoryAddress, - left: MemoryAddress, - right: MemoryAddress, - bit_size: u32, + result: SingleAddrVariable, + left: SingleAddrVariable, + right: SingleAddrVariable, signed: bool, ) { // no debug_show, shown in binary instruction let scratch_register_i = self.allocate_register(); let scratch_register_j = self.allocate_register(); + assert!( + left.bit_size == right.bit_size, + "Not equal bitsize: lhs {}, rhs {}", + left.bit_size, + right.bit_size + ); + let bit_size = left.bit_size; // i = left / right self.push_opcode(BrilligOpcode::BinaryIntOp { op: match signed { @@ -808,8 +849,8 @@ impl BrilligContext { }, destination: scratch_register_i, bit_size, - lhs: left, - rhs: right, + lhs: left.address, + rhs: right.address, }); // j = i * right @@ -818,15 +859,15 @@ impl BrilligContext { destination: scratch_register_j, bit_size, lhs: scratch_register_i, - rhs: right, + rhs: right.address, }); // result_register = left - j self.push_opcode(BrilligOpcode::BinaryIntOp { op: BinaryIntOp::Sub, - destination: result_register, + destination: result.address, bit_size, - lhs: left, + lhs: left.address, rhs: scratch_register_j, }); // Free scratch registers @@ -909,9 +950,9 @@ impl BrilligContext { constant: usize, ) { let const_register = self.make_usize_constant(Value::from(constant)); - self.memory_op(operand, const_register, destination, op); + self.memory_op(operand, const_register.address, destination, op); // Mark as no longer used for this purpose, frees for reuse - self.deallocate_register(const_register); + self.deallocate_single_addr(const_register); } /// Utility method to perform a binary instruction with a memory address @@ -923,10 +964,16 @@ impl BrilligContext { op: BinaryIntOp, ) { self.binary_instruction( - lhs, - rhs, - destination, - BrilligBinaryOp::Integer { op, bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE }, + SingleAddrVariable::new_usize(lhs), + SingleAddrVariable::new_usize(rhs), + SingleAddrVariable::new( + destination, + BrilligContext::binary_result_bit_size( + BrilligBinaryOp::Integer(op), + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + ), + ), + BrilligBinaryOp::Integer(op), ); } @@ -983,7 +1030,7 @@ impl BrilligContext { /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { let size_register = self.make_usize_constant(array.size.into()); - BrilligVector { size: size_register, pointer: array.pointer, rc: array.rc } + BrilligVector { size: size_register.address, pointer: array.pointer, rc: array.rc } } /// Issues a blackbox operation. @@ -996,47 +1043,48 @@ impl BrilligContext { /// And the radix register limb_count times to the target vector. pub(crate) fn radix_instruction( &mut self, - source: MemoryAddress, + source_field: SingleAddrVariable, target_vector: BrilligVector, - radix: MemoryAddress, - limb_count: MemoryAddress, + radix: SingleAddrVariable, + limb_count: SingleAddrVariable, big_endian: bool, ) { - self.mov_instruction(target_vector.size, limb_count); + assert!(source_field.bit_size == FieldElement::max_num_bits()); + assert!(radix.bit_size == 32); + assert!(limb_count.bit_size == 32); + let radix_as_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + self.cast_instruction(radix_as_field, radix); + + self.cast_instruction(SingleAddrVariable::new_usize(target_vector.size), limb_count); self.usize_const(target_vector.rc, 1_usize.into()); self.allocate_array_instruction(target_vector.pointer, target_vector.size); - let shifted_register = self.allocate_register(); - self.mov_instruction(shifted_register, source); + let shifted_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + self.mov_instruction(shifted_field.address, source_field.address); - let modulus_register: MemoryAddress = self.allocate_register(); + let modulus_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); self.loop_instruction(target_vector.size, |ctx, iterator_register| { // Compute the modulus - ctx.modulo_instruction( - modulus_register, - shifted_register, - radix, - FieldElement::max_num_bits(), - false, - ); + ctx.modulo_instruction(modulus_field, shifted_field, radix_as_field, false); // Write it - ctx.array_set(target_vector.pointer, iterator_register, modulus_register); + ctx.array_set(target_vector.pointer, iterator_register, modulus_field.address); // Integer div the field ctx.binary_instruction( - shifted_register, - radix, - shifted_register, - BrilligBinaryOp::Integer { - op: BinaryIntOp::UnsignedDiv, - bit_size: FieldElement::max_num_bits(), - }, + shifted_field, + radix_as_field, + shifted_field, + BrilligBinaryOp::Integer(BinaryIntOp::UnsignedDiv), ); }); // Deallocate our temporary registers - self.deallocate_register(shifted_register); - self.deallocate_register(modulus_register); + self.deallocate_single_addr(shifted_field); + self.deallocate_single_addr(modulus_field); + self.deallocate_single_addr(radix_as_field); if big_endian { self.reverse_vector_in_place_instruction(target_vector); @@ -1061,16 +1109,24 @@ impl BrilligContext { ctx.usize_op_in_place(index_at_end_of_array, BinaryIntOp::Sub, 1); ctx.memory_op( index_at_end_of_array, - iterator_register, + iterator_register.address, index_at_end_of_array, BinaryIntOp::Sub, ); - ctx.array_get(vector.pointer, index_at_end_of_array, end_value_register); + ctx.array_get( + vector.pointer, + SingleAddrVariable::new_usize(index_at_end_of_array), + end_value_register, + ); // Write both values ctx.array_set(vector.pointer, iterator_register, end_value_register); - ctx.array_set(vector.pointer, index_at_end_of_array, start_value_register); + ctx.array_set( + vector.pointer, + SingleAddrVariable::new_usize(index_at_end_of_array), + start_value_register, + ); }); self.deallocate_register(iteration_count); @@ -1086,13 +1142,12 @@ impl BrilligContext { } /// Type to encapsulate the binary operation types in Brillig -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub(crate) enum BrilligBinaryOp { - Field { op: BinaryFieldOp }, - Integer { op: BinaryIntOp, bit_size: u32 }, - // Modulo operation requires more than one opcode - // Brillig. - Modulo { is_signed_integer: bool, bit_size: u32 }, + Field(BinaryFieldOp), + Integer(BinaryIntOp), + // Modulo operation requires more than one brillig opcode + Modulo { is_signed_integer: bool }, } #[cfg(test)] diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 48ad3c5bae4..b94f8140ddd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -5,12 +5,24 @@ use serde::{Deserialize, Serialize}; use crate::ssa::ir::types::Type; +use super::BRILLIG_MEMORY_ADDRESSING_BIT_SIZE; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct SingleAddrVariable { pub(crate) address: MemoryAddress, pub(crate) bit_size: u32, } +impl SingleAddrVariable { + pub(crate) fn new(address: MemoryAddress, bit_size: u32) -> Self { + SingleAddrVariable { address, bit_size } + } + + pub(crate) fn new_usize(address: MemoryAddress) -> Self { + SingleAddrVariable { address, bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE } + } +} + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index dd57f0c4426..e32ce6f6b92 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -1,7 +1,7 @@ //! This module contains functions for producing a higher level view disassembler of Brillig. use super::BrilligBinaryOp; -use crate::brillig::brillig_ir::{ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE}; +use crate::brillig::brillig_ir::ReservedRegisters; use acvm::acir::brillig::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, ValueOrArray, @@ -83,23 +83,11 @@ impl DebugToString for BinaryIntOp { impl DebugToString for BrilligBinaryOp { fn debug_to_string(&self) -> String { match self { - BrilligBinaryOp::Field { op } => op.debug_to_string(), - BrilligBinaryOp::Integer { op, bit_size } => { - // rationale: if there's >= 64 bits, we should not bother with this detail - if *bit_size >= BRILLIG_MEMORY_ADDRESSING_BIT_SIZE { - op.debug_to_string() - } else { - format!("i{}::{}", bit_size, op.debug_to_string()) - } - } - BrilligBinaryOp::Modulo { is_signed_integer, bit_size } => { + BrilligBinaryOp::Field(op) => op.debug_to_string(), + BrilligBinaryOp::Integer(op) => op.debug_to_string(), + BrilligBinaryOp::Modulo { is_signed_integer } => { let op = if *is_signed_integer { "%" } else { "%%" }; - // rationale: if there's >= 64 bits, we should not bother with this detail - if *bit_size >= BRILLIG_MEMORY_ADDRESSING_BIT_SIZE { - op.into() - } else { - format!("{op}:{bit_size}") - } + op.into() } } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 9d186f9bc60..83440e4a51d 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -79,9 +79,9 @@ impl BrilligContext { let rc_register = self.make_usize_constant(1_usize.into()); let flattened_size = BrilligContext::flattened_size(argument); let var = BrilligVariable::BrilligArray(BrilligArray { - pointer: pointer_to_the_array_in_calldata, + pointer: pointer_to_the_array_in_calldata.address, size: flattened_size, - rc: rc_register, + rc: rc_register.address, }); current_calldata_pointer += flattened_size; @@ -218,7 +218,7 @@ impl BrilligContext { self.mov_instruction(nested_array_pointer, flattened_array_pointer); self.memory_op( nested_array_pointer, - source_index, + source_index.address, nested_array_pointer, acvm::brillig_vm::brillig::BinaryIntOp::Add, ); @@ -253,8 +253,8 @@ impl BrilligContext { BrilligParameter::Slice(..) => unreachable!("ICE: Cannot deflatten slices"), } - self.deallocate_register(source_index); - self.deallocate_register(target_index); + self.deallocate_single_addr(source_index); + self.deallocate_single_addr(target_index); } } @@ -323,11 +323,11 @@ impl BrilligContext { self.flatten_array( item_type, *item_count, - pointer_to_return_data, + pointer_to_return_data.address, returned_pointer, ); - self.deallocate_register(pointer_to_return_data); + self.deallocate_single_addr(pointer_to_return_data); return_data_index += BrilligContext::flattened_size(return_param); } BrilligParameter::Slice(..) => { @@ -412,7 +412,7 @@ impl BrilligContext { self.memory_op( flattened_nested_array_pointer, - target_index, + target_index.address, flattened_nested_array_pointer, acvm::brillig_vm::brillig::BinaryIntOp::Add, ); @@ -436,8 +436,8 @@ impl BrilligContext { BrilligParameter::Slice(..) => unreachable!("ICE: Cannot flatten slices"), } - self.deallocate_register(source_index); - self.deallocate_register(target_index); + self.deallocate_single_addr(source_index); + self.deallocate_single_addr(target_index); } } @@ -449,7 +449,7 @@ impl BrilligContext { flattened_array_pointer, item_count, ); - self.deallocate_register(item_count); + self.deallocate_single_addr(item_count); } } } diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs index cbaeb2477d6..e785212f8d2 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs @@ -92,7 +92,7 @@ impl FunctionBuilder { let index = self .current_function .dfg - .make_constant(FieldElement::from(i as i128), Type::field()); + .make_constant(FieldElement::from(i as i128), Type::length_type()); let element = self.insert_array_get(value, index, typ[0].clone()); self.add_to_data_bus(element, databus); }