diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index 1c491f32c6a..6c339c9e21f 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -376,7 +376,10 @@ impl std::fmt::Display for Program { } for (func_index, function) in self.unconstrained_functions.iter().enumerate() { writeln!(f, "unconstrained func {func_index}")?; - writeln!(f, "{:?}", function.bytecode)?; + let width = function.bytecode.len().to_string().len(); + for (index, opcode) in function.bytecode.iter().enumerate() { + writeln!(f, "{index:>width$}: {opcode}")?; + } } Ok(()) } diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index a8b5c712bbf..3d9060b2229 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -76,3 +76,105 @@ pub enum BlackBoxOp { output_bits: MemoryAddress, }, } + +impl std::fmt::Display for BlackBoxOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BlackBoxOp::AES128Encrypt { inputs, iv, key, outputs } => { + write!( + f, + "aes_128_encrypt(inputs: {inputs}, iv: {iv}, key: {key}, outputs: {outputs})" + ) + } + BlackBoxOp::Blake2s { message, output } => { + write!(f, "blake2s(message: {message}, output: {output})") + } + BlackBoxOp::Blake3 { message, output } => { + write!(f, "blake3(message: {message}, output: {output})") + } + BlackBoxOp::Keccakf1600 { input, output } => { + write!(f, "keccakf1600(input: {input}, output: {output})") + } + BlackBoxOp::EcdsaSecp256k1 { + hashed_msg, + public_key_x, + public_key_y, + signature, + result, + } => { + write!( + f, + "ecdsa_secp256k1(hashed_msg: {hashed_msg}, public_key_x: {public_key_x}, public_key_y: {public_key_y}, signature: {signature}, result: {result})" + ) + } + BlackBoxOp::EcdsaSecp256r1 { + hashed_msg, + public_key_x, + public_key_y, + signature, + result, + } => { + write!( + f, + "ecdsa_secp256r1(hashed_msg: {hashed_msg}, public_key_x: {public_key_x}, public_key_y: {public_key_y}, signature: {signature}, result: {result})" + ) + } + BlackBoxOp::MultiScalarMul { points, scalars, outputs } => { + write!( + f, + "multi_scalar_mul(points: {points}, scalars: {scalars}, outputs: {outputs})" + ) + } + BlackBoxOp::EmbeddedCurveAdd { + input1_x, + input1_y, + input1_infinite, + input2_x, + input2_y, + input2_infinite, + result, + } => { + write!( + f, + "embedded_curve_add(input1_x: {input1_x}, input1_y: {input1_y}, input1_infinite: {input1_infinite}, input2_x: {input2_x}, input2_y: {input2_y}, input2_infinite: {input2_infinite}, result: {result})" + ) + } + BlackBoxOp::BigIntAdd { lhs, rhs, output } => { + write!(f, "big_int_add(lhs: {lhs}, rhs: {rhs}, output: {output})") + } + BlackBoxOp::BigIntSub { lhs, rhs, output } => { + write!(f, "big_int_sub(lhs: {lhs}, rhs: {rhs}, output: {output})") + } + BlackBoxOp::BigIntMul { lhs, rhs, output } => { + write!(f, "big_int_mul(lhs: {lhs}, rhs: {rhs}, output: {output})") + } + BlackBoxOp::BigIntDiv { lhs, rhs, output } => { + write!(f, "big_int_div(lhs: {lhs}, rhs: {rhs}, output: {output})") + } + BlackBoxOp::BigIntFromLeBytes { inputs, modulus, output } => { + write!( + f, + "big_int_from_le_bytes(inputs: {inputs}, modulus: {modulus}, output: {output})" + ) + } + BlackBoxOp::BigIntToLeBytes { input, output } => { + write!(f, "big_int_to_le_bytes(input: {input}, output: {output})") + } + BlackBoxOp::Poseidon2Permutation { message, output, len } => { + write!(f, "poseidon2_permutation(message: {message}, len: {len}, output: {output})") + } + BlackBoxOp::Sha256Compression { input, hash_values, output } => { + write!( + f, + "sha256_compression(input: {input}, hash_values: {hash_values}, output: {output})" + ) + } + BlackBoxOp::ToRadix { input, radix, output_pointer, num_limbs, output_bits } => { + write!( + f, + "to_radix(input: {input}, radix: {radix}, num_limbs: {num_limbs}, output_pointer: {output_pointer}, output_bits: {output_bits})" + ) + } + } + } +} diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index f789dbf5496..292328c764b 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -61,6 +61,15 @@ impl MemoryAddress { } } +impl std::fmt::Display for MemoryAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MemoryAddress::Direct(address) => write!(f, "@{address}"), + MemoryAddress::Relative(offset) => write!(f, "sp[{offset}]"), + } + } +} + /// Describes the memory layout for an array/vector element #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] pub enum HeapValueType { @@ -106,6 +115,44 @@ impl HeapValueType { } } +impl std::fmt::Display for HeapValueType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let write_types = + |f: &mut std::fmt::Formatter<'_>, value_types: &[HeapValueType]| -> std::fmt::Result { + if value_types.len() == 1 { + write!(f, "{}", value_types[0])?; + } else { + write!(f, "(")?; + for (index, value_type) in value_types.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{value_type}")?; + } + write!(f, ")")?; + } + Ok(()) + }; + + match self { + HeapValueType::Simple(bit_size) => { + write!(f, "{bit_size}") + } + HeapValueType::Array { value_types, size } => { + write!(f, "[")?; + write_types(f, value_types)?; + write!(f, "; {size}")?; + write!(f, "]") + } + HeapValueType::Vector { value_types } => { + write!(f, "&[")?; + write_types(f, value_types)?; + write!(f, "]") + } + } + } +} + /// A fixed-sized array starting from a Brillig memory location. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] @@ -120,6 +167,12 @@ impl Default for HeapArray { } } +impl std::fmt::Display for HeapArray { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[{}; {}]", self.pointer, self.size) + } +} + /// A memory-sized vector passed starting from a Brillig memory location and with a memory-held size #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] @@ -128,6 +181,12 @@ pub struct HeapVector { pub size: MemoryAddress, } +impl std::fmt::Display for HeapVector { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "&[{}; {}]", self.pointer, self.size) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] pub enum IntegerBitSize { @@ -205,6 +264,15 @@ impl BitSize { } } +impl std::fmt::Display for BitSize { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + BitSize::Field => write!(f, "field"), + BitSize::Integer(bit_size) => write!(f, "{bit_size}"), + } + } +} + /// Lays out various ways an external foreign call's input and output data may be interpreted inside Brillig. /// This data can either be an individual value or memory. /// @@ -229,6 +297,22 @@ pub enum ValueOrArray { HeapVector(HeapVector), } +impl std::fmt::Display for ValueOrArray { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ValueOrArray::MemoryAddress(memory_address) => { + write!(f, "{memory_address}") + } + ValueOrArray::HeapArray(heap_array) => { + write!(f, "{heap_array}") + } + ValueOrArray::HeapVector(heap_vector) => { + write!(f, "{heap_vector}") + } + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] pub enum BrilligOpcode { @@ -362,6 +446,109 @@ pub enum BrilligOpcode { }, } +impl std::fmt::Display for BrilligOpcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BrilligOpcode::BinaryFieldOp { destination, op, lhs, rhs } => { + write!(f, "{destination} = field {op} {lhs}, {rhs}") + } + BrilligOpcode::BinaryIntOp { destination, op, bit_size, lhs, rhs } => { + write!(f, "{destination} = {bit_size} {op} {lhs}, {rhs}") + } + BrilligOpcode::Not { destination, source, bit_size } => { + write!(f, "{destination} = {bit_size} not {source}") + } + BrilligOpcode::Cast { destination, source, bit_size } => { + write!(f, "{destination} = cast {source} to {bit_size}") + } + BrilligOpcode::JumpIfNot { condition, location } => { + write!(f, "jump if not {condition} to {location}") + } + BrilligOpcode::JumpIf { condition, location } => { + write!(f, "jump if {condition} to {location}") + } + BrilligOpcode::Jump { location } => { + write!(f, "jump to {location}") + } + BrilligOpcode::CalldataCopy { destination_address, size_address, offset_address } => { + write!( + f, + "{destination_address} = calldata copy [{offset_address}; {size_address}]" + ) + } + BrilligOpcode::Call { location } => { + write!(f, "call {location}") + } + BrilligOpcode::Const { destination, bit_size, value } => { + write!(f, "{destination} = const {bit_size} {value}") + } + BrilligOpcode::IndirectConst { destination_pointer, bit_size, value } => { + write!(f, "{destination_pointer} = indirect const {bit_size} {value}") + } + BrilligOpcode::Return => { + write!(f, "return") + } + BrilligOpcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert_eq!(destinations.len(), destination_value_types.len()); + + if !destinations.is_empty() { + for (index, (destination, destination_value_type)) in + destinations.iter().zip(destination_value_types.iter()).enumerate() + { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{destination}: {destination_value_type}")?; + } + write!(f, " = ")?; + } + + write!(f, "foreign call {function}(")?; + + assert_eq!(inputs.len(), input_value_types.len()); + for (index, (input, input_value_type)) in + inputs.iter().zip(input_value_types.iter()).enumerate() + { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{input}: {input_value_type}")?; + } + + write!(f, ")")?; + Ok(()) + } + BrilligOpcode::Mov { destination, source } => { + write!(f, "{destination} = {source}") + } + BrilligOpcode::ConditionalMov { destination, source_a, source_b, condition } => { + write!(f, "{destination} = if {condition} then {source_a} else {source_b}") + } + BrilligOpcode::Load { destination, source_pointer } => { + write!(f, "{destination} = load {source_pointer}") + } + BrilligOpcode::Store { destination_pointer, source } => { + write!(f, "store {source} at {destination_pointer}") + } + BrilligOpcode::BlackBox(black_box_op) => { + write!(f, "{black_box_op}") + } + BrilligOpcode::Trap { revert_data } => { + write!(f, "trap {revert_data}") + } + BrilligOpcode::Stop { return_data } => { + write!(f, "stop {return_data}") + } + } + } +} + /// Binary fixed-length field expressions #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] @@ -381,6 +568,21 @@ pub enum BinaryFieldOp { LessThanEquals, } +impl std::fmt::Display for BinaryFieldOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinaryFieldOp::Add => write!(f, "add"), + BinaryFieldOp::Sub => write!(f, "sub"), + BinaryFieldOp::Mul => write!(f, "mul"), + BinaryFieldOp::Div => write!(f, "field_div"), + BinaryFieldOp::IntegerDiv => write!(f, "int_div"), + BinaryFieldOp::Equals => write!(f, "eq"), + BinaryFieldOp::LessThan => write!(f, "lt"), + BinaryFieldOp::LessThanEquals => write!(f, "lt_eq"), + } + } +} + /// Binary fixed-length integer expressions #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] #[cfg_attr(feature = "arb", derive(proptest_derive::Arbitrary))] @@ -407,6 +609,25 @@ pub enum BinaryIntOp { Shr, } +impl std::fmt::Display for BinaryIntOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinaryIntOp::Add => write!(f, "add"), + BinaryIntOp::Sub => write!(f, "sub"), + BinaryIntOp::Mul => write!(f, "mul"), + BinaryIntOp::Div => write!(f, "div"), + BinaryIntOp::Equals => write!(f, "eq"), + BinaryIntOp::LessThan => write!(f, "lt"), + BinaryIntOp::LessThanEquals => write!(f, "lt_eq"), + BinaryIntOp::And => write!(f, "and"), + BinaryIntOp::Or => write!(f, "or"), + BinaryIntOp::Xor => write!(f, "xor"), + BinaryIntOp::Shl => write!(f, "shl"), + BinaryIntOp::Shr => write!(f, "shr"), + } + } +} + #[cfg(feature = "arb")] mod tests { use proptest::arbitrary::Arbitrary; diff --git a/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs b/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs index 4e12391f470..9402cf7bf07 100644 --- a/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs +++ b/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs @@ -51,11 +51,67 @@ fn multiple_brillig_calls_one_bytecode() { BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w5] BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w6] BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w7] - + unconstrained func 0 - [Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Call { location: 14 }, Call { location: 15 }, Mov { destination: Direct(32838), source: Relative(1) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32838 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 1 }, Stop { return_data: HeapVector { pointer: Relative(2), size: Relative(3) } }, Return, Call { location: 23 }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(2), bit_size: Integer(U1), value: 0 }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U1, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 22 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 28 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return] + 0: @2 = const u32 1 + 1: @1 = const u32 32839 + 2: @0 = const u32 3 + 3: sp[3] = const u32 2 + 4: sp[4] = const u32 0 + 5: @32836 = calldata copy [sp[4]; sp[3]] + 6: sp[1] = @32836 + 7: sp[2] = @32837 + 8: call 14 + 9: call 15 + 10: @32838 = sp[1] + 11: sp[2] = const u32 32838 + 12: sp[3] = const u32 1 + 13: stop &[sp[2]; sp[3]] + 14: return + 15: call 23 + 16: sp[3] = field eq sp[1], sp[2] + 17: sp[2] = const bool 0 + 18: sp[4] = bool eq sp[3], sp[2] + 19: jump if sp[4] to 22 + 20: sp[5] = const u32 0 + 21: trap &[@1; sp[5]] + 22: return + 23: @32772 = const u32 30720 + 24: @32771 = u32 lt @0, @32772 + 25: jump if @32771 to 28 + 26: @1 = indirect const u64 15764276373176857197 + 27: trap &[@1; @2] + 28: return unconstrained func 1 - [Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Call { location: 14 }, Call { location: 15 }, Mov { destination: Direct(32838), source: Relative(1) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32838 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 1 }, Stop { return_data: HeapVector { pointer: Relative(2), size: Relative(3) } }, Return, Call { location: 23 }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(2), bit_size: Integer(U1), value: 0 }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U1, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 22 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 28 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return] + 0: @2 = const u32 1 + 1: @1 = const u32 32839 + 2: @0 = const u32 3 + 3: sp[3] = const u32 2 + 4: sp[4] = const u32 0 + 5: @32836 = calldata copy [sp[4]; sp[3]] + 6: sp[1] = @32836 + 7: sp[2] = @32837 + 8: call 14 + 9: call 15 + 10: @32838 = sp[1] + 11: sp[2] = const u32 32838 + 12: sp[3] = const u32 1 + 13: stop &[sp[2]; sp[3]] + 14: return + 15: call 23 + 16: sp[3] = field eq sp[1], sp[2] + 17: sp[2] = const bool 0 + 18: sp[4] = bool eq sp[3], sp[2] + 19: jump if sp[4] to 22 + 20: sp[5] = const u32 0 + 21: trap &[@1; sp[5]] + 22: return + 23: @32772 = const u32 30720 + 24: @32771 = u32 lt @0, @32772 + 25: jump if @32771 to 28 + 26: @1 = indirect const u64 15764276373176857197 + 27: trap &[@1; @2] + 28: return "); } @@ -113,11 +169,26 @@ fn multiple_brillig_stdlib_calls() { BLACKBOX::RANGE [(w10, 32)] [] EXPR [ (-1, w2, w8) (1, w1) (-1, w9) 0 ] EXPR [ (1, w8) -1 ] - + unconstrained func 0 - [Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }] + 0: @21 = const u32 1 + 1: @20 = const u32 0 + 2: @0 = calldata copy [@20; @21] + 3: @2 = const field 0 + 4: @3 = field eq @0, @2 + 5: jump if @3 to 8 + 6: @1 = const field 1 + 7: @0 = field field_div @1, @0 + 8: stop &[@20; @21] unconstrained func 1 - [Const { destination: Direct(10), bit_size: Integer(U32), value: 2 }, Const { destination: Direct(11), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(10), offset_address: Direct(11) }, BinaryFieldOp { destination: Direct(2), op: IntegerDiv, lhs: Direct(0), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Mul, lhs: Direct(2), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Sub, lhs: Direct(0), rhs: Direct(1) }, Mov { destination: Direct(0), source: Direct(2) }, Stop { return_data: HeapVector { pointer: Direct(11), size: Direct(10) } }] + 0: @10 = const u32 2 + 1: @11 = const u32 0 + 2: @0 = calldata copy [@11; @10] + 3: @2 = field int_div @0, @1 + 4: @1 = field mul @2, @1 + 5: @1 = field sub @0, @1 + 6: @0 = @2 + 7: stop &[@11; @10] "); } @@ -190,13 +261,58 @@ fn brillig_stdlib_calls_with_regular_brillig_call() { BLACKBOX::RANGE [(w12, 32)] [] EXPR [ (-1, w2, w10) (1, w1) (-1, w11) 0 ] EXPR [ (1, w10) -1 ] - + unconstrained func 0 - [Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U32) }, Cast { destination: Direct(32837), source: Direct(32837), bit_size: Integer(U32) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Call { location: 16 }, Call { location: 17 }, Mov { destination: Direct(32838), source: Relative(1) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32838 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 1 }, Stop { return_data: HeapVector { pointer: Relative(2), size: Relative(3) } }, Return, Call { location: 25 }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(2), bit_size: Integer(U1), value: 0 }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U1, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 24 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 30 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return] + 0: @2 = const u32 1 + 1: @1 = const u32 32839 + 2: @0 = const u32 3 + 3: sp[3] = const u32 2 + 4: sp[4] = const u32 0 + 5: @32836 = calldata copy [sp[4]; sp[3]] + 6: @32836 = cast @32836 to u32 + 7: @32837 = cast @32837 to u32 + 8: sp[1] = @32836 + 9: sp[2] = @32837 + 10: call 16 + 11: call 17 + 12: @32838 = sp[1] + 13: sp[2] = const u32 32838 + 14: sp[3] = const u32 1 + 15: stop &[sp[2]; sp[3]] + 16: return + 17: call 25 + 18: sp[3] = u32 eq sp[1], sp[2] + 19: sp[2] = const bool 0 + 20: sp[4] = bool eq sp[3], sp[2] + 21: jump if sp[4] to 24 + 22: sp[5] = const u32 0 + 23: trap &[@1; sp[5]] + 24: return + 25: @32772 = const u32 30720 + 26: @32771 = u32 lt @0, @32772 + 27: jump if @32771 to 30 + 28: @1 = indirect const u64 15764276373176857197 + 29: trap &[@1; @2] + 30: return unconstrained func 1 - [Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }] + 0: @21 = const u32 1 + 1: @20 = const u32 0 + 2: @0 = calldata copy [@20; @21] + 3: @2 = const field 0 + 4: @3 = field eq @0, @2 + 5: jump if @3 to 8 + 6: @1 = const field 1 + 7: @0 = field field_div @1, @0 + 8: stop &[@20; @21] unconstrained func 2 - [Const { destination: Direct(10), bit_size: Integer(U32), value: 2 }, Const { destination: Direct(11), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(10), offset_address: Direct(11) }, BinaryFieldOp { destination: Direct(2), op: IntegerDiv, lhs: Direct(0), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Mul, lhs: Direct(2), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Sub, lhs: Direct(0), rhs: Direct(1) }, Mov { destination: Direct(0), source: Direct(2) }, Stop { return_data: HeapVector { pointer: Direct(11), size: Direct(10) } }] + 0: @10 = const u32 2 + 1: @11 = const u32 0 + 2: @0 = calldata copy [@11; @10] + 3: @2 = field int_div @0, @1 + 4: @1 = field mul @2, @1 + 5: @1 = field sub @0, @1 + 6: @0 = @2 + 7: stop &[@11; @10] "); } @@ -297,10 +413,55 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() { EXPR [ (-1, w0) (1, w2) 0 ] unconstrained func 0 - [Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U32) }, Cast { destination: Direct(32837), source: Direct(32837), bit_size: Integer(U32) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Call { location: 16 }, Call { location: 17 }, Mov { destination: Direct(32838), source: Relative(1) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32838 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 1 }, Stop { return_data: HeapVector { pointer: Relative(2), size: Relative(3) } }, Return, Call { location: 25 }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(2), bit_size: Integer(U1), value: 0 }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U1, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 24 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 30 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return] + 0: @2 = const u32 1 + 1: @1 = const u32 32839 + 2: @0 = const u32 3 + 3: sp[3] = const u32 2 + 4: sp[4] = const u32 0 + 5: @32836 = calldata copy [sp[4]; sp[3]] + 6: @32836 = cast @32836 to u32 + 7: @32837 = cast @32837 to u32 + 8: sp[1] = @32836 + 9: sp[2] = @32837 + 10: call 16 + 11: call 17 + 12: @32838 = sp[1] + 13: sp[2] = const u32 32838 + 14: sp[3] = const u32 1 + 15: stop &[sp[2]; sp[3]] + 16: return + 17: call 25 + 18: sp[3] = u32 eq sp[1], sp[2] + 19: sp[2] = const bool 0 + 20: sp[4] = bool eq sp[3], sp[2] + 21: jump if sp[4] to 24 + 22: sp[5] = const u32 0 + 23: trap &[@1; sp[5]] + 24: return + 25: @32772 = const u32 30720 + 26: @32771 = u32 lt @0, @32772 + 27: jump if @32771 to 30 + 28: @1 = indirect const u64 15764276373176857197 + 29: trap &[@1; @2] + 30: return unconstrained func 1 - [Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }] + 0: @21 = const u32 1 + 1: @20 = const u32 0 + 2: @0 = calldata copy [@20; @21] + 3: @2 = const field 0 + 4: @3 = field eq @0, @2 + 5: jump if @3 to 8 + 6: @1 = const field 1 + 7: @0 = field field_div @1, @0 + 8: stop &[@20; @21] unconstrained func 2 - [Const { destination: Direct(10), bit_size: Integer(U32), value: 2 }, Const { destination: Direct(11), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(10), offset_address: Direct(11) }, BinaryFieldOp { destination: Direct(2), op: IntegerDiv, lhs: Direct(0), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Mul, lhs: Direct(2), rhs: Direct(1) }, BinaryFieldOp { destination: Direct(1), op: Sub, lhs: Direct(0), rhs: Direct(1) }, Mov { destination: Direct(0), source: Direct(2) }, Stop { return_data: HeapVector { pointer: Direct(11), size: Direct(10) } }] + 0: @10 = const u32 2 + 1: @11 = const u32 0 + 2: @0 = calldata copy [@11; @10] + 3: @2 = field int_div @0, @1 + 4: @1 = field mul @2, @1 + 5: @1 = field sub @0, @1 + 6: @0 = @2 + 7: stop &[@11; @10] "); } diff --git a/compiler/noirc_evaluator/src/acir/tests/mod.rs b/compiler/noirc_evaluator/src/acir/tests/mod.rs index 0b2451c7c0f..8e59605565e 100644 --- a/compiler/noirc_evaluator/src/acir/tests/mod.rs +++ b/compiler/noirc_evaluator/src/acir/tests/mod.rs @@ -130,7 +130,57 @@ fn does_not_generate_memory_blocks_without_dynamic_accesses() { EXPR [ (1, w0) 0 ] unconstrained func 0 - [Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U32) }, Mov { destination: Relative(1), source: Direct(32836) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(4), rhs: Relative(6) }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(5) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, Store { destination_pointer: Relative(5), source: Relative(4) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(5), rhs: Direct(2) }, Store { destination_pointer: Relative(5), source: Relative(4) }, Const { destination: Relative(6), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(6) }, Mov { destination: Direct(32771), source: Relative(2) }, Mov { destination: Direct(32772), source: Relative(5) }, Mov { destination: Direct(32773), source: Relative(4) }, Call { location: 31 }, Mov { destination: Relative(2), source: Relative(3) }, Call { location: 42 }, Call { location: 43 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, BinaryIntOp { destination: Direct(32775), op: Add, bit_size: U32, lhs: Direct(32771), rhs: Direct(32773) }, Mov { destination: Direct(32776), source: Direct(32771) }, Mov { destination: Direct(32777), source: Direct(32772) }, BinaryIntOp { destination: Direct(32778), op: Equals, bit_size: U32, lhs: Direct(32776), rhs: Direct(32775) }, JumpIf { condition: Direct(32778), location: 41 }, Load { destination: Direct(32774), source_pointer: Direct(32776) }, Store { destination_pointer: Direct(32777), source: Direct(32774) }, BinaryIntOp { destination: Direct(32776), op: Add, bit_size: U32, lhs: Direct(32776), rhs: Direct(2) }, BinaryIntOp { destination: Direct(32777), op: Add, bit_size: U32, lhs: Direct(32777), rhs: Direct(2) }, Jump { location: 34 }, Return, Return, Call { location: 45 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 50 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return] + 0: @2 = const u32 1 + 1: @1 = const u32 32839 + 2: @0 = const u32 3 + 3: sp[3] = const u32 3 + 4: sp[4] = const u32 0 + 5: @32836 = calldata copy [sp[4]; sp[3]] + 6: @32836 = cast @32836 to u32 + 7: sp[1] = @32836 + 8: sp[2] = const u32 32837 + 9: sp[4] = const u32 2 + 10: sp[6] = const u32 3 + 11: sp[5] = u32 add sp[4], sp[6] + 12: sp[3] = @1 + 13: @1 = u32 add @1, sp[5] + 14: sp[3] = indirect const u32 1 + 15: sp[5] = u32 add sp[3], @2 + 16: store sp[4] at sp[5] + 17: sp[5] = u32 add sp[5], @2 + 18: store sp[4] at sp[5] + 19: sp[6] = const u32 3 + 20: sp[5] = u32 add sp[3], sp[6] + 21: @32771 = sp[2] + 22: @32772 = sp[5] + 23: @32773 = sp[4] + 24: call 31 + 25: sp[2] = sp[3] + 26: call 42 + 27: call 43 + 28: sp[1] = const u32 32839 + 29: sp[2] = const u32 0 + 30: stop &[sp[1]; sp[2]] + 31: @32775 = u32 add @32771, @32773 + 32: @32776 = @32771 + 33: @32777 = @32772 + 34: @32778 = u32 eq @32776, @32775 + 35: jump if @32778 to 41 + 36: @32774 = load @32776 + 37: store @32774 at @32777 + 38: @32776 = u32 add @32776, @2 + 39: @32777 = u32 add @32777, @2 + 40: jump to 34 + 41: return + 42: return + 43: call 45 + 44: return + 45: @32772 = const u32 30720 + 46: @32771 = u32 lt @0, @32772 + 47: jump if @32771 to 50 + 48: @1 = indirect const u64 15764276373176857197 + 49: trap &[@1; @2] + 50: return "); }