diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index dfe23b45034b..c8ac2eb0ff8e 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -61,7 +61,7 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func); - message_vector.size = *array_size; + message_vector.size = array_size.address; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { message: message_vector.to_heap_vector(), @@ -98,7 +98,7 @@ pub(crate) fn convert_black_box_call( public_key_x: public_key_x.to_heap_array(), public_key_y: public_key_y.to_heap_array(), signature: signature.to_heap_array(), - result: *result_register, + result: result_register.address, }); } else { unreachable!( @@ -119,7 +119,7 @@ pub(crate) fn convert_black_box_call( public_key_x: public_key_x.to_heap_array(), public_key_y: public_key_y.to_heap_array(), signature: signature.to_heap_array(), - result: *result_register, + result: result_register.address, }); } else { unreachable!( @@ -137,7 +137,7 @@ pub(crate) fn convert_black_box_call( let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { inputs: message_vector.to_heap_vector(), - domain_separator: *domain_separator, + domain_separator: domain_separator.address, output: result_array.to_heap_array(), }); } else { @@ -153,8 +153,8 @@ pub(crate) fn convert_black_box_call( let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { inputs: message_vector.to_heap_vector(), - domain_separator: *domain_separator, - output: *result, + domain_separator: domain_separator.address, + output: result.address, }); } else { unreachable!("ICE: Pedersen hash expects one array argument, a register for the domain separator, and one register result") @@ -169,11 +169,11 @@ pub(crate) fn convert_black_box_call( let message_hash = convert_array_or_vector(brillig_context, message, bb_func); let signature = brillig_context.array_to_vector(signature); brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { - public_key_x: *public_key_x, - public_key_y: *public_key_y, + public_key_x: public_key_x.address, + public_key_y: public_key_y.address, message: message_hash.to_heap_vector(), signature: signature.to_heap_vector(), - result: *result_register, + result: result_register.address, }); } else { unreachable!("ICE: Schnorr verify expects two registers for the public key, an array for signature, an array for the message hash and one result register") @@ -186,8 +186,8 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::FixedBaseScalarMul { - low: *low, - high: *high, + low: low.address, + high: high.address, result: result_array.to_heap_array(), }); } else { @@ -203,10 +203,10 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::EmbeddedCurveAdd { - input1_x: *input1_x, - input1_y: *input1_y, - input2_x: *input2_x, - input2_y: *input2_y, + input1_x: input1_x.address, + input1_y: input1_y.address, + input2_x: input2_x.address, + input2_y: input2_y.address, result: result_array.to_heap_array(), }); } else { @@ -234,9 +234,9 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::BigIntAdd { - lhs: *lhs, - rhs: *rhs, - output: *output, + lhs: lhs.address, + rhs: rhs.address, + output: output.address, }); } else { unreachable!( @@ -251,9 +251,9 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::BigIntSub { - lhs: *lhs, - rhs: *rhs, - output: *output, + lhs: lhs.address, + rhs: rhs.address, + output: output.address, }); } else { unreachable!( @@ -268,9 +268,9 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::BigIntMul { - lhs: *lhs, - rhs: *rhs, - output: *output, + lhs: lhs.address, + rhs: rhs.address, + output: output.address, }); } else { unreachable!( @@ -285,9 +285,9 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::BigIntDiv { - lhs: *lhs, - rhs: *rhs, - output: *output, + lhs: lhs.address, + rhs: rhs.address, + output: output.address, }); } else { unreachable!( @@ -304,7 +304,7 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::BigIntFromLeBytes { inputs: inputs_vector.to_heap_vector(), modulus: modulus_vector.to_heap_vector(), - output: *output, + output: output.address, }); } else { unreachable!( @@ -319,7 +319,7 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::BigIntToLeBytes { - input: *input, + input: input.address, output: result_vector.to_heap_vector(), }); } else { @@ -338,7 +338,7 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::Poseidon2Permutation { message: message_vector.to_heap_vector(), output: result_array.to_heap_array(), - len: *state_len, + len: state_len.address, }); } else { unreachable!("ICE: Poseidon2Permutation expects one array argument, a length and one array result") diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 84b719f29aa7..af292a764fab 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,5 +1,5 @@ use crate::brillig::brillig_ir::brillig_variable::{ - type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, SimpleVariable, }; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, @@ -117,9 +117,9 @@ impl<'block> BrilligBlock<'block> { ) { match terminator_instruction { TerminatorInstruction::JmpIf { condition, then_destination, else_destination } => { - let condition = self.convert_ssa_register_value(*condition, dfg); + let condition = self.convert_ssa_simple_value(*condition, dfg); self.brillig_context.jump_if_instruction( - condition, + condition.address, self.create_block_label_for_current_function(*then_destination), ); self.brillig_context.jump_instruction( @@ -163,11 +163,8 @@ impl<'block> BrilligBlock<'block> { /// Passes an arbitrary variable from the registers of the source to the registers of the destination fn pass_variable(&mut self, source: BrilligVariable, destination: BrilligVariable) { match (source, destination) { - ( - BrilligVariable::Simple(source_register), - BrilligVariable::Simple(destination_register), - ) => { - self.brillig_context.mov_instruction(destination_register, source_register); + (BrilligVariable::Simple(source_var), BrilligVariable::Simple(destination_var)) => { + self.brillig_context.mov_instruction(destination_var.address, source_var.address); } ( BrilligVariable::BrilligArray(BrilligArray { @@ -241,16 +238,19 @@ impl<'block> BrilligBlock<'block> { match instruction { Instruction::Binary(binary) => { - let result_register = self.variables.define_register_variable( + let result_var = self.variables.define_simple_variable( self.function_context, self.brillig_context, dfg.instruction_results(instruction_id)[0], dfg, ); - self.convert_ssa_binary(binary, dfg, result_register); + self.convert_ssa_binary(binary, dfg, result_var); } Instruction::Constrain(lhs, rhs, assert_message) => { - let condition = self.brillig_context.allocate_register(); + let condition = SimpleVariable { + address: self.brillig_context.allocate_register(), + bit_size: 1, + }; self.convert_ssa_binary( &Binary { lhs: *lhs, rhs: *rhs, operator: BinaryOp::Eq }, @@ -281,12 +281,12 @@ impl<'block> BrilligBlock<'block> { None }; - self.brillig_context.constrain_instruction(condition, assert_message); - self.brillig_context.deallocate_register(condition); + self.brillig_context.constrain_instruction(condition.address, assert_message); + self.brillig_context.deallocate_register(condition.address); } Instruction::Allocate => { let result_value = dfg.instruction_results(instruction_id)[0]; - let address_register = self.variables.define_register_variable( + let address_register = self.variables.define_simple_variable( self.function_context, self.brillig_context, result_value, @@ -296,15 +296,15 @@ impl<'block> BrilligBlock<'block> { Type::Reference(element) => match *element { Type::Array(..) => { self.brillig_context - .allocate_array_reference_instruction(address_register); + .allocate_array_reference_instruction(address_register.address); } Type::Slice(..) => { self.brillig_context - .allocate_vector_reference_instruction(address_register); + .allocate_vector_reference_instruction(address_register.address); } _ => { self.brillig_context - .allocate_simple_reference_instruction(address_register); + .allocate_simple_reference_instruction(address_register.address); } }, _ => { @@ -313,10 +313,11 @@ impl<'block> BrilligBlock<'block> { } } Instruction::Store { address, value } => { - let address_register = self.convert_ssa_register_value(*address, dfg); + let address_var = self.convert_ssa_simple_value(*address, dfg); let source_variable = self.convert_ssa_value(*value, dfg); - self.brillig_context.store_variable_instruction(address_register, source_variable); + self.brillig_context + .store_variable_instruction(address_var.address, source_variable); } Instruction::Load { address } => { let target_variable = self.variables.define_variable( @@ -326,20 +327,20 @@ impl<'block> BrilligBlock<'block> { dfg, ); - let address_register = self.convert_ssa_register_value(*address, dfg); + let address_variable = self.convert_ssa_simple_value(*address, dfg); - self.brillig_context.load_variable_instruction(target_variable, address_register); + self.brillig_context + .load_variable_instruction(target_variable, address_variable.address); } Instruction::Not(value) => { - let condition_register = self.convert_ssa_register_value(*value, dfg); - let result_register = self.variables.define_register_variable( + let condition_register = self.convert_ssa_simple_value(*value, dfg); + let result_register = self.variables.define_simple_variable( self.function_context, self.brillig_context, dfg.instruction_results(instruction_id)[0], dfg, ); - let bit_size = get_bit_size_from_ssa_type(&dfg.type_of_value(*value)); - self.brillig_context.not_instruction(condition_register, bit_size, result_register); + self.brillig_context.not_instruction(condition_register, result_register); } Instruction::Call { func, arguments } => match &dfg[*func] { Value::ForeignFunction(func_name) => { @@ -431,7 +432,7 @@ impl<'block> BrilligBlock<'block> { ); } Value::Intrinsic(Intrinsic::ArrayLen) => { - let result_register = self.variables.define_register_variable( + let result_variable = self.variables.define_simple_variable( self.function_context, self.brillig_context, dfg.instruction_results(instruction_id)[0], @@ -443,10 +444,11 @@ impl<'block> BrilligBlock<'block> { // or an array in the case of an array. if let Type::Numeric(_) = dfg.type_of_value(param_id) { let len_variable = self.convert_ssa_value(arguments[0], dfg); - let len_register_index = len_variable.extract_register(); - self.brillig_context.mov_instruction(result_register, len_register_index); + let length = len_variable.extract_simple(); + self.brillig_context + .mov_instruction(result_variable.address, length.address); } else { - self.convert_ssa_array_len(arguments[0], result_register, dfg); + self.convert_ssa_array_len(arguments[0], result_variable.address, dfg); } } Value::Intrinsic( @@ -465,13 +467,13 @@ impl<'block> BrilligBlock<'block> { ); } Value::Intrinsic(Intrinsic::ToRadix(endianness)) => { - let source = self.convert_ssa_register_value(arguments[0], dfg); - let radix = self.convert_ssa_register_value(arguments[1], dfg); - let limb_count = self.convert_ssa_register_value(arguments[2], dfg); + let source = self.convert_ssa_simple_value(arguments[0], dfg); + let radix = self.convert_ssa_simple_value(arguments[1], dfg); + let limb_count = self.convert_ssa_simple_value(arguments[2], dfg); let results = dfg.instruction_results(instruction_id); - let target_len = self.variables.define_register_variable( + let target_len = self.variables.define_simple_variable( self.function_context, self.brillig_context, results[0], @@ -489,19 +491,19 @@ impl<'block> BrilligBlock<'block> { .extract_vector(); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len, limb_count); + self.brillig_context.mov_instruction(target_len.address, limb_count.address); self.brillig_context.radix_instruction( - source, + source.address, target_vector, - radix, - limb_count, + radix.address, + limb_count.address, matches!(endianness, Endian::Big), ); } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { - let source = self.convert_ssa_register_value(arguments[0], dfg); - let limb_count = self.convert_ssa_register_value(arguments[1], dfg); + let source = self.convert_ssa_simple_value(arguments[0], dfg); + let limb_count = self.convert_ssa_simple_value(arguments[1], dfg); let results = dfg.instruction_results(instruction_id); @@ -511,7 +513,7 @@ impl<'block> BrilligBlock<'block> { results[0], dfg, ); - let target_len = target_len_variable.extract_register(); + let target_len = target_len_variable.extract_simple(); let target_vector = match self.variables.define_variable( self.function_context, @@ -531,13 +533,13 @@ impl<'block> BrilligBlock<'block> { .make_constant(2_usize.into(), FieldElement::max_num_bits()); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len, limb_count); + self.brillig_context.mov_instruction(target_len.address, limb_count.address); self.brillig_context.radix_instruction( - source, + source.address, target_vector, radix, - limb_count, + limb_count.address, matches!(endianness, Endian::Big), ); @@ -549,29 +551,29 @@ impl<'block> BrilligBlock<'block> { }, Instruction::Truncate { value, bit_size, .. } => { let result_ids = dfg.instruction_results(instruction_id); - let destination_register = self.variables.define_register_variable( + let destination_register = self.variables.define_simple_variable( self.function_context, self.brillig_context, result_ids[0], dfg, ); - let source_register = self.convert_ssa_register_value(*value, dfg); + let source_register = self.convert_ssa_simple_value(*value, dfg); self.brillig_context.truncate_instruction( destination_register, source_register, *bit_size, ); } - Instruction::Cast(value, typ) => { + Instruction::Cast(value, _) => { let result_ids = dfg.instruction_results(instruction_id); - let destination_register = self.variables.define_register_variable( + let destination_variable = self.variables.define_simple_variable( self.function_context, self.brillig_context, result_ids[0], dfg, ); - let source_register = self.convert_ssa_register_value(*value, dfg); - self.convert_cast(destination_register, source_register, typ); + let source_variable = self.convert_ssa_simple_value(*value, dfg); + self.convert_cast(destination_variable, source_variable); } Instruction::ArrayGet { array, index } => { let result_ids = dfg.instruction_results(instruction_id); @@ -589,17 +591,17 @@ impl<'block> BrilligBlock<'block> { _ => unreachable!("ICE: array get on non-array"), }; - let index_register = self.convert_ssa_register_value(*index, dfg); - self.validate_array_index(array_variable, index_register); + let index_variable = self.convert_ssa_simple_value(*index, dfg); + self.validate_array_index(array_variable, index_variable); self.retrieve_variable_from_array( array_pointer, - index_register, + index_variable.address, destination_variable, ); } Instruction::ArraySet { array, index, value, .. } => { let source_variable = self.convert_ssa_value(*array, dfg); - let index_register = self.convert_ssa_register_value(*index, dfg); + let index_register = self.convert_ssa_simple_value(*index, dfg); let value_variable = self.convert_ssa_value(*value, dfg); let result_ids = dfg.instruction_results(instruction_id); @@ -614,28 +616,42 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_array_set( source_variable, destination_variable, - index_register, + index_register.address, value_variable, ); } Instruction::RangeCheck { value, max_bit_size, assert_message } => { - let left = self.convert_ssa_register_value(*value, dfg); - let max = BigUint::from(2_u128).pow(*max_bit_size); - let right = self.brillig_context.allocate_register(); - self.brillig_context.const_instruction( - right, + let value = self.convert_ssa_simple_value(*value, dfg); + // Cast original value to field + let left = SimpleVariable { + address: self.brillig_context.allocate_register(), + bit_size: FieldElement::max_num_bits(), + }; + self.convert_cast(left, value); + + // Create a field constant with the max + let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); + let right = self.brillig_context.make_constant( FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), FieldElement::max_num_bits(), ); + // Check if lte max let brillig_binary_op = BrilligBinaryOp::Integer { - op: BinaryIntOp::LessThan, - bit_size: max_bit_size + 1, + op: BinaryIntOp::LessThanEquals, + bit_size: FieldElement::max_num_bits(), }; let condition = self.brillig_context.allocate_register(); - self.brillig_context.binary_instruction(left, right, condition, brillig_binary_op); + self.brillig_context.binary_instruction( + left.address, + 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); } Instruction::IncrementRc { value } => { @@ -724,7 +740,7 @@ impl<'block> BrilligBlock<'block> { fn validate_array_index( &mut self, array_variable: BrilligVariable, - index_register: MemoryAddress, + index_register: SimpleVariable, ) { let (size_as_register, should_deallocate_size) = match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { @@ -737,7 +753,7 @@ impl<'block> BrilligBlock<'block> { let condition = self.brillig_context.allocate_register(); self.brillig_context.memory_op( - index_register, + index_register.address, size_as_register, condition, BinaryIntOp::LessThan, @@ -760,7 +776,11 @@ impl<'block> BrilligBlock<'block> { ) { match destination_variable { BrilligVariable::Simple(destination_register) => { - self.brillig_context.array_get(array_pointer, index_register, destination_register); + self.brillig_context.array_get( + array_pointer, + index_register, + destination_register.address, + ); } BrilligVariable::BrilligArray(..) | BrilligVariable::BrilligVector(..) => { let reference = self.brillig_context.allocate_register(); @@ -862,8 +882,8 @@ impl<'block> BrilligBlock<'block> { value_variable: BrilligVariable, ) { match value_variable { - BrilligVariable::Simple(value_register) => { - ctx.array_set(destination_pointer, index_register, value_register); + BrilligVariable::Simple(value_variable) => { + ctx.array_set(destination_pointer, index_register, value_variable.address); } BrilligVariable::BrilligArray(_) => { let reference: MemoryAddress = ctx.allocate_register(); @@ -934,7 +954,7 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Add); + self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); self.slice_push_back_operation(target_vector, source_vector, &item_values); } @@ -960,7 +980,7 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Add); + self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); self.slice_push_front_operation(target_vector, source_vector, &item_values); } @@ -993,7 +1013,7 @@ impl<'block> BrilligBlock<'block> { ) }); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); self.slice_pop_back_operation(target_vector, source_vector, &pop_variables); } @@ -1025,7 +1045,7 @@ impl<'block> BrilligBlock<'block> { ); let target_vector = target_variable.extract_vector(); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); self.slice_pop_front_operation(target_vector, source_vector, &pop_variables); } @@ -1052,13 +1072,13 @@ impl<'block> BrilligBlock<'block> { // Remove if indexing in insert is changed to flattened indexing // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 - let user_index = self.convert_ssa_register_value(arguments[2], dfg); + let user_index = self.convert_ssa_simple_value(arguments[2], dfg); let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, - user_index, + user_index.address, converted_index, BinaryIntOp::Mul, ); @@ -1067,7 +1087,7 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Add); + 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); @@ -1095,12 +1115,12 @@ impl<'block> BrilligBlock<'block> { // Remove if indexing in remove is changed to flattened indexing // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 - let user_index = self.convert_ssa_register_value(arguments[2], dfg); + let user_index = self.convert_ssa_simple_value(arguments[2], dfg); let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, - user_index, + user_index.address, converted_index, BinaryIntOp::Mul, ); @@ -1114,7 +1134,7 @@ impl<'block> BrilligBlock<'block> { ) }); - self.update_slice_length(target_len, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); self.slice_remove_operation( target_vector, @@ -1146,18 +1166,18 @@ impl<'block> BrilligBlock<'block> { binary_op: BinaryIntOp, ) { let source_len_variable = self.convert_ssa_value(source_value, dfg); - let source_len = source_len_variable.extract_register(); + let source_len = source_len_variable.extract_simple(); - self.brillig_context.usize_op(source_len, target_len, binary_op, 1); + self.brillig_context.usize_op(source_len.address, target_len, binary_op, 1); } /// Converts an SSA cast to a sequence of Brillig opcodes. /// Casting is only necessary when shrinking the bit size of a numeric value. - fn convert_cast(&mut self, destination: MemoryAddress, source: MemoryAddress, typ: &Type) { + fn convert_cast(&mut self, destination: SimpleVariable, source: SimpleVariable) { // We assume that `source` is a valid `target_type` as it's expected that a truncate instruction was emitted // to ensure this is the case. - self.brillig_context.cast_instruction(destination, source, get_bit_size_from_ssa_type(typ)); + self.brillig_context.cast_instruction(destination, source); } /// Converts the Binary instruction into a sequence of Brillig opcodes. @@ -1165,18 +1185,23 @@ impl<'block> BrilligBlock<'block> { &mut self, binary: &Binary, dfg: &DataFlowGraph, - result_register: MemoryAddress, + result_variable: SimpleVariable, ) { let binary_type = type_of_binary_operation(dfg[binary.lhs].get_type(), dfg[binary.rhs].get_type()); - let left = self.convert_ssa_register_value(binary.lhs, dfg); - let right = self.convert_ssa_register_value(binary.rhs, dfg); + let left = self.convert_ssa_simple_value(binary.lhs, dfg); + let right = self.convert_ssa_simple_value(binary.rhs, dfg); let brillig_binary_op = convert_ssa_binary_op_to_brillig_binary_op(binary.operator, &binary_type); - self.brillig_context.binary_instruction(left, right, result_register, brillig_binary_op); + self.brillig_context.binary_instruction( + left.address, + right.address, + result_variable.address, + brillig_binary_op, + ); } /// Converts an SSA `ValueId` into a `RegisterOrMemory`. Initializes if necessary. @@ -1198,10 +1223,10 @@ impl<'block> BrilligBlock<'block> { } else { let new_variable = self.variables.allocate_constant(self.brillig_context, value_id, dfg); - let register_index = new_variable.extract_register(); + let register_index = new_variable.extract_simple(); self.brillig_context.const_instruction( - register_index, + register_index.address, (*constant).into(), get_bit_size_from_ssa_type(typ), ); @@ -1267,10 +1292,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_register(); + let register_index = new_variable.extract_simple(); self.brillig_context.const_instruction( - register_index, + register_index.address, value_id.to_usize().into(), 32, ); @@ -1283,13 +1308,13 @@ impl<'block> BrilligBlock<'block> { } /// Converts an SSA `ValueId` into a `MemoryAddress`. Initializes if necessary. - fn convert_ssa_register_value( + fn convert_ssa_simple_value( &mut self, value_id: ValueId, dfg: &DataFlowGraph, - ) -> MemoryAddress { + ) -> SimpleVariable { let variable = self.convert_ssa_value(value_id, dfg); - variable.extract_register() + variable.extract_simple() } fn allocate_external_call_result( diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index b4c96de1969e..95fc17c75c51 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -1,10 +1,9 @@ -use acvm::brillig_vm::brillig::MemoryAddress; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ brillig::brillig_ir::{ - brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}, - BrilligContext, + brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SimpleVariable}, + BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }, ssa::ir::{ basic_block::BasicBlockId, @@ -71,15 +70,15 @@ impl BlockVariables { } /// Defines a variable that fits in a single register and returns the allocated register. - pub(crate) fn define_register_variable( + pub(crate) fn define_simple_variable( &mut self, function_context: &mut FunctionContext, brillig_context: &mut BrilligContext, value: ValueId, dfg: &DataFlowGraph, - ) -> MemoryAddress { + ) -> SimpleVariable { let variable = self.define_variable(function_context, brillig_context, value, dfg); - variable.extract_register() + variable.extract_simple() } /// Removes a variable so it's not used anymore within this block. @@ -190,12 +189,22 @@ pub(crate) fn allocate_value( let typ = dfg.type_of_value(value_id); match typ { - Type::Numeric(_) | Type::Reference(_) | Type::Function => { + Type::Numeric(numeric_type) => BrilligVariable::Simple(SimpleVariable { + address: brillig_context.allocate_register(), + bit_size: numeric_type.bit_size(), + }), + Type::Reference(_) => BrilligVariable::Simple(SimpleVariable { + 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) - let register = brillig_context.allocate_register(); - BrilligVariable::Simple(register) + BrilligVariable::Simple(SimpleVariable { + address: brillig_context.allocate_register(), + bit_size: 32, + }) } Type::Array(item_typ, elem_count) => { let pointer_register = brillig_context.allocate_register(); diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 933396be0cb9..202eda7f275b 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -334,7 +334,7 @@ mod tests { use crate::brillig::brillig_gen::brillig_fn::FunctionContext; use crate::brillig::brillig_ir::artifact::BrilligParameter; use crate::brillig::brillig_ir::brillig_variable::{ - BrilligArray, BrilligVariable, BrilligVector, + BrilligArray, BrilligVariable, BrilligVector, SimpleVariable, }; use crate::brillig::brillig_ir::tests::{ create_and_run_vm, create_context, create_entry_point_bytecode, @@ -397,7 +397,10 @@ mod tests { size: array.len(), rc: context.allocate_register(), }; - let item_to_insert = context.allocate_register(); + let item_to_insert = SimpleVariable { + address: context.allocate_register(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }; // Cast the source array to a vector let source_vector = context.array_to_vector(&array_variable); @@ -501,7 +504,10 @@ mod tests { size: context.allocate_register(), rc: context.allocate_register(), }; - let removed_item = context.allocate_register(); + let removed_item = SimpleVariable { + address: context.allocate_register(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }; let mut block = create_brillig_block(&mut function_context, &mut context); @@ -519,7 +525,11 @@ mod tests { ); } - context.return_instruction(&[target_vector.pointer, target_vector.rc, removed_item]); + context.return_instruction(&[ + target_vector.pointer, + target_vector.rc, + removed_item.address, + ]); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; let expected_return: Vec<_> = @@ -578,7 +588,10 @@ mod tests { size: array.len(), rc: context.allocate_register(), }; - let item_to_insert = context.allocate_register(); + let item_to_insert = SimpleVariable { + address: context.allocate_register(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }; let index_to_insert = context.allocate_register(); // Cast the source array to a vector @@ -708,7 +721,10 @@ mod tests { size: context.allocate_register(), rc: context.allocate_register(), }; - let removed_item = context.allocate_register(); + let removed_item = SimpleVariable { + address: context.allocate_register(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }; let mut block = create_brillig_block(&mut function_context, &mut context); @@ -719,7 +735,11 @@ mod tests { &[BrilligVariable::Simple(removed_item)], ); - context.return_instruction(&[target_vector.pointer, target_vector.size, removed_item]); + context.return_instruction(&[ + target_vector.pointer, + target_vector.size, + removed_item.address, + ]); let calldata: Vec<_> = array.into_iter().chain(vec![index]).collect(); diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 8bbde88c89ed..20d2697f9211 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -15,7 +15,7 @@ use crate::ssa::ir::dfg::CallStack; use self::{ artifact::{BrilligArtifact, UnresolvedJumpLocation}, - brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}, + brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SimpleVariable}, registers::BrilligRegistersContext, }; use acvm::{ @@ -27,6 +27,7 @@ use acvm::{ FieldElement, }; use debug_show::DebugShow; +use num_bigint::BigUint; /// Integer arithmetic in Brillig is limited to 127 bit /// integers. @@ -295,18 +296,21 @@ impl BrilligContext { // Loop body // Check if iterator < iteration_count - let iterator_less_than_iterations = self.allocate_register(); + let iterator_less_than_iterations = + SimpleVariable { address: self.allocate_register(), bit_size: 1 }; + self.memory_op( iterator_register, iteration_count, - iterator_less_than_iterations, + iterator_less_than_iterations.address, BinaryIntOp::LessThan, ); let (exit_loop_section, exit_loop_label) = self.reserve_next_section_label(); - self.not_instruction(iterator_less_than_iterations, 1, iterator_less_than_iterations); - self.jump_if_instruction(iterator_less_than_iterations, exit_loop_label); + self.not_instruction(iterator_less_than_iterations, iterator_less_than_iterations); + + self.jump_if_instruction(iterator_less_than_iterations.address, exit_loop_label); // Call the on iteration function on_iteration(self, iterator_register); @@ -320,7 +324,7 @@ impl BrilligContext { self.enter_section(exit_loop_section); // Deallocate our temporary registers - self.deallocate_register(iterator_less_than_iterations); + self.deallocate_register(iterator_less_than_iterations.address); self.deallocate_register(iterator_register); } @@ -505,14 +509,13 @@ impl BrilligContext { } /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. - pub(crate) fn cast_instruction( - &mut self, - destination: MemoryAddress, - source: MemoryAddress, - bit_size: u32, - ) { - self.debug_show.cast_instruction(destination, source, bit_size); - self.push_opcode(BrilligOpcode::Cast { destination, source, bit_size }); + pub(crate) fn cast_instruction(&mut self, destination: SimpleVariable, source: SimpleVariable) { + self.debug_show.cast_instruction(destination.address, source.address, destination.bit_size); + self.push_opcode(BrilligOpcode::Cast { + destination: destination.address, + source: source.address, + bit_size: destination.bit_size, + }); } /// Processes a binary instruction according `operation`. @@ -562,23 +565,18 @@ impl BrilligContext { /// /// Not is computed using a subtraction operation as there is no native not instruction /// in Brillig. - pub(crate) fn not_instruction( - &mut self, - input: MemoryAddress, - bit_size: u32, - result: MemoryAddress, - ) { - self.debug_show.not_instruction(input, bit_size, result); + pub(crate) fn not_instruction(&mut self, input: SimpleVariable, result: SimpleVariable) { + self.debug_show.not_instruction(input.address, input.bit_size, result.address); // Compile !x as ((-1) - x) - let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128)) + 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), bit_size); + let max = self.make_constant(Value::from(u_max), input.bit_size); let opcode = BrilligOpcode::BinaryIntOp { - destination: result, + destination: result.address, op: BinaryIntOp::Sub, - bit_size, + bit_size: input.bit_size, lhs: max, - rhs: input, + rhs: input.address, }; self.push_opcode(opcode); self.deallocate_register(max); @@ -626,8 +624,8 @@ impl BrilligContext { variable_pointer: MemoryAddress, ) { match destination { - BrilligVariable::Simple(register_index) => { - self.load_instruction(register_index, variable_pointer); + BrilligVariable::Simple(simple) => { + self.load_instruction(simple.address, variable_pointer); } BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { self.load_instruction(pointer, variable_pointer); @@ -676,8 +674,8 @@ impl BrilligContext { source: BrilligVariable, ) { match source { - BrilligVariable::Simple(register_index) => { - self.store_instruction(variable_pointer, register_index); + BrilligVariable::Simple(simple) => { + self.store_instruction(variable_pointer, simple.address); } BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { self.store_instruction(variable_pointer, pointer); @@ -717,31 +715,36 @@ impl BrilligContext { /// For Brillig, all integer operations will overflow as its cheap. pub(crate) fn truncate_instruction( &mut self, - destination_of_truncated_value: MemoryAddress, - value_to_truncate: MemoryAddress, + destination_of_truncated_value: SimpleVariable, + value_to_truncate: SimpleVariable, bit_size: u32, ) { self.debug_show.truncate_instruction( - destination_of_truncated_value, - value_to_truncate, + destination_of_truncated_value.address, + value_to_truncate.address, bit_size, ); assert!( - bit_size <= BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, - "tried to truncate to a bit size greater than allowed {bit_size}" + bit_size <= value_to_truncate.bit_size, + "tried to truncate to a bit size {} greater than the variable size {}", + bit_size, + value_to_truncate.bit_size + ); + + let mask = BigUint::from(2_u32).pow(bit_size) - BigUint::from(1_u32); + let mask_constant = self.make_constant( + FieldElement::from_be_bytes_reduce(&mask.to_bytes_be()).into(), + value_to_truncate.bit_size, ); - // The brillig VM performs all arithmetic operations modulo 2**bit_size - // So to truncate any value to a target bit size we can just issue a no-op arithmetic operation - // With bit size equal to target_bit_size - let zero_register = self.make_constant(Value::from(FieldElement::zero()), bit_size); self.binary_instruction( - value_to_truncate, - zero_register, - destination_of_truncated_value, - BrilligBinaryOp::Integer { op: BinaryIntOp::Add, bit_size }, + value_to_truncate.address, + mask_constant, + destination_of_truncated_value.address, + BrilligBinaryOp::Integer { op: BinaryIntOp::And, bit_size: value_to_truncate.bit_size }, ); - self.deallocate_register(zero_register); + + self.deallocate_register(mask_constant); } /// Emits a stop instruction diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 856fb709fa9c..e11f296f467e 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -5,6 +5,12 @@ use serde::{Deserialize, Serialize}; use crate::ssa::ir::types::Type; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +pub(crate) struct SimpleVariable { + pub(crate) address: MemoryAddress, + pub(crate) bit_size: u32, +} + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { @@ -52,15 +58,15 @@ impl BrilligVector { /// The representation of a noir value in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) enum BrilligVariable { - Simple(MemoryAddress), + Simple(SimpleVariable), BrilligArray(BrilligArray), BrilligVector(BrilligVector), } impl BrilligVariable { - pub(crate) fn extract_register(self) -> MemoryAddress { + pub(crate) fn extract_simple(self) -> SimpleVariable { match self { - BrilligVariable::Simple(register_index) => register_index, + BrilligVariable::Simple(simple) => simple, _ => unreachable!("ICE: Expected register, got {self:?}"), } } @@ -81,7 +87,7 @@ impl BrilligVariable { pub(crate) fn extract_registers(self) -> Vec { match self { - BrilligVariable::Simple(register_index) => vec![register_index], + BrilligVariable::Simple(simple) => vec![simple.address], BrilligVariable::BrilligArray(array) => array.extract_registers(), BrilligVariable::BrilligVector(vector) => vector.extract_registers(), } @@ -89,7 +95,7 @@ impl BrilligVariable { pub(crate) fn to_register_or_memory(self) -> ValueOrArray { match self { - BrilligVariable::Simple(register_index) => ValueOrArray::MemoryAddress(register_index), + BrilligVariable::Simple(simple) => ValueOrArray::MemoryAddress(simple.address), BrilligVariable::BrilligArray(array) => ValueOrArray::HeapArray(array.to_heap_array()), BrilligVariable::BrilligVector(vector) => { ValueOrArray::HeapVector(vector.to_heap_vector()) diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 0eb4c8c31bd2..4e750e7407de 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -1,6 +1,6 @@ use super::{ artifact::{BrilligArtifact, BrilligParameter}, - brillig_variable::{BrilligArray, BrilligVariable}, + brillig_variable::{BrilligArray, BrilligVariable, SimpleVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, @@ -63,9 +63,12 @@ impl BrilligContext { let mut argument_variables: Vec<_> = arguments .iter() .map(|argument| match argument { - BrilligParameter::Simple(_) => { + BrilligParameter::Simple(bit_size) => { let simple_address = self.allocate_register(); - let var = BrilligVariable::Simple(simple_address); + let var = BrilligVariable::Simple(SimpleVariable { + address: simple_address, + bit_size: *bit_size, + }); self.mov_instruction(simple_address, MemoryAddress(current_calldata_pointer)); current_calldata_pointer += 1; var @@ -279,7 +282,10 @@ impl BrilligContext { let returned_variables: Vec<_> = return_parameters .iter() .map(|return_parameter| match return_parameter { - BrilligParameter::Simple(_) => BrilligVariable::Simple(self.allocate_register()), + BrilligParameter::Simple(bit_size) => BrilligVariable::Simple(SimpleVariable { + address: self.allocate_register(), + bit_size: *bit_size, + }), BrilligParameter::Array(item_types, item_count) => { BrilligVariable::BrilligArray(BrilligArray { pointer: self.allocate_register(), @@ -304,7 +310,7 @@ impl BrilligContext { BrilligParameter::Simple(_) => { self.mov_instruction( MemoryAddress(return_data_index), - returned_variable.extract_register(), + returned_variable.extract_simple().address, ); return_data_index += 1; }