diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 240370d5e58..7b6ac3ee1eb 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -58,6 +58,16 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_terminator(terminator_instruction, dfg); } + 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(), + }, + _ => unreachable!("ICE bitwise not on a non numeric type"), + } + } + /// Creates a unique global label for a block. /// /// This uses the current functions's function ID and the block ID @@ -175,18 +185,13 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.mov_instruction(target_register, source_register); } Instruction::Not(value) => { - assert_eq!( - dfg.type_of_value(*value), - Type::bool(), - "not operator can only be applied to boolean values" - ); let condition = self.convert_ssa_value(*value, dfg); let result_ids = dfg.instruction_results(instruction_id); let result_register = self .function_context .get_or_create_register(self.brillig_context, result_ids[0]); - - self.brillig_context.not_instruction(condition, result_register); + let bit_size = Self::get_bit_size_from_ssa_type(dfg.type_of_value(*value)); + self.brillig_context.not_instruction(condition, bit_size, result_register); } Instruction::Call { func, arguments } => match &dfg[*func] { Value::ForeignFunction(func_name) => { diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir.rs b/crates/noirc_evaluator/src/brillig/brillig_ir.rs index 3c230445475..2d28a27f69b 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_ir.rs @@ -208,7 +208,7 @@ impl BrilligContext { let exit_loop_label = self.next_section_label(); - self.not_instruction(index_less_than_array_len, index_less_than_array_len); + self.not_instruction(index_less_than_array_len, 1, index_less_than_array_len); self.jump_if_instruction(index_less_than_array_len, exit_loop_label); // Copy the element from source to destination @@ -419,19 +419,26 @@ 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, condition: RegisterIndex, result: RegisterIndex) { - debug_show::not_instruction(condition, result); - let one = self.make_constant(Value::from(FieldElement::one())); - - // Compile !x as (1 - x) + pub(crate) fn not_instruction( + &mut self, + input: RegisterIndex, + bit_size: u32, + result: RegisterIndex, + ) { + debug_show::not_instruction(input, bit_size, result); + // Compile !x as ((-1) - x) + let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128)) + - FieldElement::one(); + let max = self.make_constant(Value::from(u_max)); let opcode = BrilligOpcode::BinaryIntOp { destination: result, op: BinaryIntOp::Sub, - bit_size: 1, - lhs: one, - rhs: condition, + bit_size, + lhs: max, + rhs: input, }; self.push_opcode(opcode); + self.deallocate_register(max); } /// Processes a foreign call instruction. diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 388b1f6222a..457de2264d3 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -171,8 +171,8 @@ pub(crate) fn const_instruction(result: RegisterIndex, constant: Value) { } /// Processes a not instruction. Append with "_" as this is a high-level instruction. -pub(crate) fn not_instruction(condition: RegisterIndex, result: RegisterIndex) { - debug_println!(" _NOT {} = !{}", result, condition); +pub(crate) fn not_instruction(condition: RegisterIndex, bit_size: u32, result: RegisterIndex) { + debug_println!(" i{}_NOT {} = !{}", bit_size, result, condition); } /// Processes a foreign call instruction.