diff --git a/.aztec-sync-commit b/.aztec-sync-commit index 5e6d9f5f197..a4c0dea29a2 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -91042c7bcebfebeb4e629162f44988e2cda1ed41 +57f3c9bdc99103862a165bc235efdc8ef01b4e92 diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index b16baf14d06..0ccf7e4639d 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -464,6 +464,7 @@ namespace Program { Program::MemoryAddress input; uint32_t radix; Program::HeapArray output; + bool output_bits; friend bool operator==(const ToRadix&, const ToRadix&); std::vector bincodeSerialize() const; @@ -635,6 +636,16 @@ namespace Program { static Const bincodeDeserialize(std::vector); }; + struct IndirectConst { + Program::MemoryAddress destination_pointer; + Program::BitSize bit_size; + std::string value; + + friend bool operator==(const IndirectConst&, const IndirectConst&); + std::vector bincodeSerialize() const; + static IndirectConst bincodeDeserialize(std::vector); + }; + struct Return { friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; @@ -716,7 +727,7 @@ namespace Program { static Stop bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; @@ -933,6 +944,7 @@ namespace Program { std::vector proof; std::vector public_inputs; Program::FunctionInput key_hash; + uint32_t proof_type; friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; @@ -3149,6 +3161,7 @@ namespace Program { if (!(lhs.proof == rhs.proof)) { return false; } if (!(lhs.public_inputs == rhs.public_inputs)) { return false; } if (!(lhs.key_hash == rhs.key_hash)) { return false; } + if (!(lhs.proof_type == rhs.proof_type)) { return false; } return true; } @@ -3176,6 +3189,7 @@ void serde::Serializable::seria serde::Serializable::serialize(obj.proof, serializer); serde::Serializable::serialize(obj.public_inputs, serializer); serde::Serializable::serialize(obj.key_hash, serializer); + serde::Serializable::serialize(obj.proof_type, serializer); } template <> @@ -3186,6 +3200,7 @@ Program::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable::deserialize(deserializer); obj.public_inputs = serde::Deserializable::deserialize(deserializer); obj.key_hash = serde::Deserializable::deserialize(deserializer); + obj.proof_type = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4525,6 +4540,7 @@ namespace Program { if (!(lhs.input == rhs.input)) { return false; } if (!(lhs.radix == rhs.radix)) { return false; } if (!(lhs.output == rhs.output)) { return false; } + if (!(lhs.output_bits == rhs.output_bits)) { return false; } return true; } @@ -4551,6 +4567,7 @@ void serde::Serializable::serialize(const Program: serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.radix, serializer); serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.output_bits, serializer); } template <> @@ -4560,6 +4577,7 @@ Program::BlackBoxOp::ToRadix serde::Deserializable obj.input = serde::Deserializable::deserialize(deserializer); obj.radix = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); + obj.output_bits = serde::Deserializable::deserialize(deserializer); return obj; } @@ -5382,6 +5400,50 @@ Program::BrilligOpcode::Const serde::Deserializable BrilligOpcode::IndirectConst::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BrilligOpcode::IndirectConst BrilligOpcode::IndirectConst::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BrilligOpcode::IndirectConst &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination_pointer, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::BrilligOpcode::IndirectConst serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::IndirectConst obj; + obj.destination_pointer = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BrilligOpcode::Return &lhs, const BrilligOpcode::Return &rhs) { diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 6a301ec5115..333bab419c8 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -159,6 +159,7 @@ pub enum BlackBoxFuncCall { /// The circuit implementing this opcode can use this hash to ensure that the /// key provided to the circuit matches the key produced by the circuit creator key_hash: FunctionInput, + proof_type: u32, }, BigIntAdd { lhs: u32, @@ -350,6 +351,7 @@ impl BlackBoxFuncCall { proof, public_inputs, key_hash, + proof_type: _, } => { let mut inputs = Vec::new(); inputs.extend(key.iter().copied()); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index ce28d47021c..7bed57e22a0 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -204,11 +204,11 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 165, 155, 63, - 209, 31, 248, 25, 7, 23, 7, 17, 223, 175, 96, 2, 65, 162, 139, 30, 132, 203, 221, 65, 72, - 2, 170, 227, 107, 5, 216, 63, 200, 164, 57, 200, 115, 200, 102, 15, 22, 206, 205, 50, 124, - 223, 107, 108, 128, 155, 106, 113, 217, 141, 252, 10, 25, 225, 103, 121, 136, 197, 167, - 188, 250, 213, 76, 75, 158, 22, 178, 10, 176, 188, 242, 119, 164, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 133, 110, 190, + 68, 127, 224, 103, 28, 92, 28, 68, 124, 191, 130, 9, 4, 137, 46, 122, 16, 46, 119, 7, 33, + 9, 168, 142, 175, 21, 96, 255, 32, 147, 230, 32, 207, 33, 155, 61, 88, 56, 55, 203, 240, + 125, 175, 177, 1, 110, 170, 197, 101, 55, 242, 43, 100, 132, 159, 229, 33, 22, 159, 242, + 234, 87, 51, 45, 121, 90, 200, 42, 48, 209, 35, 111, 164, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -307,15 +307,15 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 145, 217, - 205, 13, 6, 102, 14, 208, 241, 4, 222, 69, 220, 41, 186, 244, 248, 90, 140, 24, 159, 5, 23, - 86, 208, 7, 37, 253, 228, 243, 146, 144, 50, 77, 200, 198, 197, 178, 127, 136, 52, 34, 253, - 189, 165, 53, 102, 221, 66, 164, 59, 134, 63, 199, 243, 229, 206, 226, 104, 110, 192, 209, - 158, 192, 145, 84, 255, 47, 216, 239, 152, 125, 137, 90, 63, 27, 152, 159, 132, 166, 249, - 74, 229, 252, 20, 153, 97, 161, 189, 145, 161, 237, 224, 173, 128, 19, 235, 189, 126, 192, - 17, 97, 4, 177, 75, 162, 101, 154, 187, 84, 113, 97, 136, 255, 82, 89, 150, 109, 211, 213, - 85, 111, 65, 21, 233, 126, 213, 254, 7, 239, 12, 118, 104, 171, 161, 63, 176, 144, 46, 7, - 244, 246, 124, 191, 105, 41, 241, 92, 246, 1, 235, 222, 207, 212, 69, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 17, 102, 55, + 39, 24, 152, 57, 64, 199, 19, 120, 23, 113, 167, 232, 210, 227, 107, 49, 98, 124, 22, 92, + 88, 65, 31, 148, 244, 147, 207, 75, 66, 202, 52, 33, 27, 23, 203, 254, 33, 210, 136, 244, + 247, 150, 214, 152, 117, 11, 145, 238, 24, 254, 28, 207, 151, 59, 139, 163, 185, 1, 71, + 123, 2, 71, 82, 253, 191, 96, 191, 99, 246, 37, 106, 253, 108, 96, 126, 18, 154, 230, 43, + 149, 243, 83, 100, 134, 133, 246, 70, 134, 182, 131, 183, 2, 78, 172, 247, 250, 1, 71, 132, + 17, 196, 46, 137, 150, 105, 238, 82, 197, 133, 33, 254, 75, 101, 89, 182, 77, 87, 87, 189, + 5, 85, 164, 251, 85, 251, 31, 188, 51, 216, 161, 173, 134, 254, 192, 66, 186, 28, 208, 219, + 243, 253, 166, 165, 196, 115, 217, 7, 253, 216, 100, 109, 69, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 82f983e407b..53597ece157 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 145, 217, 205, 13, 6, 102, 14, 208, 241, - 4, 222, 69, 220, 41, 186, 244, 248, 90, 140, 24, 159, 5, 23, 86, 208, 7, 37, 253, 228, 243, 146, 144, 50, 77, 200, - 198, 197, 178, 127, 136, 52, 34, 253, 189, 165, 53, 102, 221, 66, 164, 59, 134, 63, 199, 243, 229, 206, 226, 104, 110, - 192, 209, 158, 192, 145, 84, 255, 47, 216, 239, 152, 125, 137, 90, 63, 27, 152, 159, 132, 166, 249, 74, 229, 252, 20, - 153, 97, 161, 189, 145, 161, 237, 224, 173, 128, 19, 235, 189, 126, 192, 17, 97, 4, 177, 75, 162, 101, 154, 187, 84, - 113, 97, 136, 255, 82, 89, 150, 109, 211, 213, 85, 111, 65, 21, 233, 126, 213, 254, 7, 239, 12, 118, 104, 171, 161, - 63, 176, 144, 46, 7, 244, 246, 124, 191, 105, 41, 241, 92, 246, 1, 235, 222, 207, 212, 69, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 17, 102, 55, 39, 24, 152, 57, 64, 199, + 19, 120, 23, 113, 167, 232, 210, 227, 107, 49, 98, 124, 22, 92, 88, 65, 31, 148, 244, 147, 207, 75, 66, 202, 52, 33, + 27, 23, 203, 254, 33, 210, 136, 244, 247, 150, 214, 152, 117, 11, 145, 238, 24, 254, 28, 207, 151, 59, 139, 163, 185, + 1, 71, 123, 2, 71, 82, 253, 191, 96, 191, 99, 246, 37, 106, 253, 108, 96, 126, 18, 154, 230, 43, 149, 243, 83, 100, + 134, 133, 246, 70, 134, 182, 131, 183, 2, 78, 172, 247, 250, 1, 71, 132, 17, 196, 46, 137, 150, 105, 238, 82, 197, + 133, 33, 254, 75, 101, 89, 182, 77, 87, 87, 189, 5, 85, 164, 251, 85, 251, 31, 188, 51, 216, 161, 173, 134, 254, 192, + 66, 186, 28, 208, 219, 243, 253, 166, 165, 196, 115, 217, 7, 253, 216, 100, 109, 69, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index dad7c7e1568..3500e03776d 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 165, 155, 63, 209, 31, 248, 25, 7, 23, 7, - 17, 223, 175, 96, 2, 65, 162, 139, 30, 132, 203, 221, 65, 72, 2, 170, 227, 107, 5, 216, 63, 200, 164, 57, 200, 115, - 200, 102, 15, 22, 206, 205, 50, 124, 223, 107, 108, 128, 155, 106, 113, 217, 141, 252, 10, 25, 225, 103, 121, 136, - 197, 167, 188, 250, 213, 76, 75, 158, 22, 178, 10, 176, 188, 242, 119, 164, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 133, 110, 190, 68, 127, 224, 103, 28, 92, + 28, 68, 124, 191, 130, 9, 4, 137, 46, 122, 16, 46, 119, 7, 33, 9, 168, 142, 175, 21, 96, 255, 32, 147, 230, 32, 207, + 33, 155, 61, 88, 56, 55, 203, 240, 125, 175, 177, 1, 110, 170, 197, 101, 55, 242, 43, 100, 132, 159, 229, 33, 22, 159, + 242, 234, 87, 51, 45, 121, 90, 200, 42, 48, 209, 35, 111, 164, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 60e4af11ea2..c3240c6ff1e 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -132,5 +132,6 @@ pub enum BlackBoxOp { input: MemoryAddress, radix: u32, output: HeapArray, + output_bits: bool, }, } diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index fdcae01b5b5..f2ba04a4d59 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -223,6 +223,11 @@ pub enum BrilligOpcode { bit_size: BitSize, value: F, }, + IndirectConst { + destination_pointer: MemoryAddress, + bit_size: BitSize, + value: F, + }, Return, /// Used to get data from an outside source. /// Also referred to as an Oracle. However, we don't use that name as diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index b49757944ad..3f1a44b921b 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -1,4 +1,4 @@ -use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; +use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, IntegerBitSize}; use acir::{AcirField, BlackBoxFunc}; use acvm_blackbox_solver::BigIntSolver; use acvm_blackbox_solver::{ @@ -6,6 +6,7 @@ use acvm_blackbox_solver::{ keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; use num_bigint::BigUint; +use num_traits::Zero; use crate::memory::MemoryValue; use crate::Memory; @@ -366,7 +367,7 @@ pub(crate) fn evaluate_black_box memory.write_slice(memory.read_ref(output.pointer), &state); Ok(()) } - BlackBoxOp::ToRadix { input, radix, output } => { + BlackBoxOp::ToRadix { input, radix, output, output_bits } => { let input: F = *memory.read(*input).extract_field().expect("ToRadix input not a field"); let mut input = BigUint::from_bytes_be(&input.to_be_bytes()); @@ -376,7 +377,15 @@ pub(crate) fn evaluate_black_box for _ in 0..output.size { let limb = &input % &radix; - limbs.push(MemoryValue::new_field(F::from_be_bytes_reduce(&limb.to_bytes_be()))); + if *output_bits { + limbs.push(MemoryValue::new_integer( + if limb.is_zero() { 0 } else { 1 }, + IntegerBitSize::U1, + )); + } else { + let limb: u8 = limb.try_into().unwrap(); + limbs.push(MemoryValue::new_integer(limb as u128, IntegerBitSize::U8)); + }; input /= &radix; } diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 936ad120335..5097ecf4707 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -339,6 +339,13 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { self.memory.write(*destination, MemoryValue::new_from_field(*value, *bit_size)); self.increment_program_counter() } + Opcode::IndirectConst { destination_pointer, bit_size, value } => { + // Convert our destination_pointer to an address + let destination = self.memory.read_ref(*destination_pointer); + // Use our usize destination index to set the value in memory + self.memory.write(destination, MemoryValue::new_from_field(*value, *bit_size)); + self.increment_program_counter() + } Opcode::BlackBox(black_box_op) => { match evaluate_black_box( black_box_op, @@ -1189,6 +1196,34 @@ mod tests { assert_eq!(memory, expected); } + #[test] + fn iconst_opcode() { + let opcodes = &[ + Opcode::Const { + destination: MemoryAddress(0), + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), + value: FieldElement::from(8_usize), + }, + Opcode::IndirectConst { + destination_pointer: MemoryAddress(0), + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), + value: FieldElement::from(27_usize), + }, + ]; + let mut vm = VM::new(vec![], opcodes, vec![], &StubbedBlackBoxSolver); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + let VM { memory, .. } = vm; + + let destination_value = memory.read(MemoryAddress::from(8)); + assert_eq!(destination_value.to_field(), (27_usize).into()); + } + #[test] fn load_opcode() { /// Brillig code for the following: diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs index d6364cefc9a..b256c2b85ab 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs @@ -9,7 +9,10 @@ mod variable_liveness; use acvm::FieldElement; use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext}; -use super::brillig_ir::{artifact::BrilligArtifact, BrilligContext}; +use super::brillig_ir::{ + artifact::{BrilligArtifact, Label}, + BrilligContext, +}; use crate::ssa::ir::function::Function; /// Converting an SSA function into Brillig bytecode. @@ -21,7 +24,7 @@ pub(crate) fn convert_ssa_function( let mut function_context = FunctionContext::new(func); - brillig_context.enter_context(FunctionContext::function_id_to_function_label(func.id())); + brillig_context.enter_context(Label::function(func.id())); for block in function_context.blocks.clone() { BrilligBlock::compile(&mut function_context, &mut brillig_context, block, &func.dfg); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 8e2b2fb7a29..802d442885f 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -6,14 +6,15 @@ use acvm::{ use crate::brillig::brillig_ir::{ brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, debug_show::DebugToString, + registers::RegisterAllocator, BrilligContext, }; /// Transforms SSA's black box function calls into the corresponding brillig instructions /// Extracting arguments and results from the SSA function call /// And making any necessary type conversions to adapt noir's blackbox calls to brillig's -pub(crate) fn convert_black_box_call( - brillig_context: &mut BrilligContext, +pub(crate) fn convert_black_box_call( + brillig_context: &mut BrilligContext, bb_func: &BlackBoxFunc, function_arguments: &[BrilligVariable], function_results: &[BrilligVariable], @@ -397,8 +398,8 @@ pub(crate) fn convert_black_box_call( } } -fn convert_array_or_vector( - brillig_context: &mut BrilligContext, +fn convert_array_or_vector( + brillig_context: &mut BrilligContext, array_or_vector: &BrilligVariable, bb_func: &BlackBoxFunc, ) -> BrilligVector { 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 1e672eeea3c..eeaa60b4323 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,8 +1,10 @@ +use crate::brillig::brillig_ir::artifact::Label; use crate::brillig::brillig_ir::brillig_variable::{ type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, }; +use crate::brillig::brillig_ir::registers::Stack; use crate::brillig::brillig_ir::{ - BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + BrilligBinaryOp, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; use crate::ssa::ir::dfg::CallStack; use crate::ssa::ir::instruction::ConstrainError; @@ -34,7 +36,7 @@ pub(crate) struct BrilligBlock<'block> { /// The basic block that is being converted pub(crate) block_id: BasicBlockId, /// Context for creating brillig opcodes - pub(crate) brillig_context: &'block mut BrilligContext, + pub(crate) brillig_context: &'block mut BrilligContext, /// Tracks the available variable during the codegen of the block pub(crate) variables: BlockVariables, /// For each instruction, the set of values that are not used anymore after it. @@ -45,7 +47,7 @@ impl<'block> BrilligBlock<'block> { /// Converts an SSA Basic block into a sequence of Brillig opcodes pub(crate) fn compile( function_context: &'block mut FunctionContext, - brillig_context: &'block mut BrilligContext, + brillig_context: &'block mut BrilligContext, block_id: BasicBlockId, dfg: &DataFlowGraph, ) { @@ -93,7 +95,7 @@ impl<'block> BrilligBlock<'block> { /// This uses the current functions's function ID and the block ID /// Making the assumption that the block ID passed in belongs to this /// function. - fn create_block_label_for_current_function(&self, block_id: BasicBlockId) -> String { + fn create_block_label_for_current_function(&self, block_id: BasicBlockId) -> Label { Self::create_block_label(self.function_context.function_id, block_id) } /// Creates a unique label for a block using the function Id and the block ID. @@ -102,8 +104,8 @@ impl<'block> BrilligBlock<'block> { /// for us to create a unique label across functions and blocks. /// /// This is so that during linking there are no duplicates or labels being overwritten. - fn create_block_label(function_id: FunctionId, block_id: BasicBlockId) -> String { - format!("{function_id}-{block_id}") + fn create_block_label(function_id: FunctionId, block_id: BasicBlockId) -> Label { + Label::block(function_id, block_id) } /// Converts an SSA terminator instruction into the necessary opcodes. @@ -468,13 +470,21 @@ impl<'block> BrilligBlock<'block> { result_ids[1], dfg, ); - let source_size_as_register = - self.convert_ssa_array_set(source_variable, destination_variable, None); - // we need to explicitly set the destination_len_variable self.brillig_context - .mov_instruction(destination_len_variable.address, source_size_as_register); - self.brillig_context.deallocate_register(source_size_as_register); + .call_array_copy_procedure(source_variable, destination_variable); + + let BrilligVariable::BrilligArray(BrilligArray { size: source_size, .. }) = + source_variable + else { + unreachable!("ICE: AsSlice on non-array") + }; + + // we need to explicitly set the destination_len_variable + self.brillig_context.usize_const_instruction( + destination_len_variable.address, + source_size.into(), + ); } Value::Intrinsic( Intrinsic::SlicePushBack @@ -539,7 +549,7 @@ impl<'block> BrilligBlock<'block> { radix, limb_count, matches!(endianness, Endian::Big), - 8, + false, ); } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { @@ -585,7 +595,7 @@ impl<'block> BrilligBlock<'block> { 2, limb_count, matches!(endianness, Endian::Big), - 1, + true, ); } @@ -660,12 +670,12 @@ impl<'block> BrilligBlock<'block> { dfg, ); self.validate_array_index(source_variable, index_register); - let source_size_as_register = self.convert_ssa_array_set( + self.convert_ssa_array_set( source_variable, destination_variable, - Some((index_register.address, value_variable)), + index_register, + value_variable, ); - self.brillig_context.deallocate_register(source_size_as_register); } Instruction::RangeCheck { value, max_bit_size, assert_message } => { let value = self.convert_ssa_single_addr_value(*value, dfg); @@ -761,9 +771,6 @@ impl<'block> BrilligBlock<'block> { .flat_map(|argument_id| self.convert_ssa_value(*argument_id, dfg).extract_registers()) .collect(); - // Create label for the function that will be called - let label_of_function_to_call = FunctionContext::function_id_to_function_label(func_id); - let variables_to_save = self.variables.get_available_variables(self.function_context); let saved_registers = self @@ -774,7 +781,7 @@ impl<'block> BrilligBlock<'block> { self.variables.dump_constants(); // Call instruction, which will interpret above registers 0..num args - self.brillig_context.add_external_call_instruction(label_of_function_to_call); + self.brillig_context.add_external_call_instruction(func_id); // Important: resolve after pre_call_save_registers_prep_args // This ensures we don't save the results to registers unnecessarily. @@ -870,88 +877,23 @@ impl<'block> BrilligBlock<'block> { &mut self, source_variable: BrilligVariable, destination_variable: BrilligVariable, - opt_index_and_value: Option<(MemoryAddress, BrilligVariable)>, - ) -> MemoryAddress { + index_register: SingleAddrVariable, + value_variable: BrilligVariable, + ) { + assert!(index_register.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); let destination_pointer = match destination_variable { BrilligVariable::BrilligArray(BrilligArray { pointer, .. }) => pointer, BrilligVariable::BrilligVector(BrilligVector { pointer, .. }) => pointer, _ => unreachable!("ICE: array_set SSA returns non-array"), }; - let reference_count = match source_variable { - BrilligVariable::BrilligArray(BrilligArray { rc, .. }) - | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, - _ => unreachable!("ICE: array_set SSA on non-array"), - }; - - let (source_pointer, source_size_as_register) = match source_variable { - BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { - let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.usize_const_instruction(source_size_register, size.into()); - (pointer, source_size_register) - } - BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { - let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.mov_instruction(source_size_register, size); - (pointer, source_size_register) - } - _ => unreachable!("ICE: array_set SSA on non-array"), - }; - - // Here we want to compare the reference count against 1. - let one = self.brillig_context.make_usize_constant_instruction(1_usize.into()); - let condition = self.brillig_context.allocate_register(); - self.brillig_context.memory_op_instruction( - reference_count, - one.address, - condition, - BrilligBinaryOp::Equals, + self.brillig_context.call_array_copy_procedure(source_variable, destination_variable); + // Then set the value in the newly created array + self.brillig_context.codegen_store_variable_in_array( + destination_pointer, + index_register, + value_variable, ); - self.brillig_context.codegen_branch(condition, |ctx, cond| { - if cond { - // Reference count is 1, we can mutate the array directly - ctx.mov_instruction(destination_pointer, source_pointer); - } else { - // First issue a array copy to the destination - ctx.codegen_allocate_array(destination_pointer, source_size_as_register); - - ctx.codegen_copy_array( - source_pointer, - destination_pointer, - SingleAddrVariable::new( - source_size_as_register, - BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - ), - ); - } - }); - - match destination_variable { - BrilligVariable::BrilligArray(BrilligArray { rc: target_rc, .. }) => { - self.brillig_context.usize_const_instruction(target_rc, 1_usize.into()); - } - BrilligVariable::BrilligVector(BrilligVector { - size: target_size, - rc: target_rc, - .. - }) => { - self.brillig_context.mov_instruction(target_size, source_size_as_register); - self.brillig_context.usize_const_instruction(target_rc, 1_usize.into()); - } - _ => unreachable!("ICE: array_set SSA on non-array"), - } - - if let Some((index_register, value_variable)) = opt_index_and_value { - // Then set the value in the newly created array - self.brillig_context.codegen_store_variable_in_array( - destination_pointer, - SingleAddrVariable::new_usize(index_register), - value_variable, - ); - } - - self.brillig_context.deallocate_register(condition); - source_size_as_register } /// Convert the SSA slice operations to brillig slice operations @@ -1733,11 +1675,9 @@ impl<'block> BrilligBlock<'block> { let subitem_pointer = SingleAddrVariable::new_usize(self.brillig_context.allocate_register()); - let one = self.brillig_context.make_usize_constant_instruction(1_usize.into()); - // Initializes a single subitem let initializer_fn = - |ctx: &mut BrilligContext<_>, subitem_start_pointer: SingleAddrVariable| { + |ctx: &mut BrilligContext<_, _>, subitem_start_pointer: SingleAddrVariable| { ctx.mov_instruction(subitem_pointer.address, subitem_start_pointer.address); for (subitem_index, subitem) in subitem_to_repeat_variables.into_iter().enumerate() @@ -1746,7 +1686,7 @@ impl<'block> BrilligBlock<'block> { if subitem_index != item_types.len() - 1 { ctx.memory_op_instruction( subitem_pointer.address, - one.address, + ReservedRegisters::usize_one(), subitem_pointer.address, BrilligBinaryOp::Add, ); @@ -1764,13 +1704,13 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.deallocate_single_addr(step_variable); self.brillig_context.deallocate_single_addr(subitem_pointer); - self.brillig_context.deallocate_single_addr(one); } else { let subitem = subitem_to_repeat_variables.into_iter().next().unwrap(); - let initializer_fn = |ctx: &mut BrilligContext<_>, item_pointer: SingleAddrVariable| { - ctx.codegen_store_variable_in_pointer(item_pointer.address, subitem); - }; + let initializer_fn = + |ctx: &mut BrilligContext<_, _>, item_pointer: SingleAddrVariable| { + ctx.codegen_store_variable_in_pointer(item_pointer.address, subitem); + }; // for (let item_pointer = pointer; item_pointer < pointer + data_length; item_pointer += 1) { initializer_fn(iterator) } self.brillig_context.codegen_for_loop( @@ -1791,20 +1731,28 @@ impl<'block> BrilligBlock<'block> { ) { // Allocate a register for the iterator let write_pointer_register = self.brillig_context.allocate_register(); - let one = self.brillig_context.make_usize_constant_instruction(1_usize.into()); self.brillig_context.mov_instruction(write_pointer_register, pointer); for (element_idx, element_id) in data.iter().enumerate() { - let element_variable = self.convert_ssa_value(*element_id, dfg); - // Store the item in memory - self.brillig_context - .codegen_store_variable_in_pointer(write_pointer_register, element_variable); + if let Some((constant, typ)) = dfg.get_numeric_constant_with_type(*element_id) { + self.brillig_context.indirect_const_instruction( + write_pointer_register, + typ.bit_size(), + constant, + ); + } else { + let element_variable = self.convert_ssa_value(*element_id, dfg); + // Store the item in memory + self.brillig_context + .codegen_store_variable_in_pointer(write_pointer_register, element_variable); + } + if element_idx != data.len() - 1 { // Increment the write_pointer_register self.brillig_context.memory_op_instruction( write_pointer_register, - one.address, + ReservedRegisters::usize_one(), write_pointer_register, BrilligBinaryOp::Add, ); @@ -1812,7 +1760,6 @@ impl<'block> BrilligBlock<'block> { } self.brillig_context.deallocate_register(write_pointer_register); - self.brillig_context.deallocate_single_addr(one); } /// Converts an SSA `ValueId` into a `MemoryAddress`. Initializes if necessary. 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 ffbca256d28..63b2073c654 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 @@ -7,6 +7,7 @@ use crate::{ get_bit_size_from_ssa_type, BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, }, + registers::{RegisterAllocator, Stack}, BrilligContext, }, ssa::ir::{ @@ -51,7 +52,7 @@ impl BlockVariables { pub(crate) fn define_variable( &mut self, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, ) -> BrilligVariable { @@ -71,7 +72,7 @@ impl BlockVariables { pub(crate) fn define_single_addr_variable( &mut self, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value: ValueId, dfg: &DataFlowGraph, ) -> SingleAddrVariable { @@ -84,7 +85,7 @@ impl BlockVariables { &mut self, value_id: &ValueId, function_context: &mut FunctionContext, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, ) { assert!(self.available_variables.remove(value_id), "ICE: Variable is not available"); let variable = function_context @@ -123,7 +124,7 @@ impl BlockVariables { /// We keep constants block-local. pub(crate) fn allocate_constant( &mut self, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, value_id: ValueId, dfg: &DataFlowGraph, ) -> BrilligVariable { @@ -155,9 +156,9 @@ pub(crate) fn compute_array_length(item_typ: &CompositeType, elem_count: usize) } /// For a given value_id, allocates the necessary registers to hold it. -pub(crate) fn allocate_value( +pub(crate) fn allocate_value( value_id: ValueId, - brillig_context: &mut BrilligContext, + brillig_context: &mut BrilligContext, dfg: &DataFlowGraph, ) -> BrilligVariable { let typ = dfg.type_of_value(value_id); 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 f0752c80c46..c1abad17a8f 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -2,7 +2,7 @@ use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ - artifact::{BrilligParameter, Label}, + artifact::BrilligParameter, brillig_variable::{get_bit_size_from_ssa_type, BrilligVariable}, }, ssa::ir::{ @@ -44,11 +44,6 @@ impl FunctionContext { } } - /// Creates a function label from a given SSA function id. - pub(crate) fn function_id_to_function_label(function_id: FunctionId) -> Label { - function_id.to_string() - } - pub(crate) fn ssa_type_to_parameter(typ: &Type) -> BrilligParameter { match typ { Type::Numeric(_) | Type::Reference(_) => { 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 55679432b1f..9dbf0ee9bb6 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 @@ -24,7 +24,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we copy the source vector into the target vector - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_vector.pointer, target_vector.pointer, SingleAddrVariable::new_usize(source_vector.size), @@ -74,7 +74,7 @@ impl<'block> BrilligBlock<'block> { ); // Now we copy the source vector into the target vector starting at index variables_to_insert.len() - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_vector.pointer, destination_copy_pointer, SingleAddrVariable::new_usize(source_vector.size), @@ -121,7 +121,7 @@ impl<'block> BrilligBlock<'block> { ); // Now we copy the source vector starting at index removed_items.len() into the target vector - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_copy_pointer, target_vector.pointer, SingleAddrVariable::new_usize(target_vector.size), @@ -154,7 +154,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we copy all elements except the last items into the target vector - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_vector.pointer, target_vector.pointer, SingleAddrVariable::new_usize(target_vector.size), @@ -192,11 +192,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index - self.brillig_context.codegen_copy_array( - source_vector.pointer, - target_vector.pointer, - index, - ); + self.brillig_context.codegen_mem_copy(source_vector.pointer, target_vector.pointer, index); // Compute the source pointer just at the index let source_pointer_at_index = self.brillig_context.allocate_register(); @@ -231,7 +227,7 @@ impl<'block> BrilligBlock<'block> { ); // Copy the elements to the right of the index - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_pointer_at_index, target_pointer_after_index, SingleAddrVariable::new_usize(item_count), @@ -279,11 +275,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index - self.brillig_context.codegen_copy_array( - source_vector.pointer, - target_vector.pointer, - index, - ); + self.brillig_context.codegen_mem_copy(source_vector.pointer, target_vector.pointer, index); // Compute the source pointer after the removed items let source_pointer_after_index = self.brillig_context.allocate_register(); @@ -323,7 +315,7 @@ impl<'block> BrilligBlock<'block> { ); // Copy the elements to the right of the index - self.brillig_context.codegen_copy_array( + self.brillig_context.codegen_mem_copy( source_pointer_after_index, target_pointer_at_index, SingleAddrVariable::new_usize(item_count), @@ -371,10 +363,11 @@ mod tests { use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; use crate::brillig::brillig_gen::brillig_fn::FunctionContext; - use crate::brillig::brillig_ir::artifact::BrilligParameter; + use crate::brillig::brillig_ir::artifact::{BrilligParameter, Label}; use crate::brillig::brillig_ir::brillig_variable::{ BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, }; + use crate::brillig::brillig_ir::registers::Stack; use crate::brillig::brillig_ir::tests::{ create_and_run_vm, create_context, create_entry_point_bytecode, }; @@ -384,12 +377,14 @@ mod tests { use crate::ssa::ir::map::Id; use crate::ssa::ssa_gen::Ssa; - fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { + fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { let mut builder = FunctionBuilder::new("main".to_string(), Id::test_new(0)); builder.set_runtime(RuntimeType::Brillig); let ssa = builder.finish(); - let brillig_context = create_context(); + let mut brillig_context = create_context(ssa.main_id); + brillig_context.enter_context(Label::block(ssa.main_id, Id::test_new(0))); + brillig_context.disable_procedures(); let function_context = FunctionContext::new(ssa.main()); (ssa, function_context, brillig_context) @@ -397,7 +392,7 @@ mod tests { fn create_brillig_block<'a>( function_context: &'a mut FunctionContext, - brillig_context: &'a mut BrilligContext, + brillig_context: &'a mut BrilligContext, ) -> BrilligBlock<'a> { let variables = BlockVariables::default(); BrilligBlock { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 21f8722c116..05117b96c5d 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -12,6 +12,7 @@ pub(crate) mod artifact; pub(crate) mod brillig_variable; pub(crate) mod debug_show; +pub(crate) mod procedures; pub(crate) mod registers; mod codegen_binary; @@ -23,11 +24,11 @@ mod codegen_stack; mod entry_point; mod instructions; +use artifact::Label; pub(crate) use instructions::BrilligBinaryOp; +use registers::{RegisterAllocator, ScratchSpace}; -use self::{ - artifact::BrilligArtifact, debug_show::DebugToString, registers::BrilligRegistersContext, -}; +use self::{artifact::BrilligArtifact, debug_show::DebugToString, registers::Stack}; use crate::ssa::ir::dfg::CallStack; use acvm::{ acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, @@ -46,6 +47,8 @@ pub(crate) enum ReservedRegisters { FreeMemoryPointer = 0, /// This register stores the previous stack pointer. The registers of the caller are stored here. PreviousStackPointer = 1, + /// This register stores a 1_usize constant. + UsizeOne = 2, } impl ReservedRegisters { @@ -53,7 +56,7 @@ impl ReservedRegisters { /// /// This is used to offset the general registers /// which should not overwrite the special register - const NUM_RESERVED_REGISTERS: usize = 2; + const NUM_RESERVED_REGISTERS: usize = 3; /// Returns the length of the reserved registers pub(crate) fn len() -> usize { @@ -70,42 +73,67 @@ impl ReservedRegisters { MemoryAddress::from(ReservedRegisters::PreviousStackPointer as usize) } - /// Returns a user defined (non-reserved) register index. - fn user_register_index(index: usize) -> MemoryAddress { - MemoryAddress::from(index + ReservedRegisters::len()) + /// Returns the usize one register. This will be used to perform arithmetic operations. + pub(crate) fn usize_one() -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::UsizeOne as usize) } } /// Brillig context object that is used while constructing the /// Brillig bytecode. -pub(crate) struct BrilligContext { +pub(crate) struct BrilligContext { obj: BrilligArtifact, /// Tracks register allocations - registers: BrilligRegistersContext, + registers: Registers, /// Context label, must be unique with respect to the function /// being linked. - context_label: String, + context_label: Label, /// Section label, used to separate sections of code - section_label: usize, + current_section: usize, /// Stores the next available section next_section: usize, /// IR printer debug_show: DebugShow, + /// Whether this context can call procedures or not. + /// This is used to prevent a procedure from calling another procedure. + can_call_procedures: bool, } -impl BrilligContext { - /// Initial context state - pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext { +/// Regular brillig context to codegen user defined functions +impl BrilligContext { + pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext { BrilligContext { obj: BrilligArtifact::default(), - registers: BrilligRegistersContext::new(), - context_label: String::default(), - section_label: 0, + registers: Stack::new(), + context_label: Label::entrypoint(), + current_section: 0, next_section: 1, debug_show: DebugShow::new(enable_debug_trace), + can_call_procedures: true, } } + /// Allows disabling procedures so tests don't need a linking pass + pub(crate) fn disable_procedures(&mut self) { + self.can_call_procedures = false; + } +} + +/// Special brillig context to codegen compiler intrinsic shared procedures +impl BrilligContext { + pub(crate) fn new_for_procedure(enable_debug_trace: bool) -> BrilligContext { + BrilligContext { + obj: BrilligArtifact::default(), + registers: ScratchSpace::new(), + context_label: Label::entrypoint(), + current_section: 0, + next_section: 1, + debug_show: DebugShow::new(enable_debug_trace), + can_call_procedures: false, + } + } +} +impl BrilligContext { /// Adds a brillig instruction to the brillig byte code fn push_opcode(&mut self, opcode: BrilligOpcode) { self.obj.push_opcode(opcode); @@ -135,8 +163,10 @@ pub(crate) mod tests { use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; + use crate::ssa::ir::function::FunctionId; - use super::artifact::{BrilligParameter, GeneratedBrillig}; + use super::artifact::{BrilligParameter, GeneratedBrillig, Label}; + use super::registers::Stack; use super::{BrilligOpcode, ReservedRegisters}; pub(crate) struct DummyBlackBoxSolver; @@ -195,20 +225,20 @@ pub(crate) mod tests { } } - pub(crate) fn create_context() -> BrilligContext { + pub(crate) fn create_context(id: FunctionId) -> BrilligContext { let mut context = BrilligContext::new(true); - context.enter_context("test"); + context.enter_context(Label::function(id)); context } pub(crate) fn create_entry_point_bytecode( - context: BrilligContext, + context: BrilligContext, arguments: Vec, returns: Vec, ) -> GeneratedBrillig { let artifact = context.artifact(); let mut entry_point_artifact = - BrilligContext::new_entry_point_artifact(arguments, returns, "test".to_string()); + BrilligContext::new_entry_point_artifact(arguments, returns, FunctionId::test_new(0)); entry_point_artifact.link_with(&artifact); entry_point_artifact.finish() } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 53964f64170..d0bd91e185c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -1,7 +1,8 @@ use acvm::acir::brillig::Opcode as BrilligOpcode; use std::collections::{BTreeMap, HashMap}; -use crate::ssa::ir::dfg::CallStack; +use crate::brillig::brillig_ir::procedures::ProcedureId; +use crate::ssa::ir::{basic_block::BasicBlockId, dfg::CallStack, function::FunctionId}; /// Represents a parameter or a return value of an entry point function. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] @@ -45,7 +46,7 @@ pub(crate) struct BrilligArtifact { /// which are defined in other bytecode, that this bytecode has called. /// TODO: perhaps we should combine this with the `unresolved_jumps` field /// TODO: and have an enum which indicates whether the jump is internal or external - unresolved_external_call_labels: Vec<(JumpInstructionPosition, UnresolvedJumpLocation)>, + unresolved_external_call_labels: Vec<(JumpInstructionPosition, Label)>, /// Maps the opcodes that are associated with a callstack to it. locations: BTreeMap, /// The current call stack. All opcodes that are pushed will be associated with this call stack. @@ -56,11 +57,74 @@ pub(crate) struct BrilligArtifact { /// A pointer to a location in the opcode. pub(crate) type OpcodeLocation = usize; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub(crate) enum LabelType { + /// Labels for the entry point bytecode + Entrypoint, + /// Labels for user defined functions + Function(FunctionId, Option), + /// Labels for intrinsic procedures + Procedure(ProcedureId), +} + +impl std::fmt::Display for LabelType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + LabelType::Function(function_id, block_id) => { + if let Some(block_id) = block_id { + write!(f, "Function({:?}, {:?})", function_id, block_id) + } else { + write!(f, "Function({:?})", function_id) + } + } + LabelType::Entrypoint => write!(f, "Entrypoint"), + LabelType::Procedure(procedure_id) => write!(f, "Procedure({:?})", procedure_id), + } + } +} + /// An identifier for a location in the code. /// /// It is assumed that an entity will keep a map /// of labels to Opcode locations. -pub(crate) type Label = String; +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub(crate) struct Label { + pub(crate) label_type: LabelType, + pub(crate) section: Option, +} + +impl Label { + pub(crate) fn add_section(&self, section: usize) -> Self { + Label { label_type: self.label_type, section: Some(section) } + } + + pub(crate) fn function(func_id: FunctionId) -> Self { + Label { label_type: LabelType::Function(func_id, None), section: None } + } + + pub(crate) fn block(func_id: FunctionId, block_id: BasicBlockId) -> Self { + Label { label_type: LabelType::Function(func_id, Some(block_id)), section: None } + } + + pub(crate) fn entrypoint() -> Self { + Label { label_type: LabelType::Entrypoint, section: None } + } + + pub(crate) fn procedure(procedure_id: ProcedureId) -> Self { + Label { label_type: LabelType::Procedure(procedure_id), section: None } + } +} + +impl std::fmt::Display for Label { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(section) = self.section { + write!(f, "{:?} - {}", self.label_type, section) + } else { + write!(f, "{:?}", self.label_type) + } + } +} /// Pointer to a unresolved Jump instruction in /// the bytecode. pub(crate) type JumpInstructionPosition = OpcodeLocation; @@ -90,7 +154,7 @@ impl BrilligArtifact { /// Gets the first unresolved function call of this artifact. pub(crate) fn first_unresolved_function_call(&self) -> Option