From 95a41a693eb29bbb3ef22a5843e8af39f69740e6 Mon Sep 17 00:00:00 2001 From: Tom French Date: Sun, 9 Feb 2025 11:13:16 +0000 Subject: [PATCH 1/2] feat: remove foreign calls array from `BrilligVM` constructor --- acvm-repo/acvm/src/pwg/brillig.rs | 2 +- acvm-repo/brillig_vm/src/lib.rs | 25 ++-- .../noirc_evaluator/src/acir/acir_variable.rs | 132 ++++++++++++++++++ .../noirc_evaluator/src/brillig/brillig_ir.rs | 23 +-- .../src/ssa/opt/constant_folding.rs | 4 +- 5 files changed, 161 insertions(+), 25 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index a5f5783478e..a635cd92615 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -133,7 +133,7 @@ impl<'b, B: BlackBoxFunctionSolver, F: AcirField> BrilligSolver<'b, F, B> { // Instantiate a Brillig VM given the solved calldata // along with the Brillig bytecode. - let vm = VM::new(calldata, brillig_bytecode, vec![], bb_solver, profiling_active); + let vm = VM::new(calldata, brillig_bytecode, bb_solver, profiling_active); Ok(vm) } diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 8602f74e0d6..9a40022a3ba 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -107,7 +107,6 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { pub fn new( calldata: Vec, bytecode: &'a [Opcode], - foreign_call_results: Vec>, black_box_solver: &'a B, profiling_active: bool, ) -> Self { @@ -117,7 +116,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { calldata, program_counter: 0, foreign_call_counter: 0, - foreign_call_results, + foreign_call_results: Vec::new(), bytecode, status: VMStatus::InProgress, memory: Memory::default(), @@ -857,7 +856,7 @@ mod tests { // Start VM let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, &opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, &opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); @@ -908,7 +907,7 @@ mod tests { ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, &opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, &opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -977,7 +976,7 @@ mod tests { ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, &opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, &opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1050,7 +1049,7 @@ mod tests { }, ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1111,7 +1110,7 @@ mod tests { }, ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1158,7 +1157,7 @@ mod tests { Opcode::Mov { destination: MemoryAddress::direct(2), source: MemoryAddress::direct(0) }, ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1224,7 +1223,7 @@ mod tests { }, ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1321,7 +1320,7 @@ mod tests { .chain([equal_opcode, not_equal_opcode, less_than_opcode, less_than_equal_opcode]) .collect(); let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, &opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, &opcodes, &solver, false); // Calldata copy let status = vm.process_opcode(); @@ -1451,7 +1450,7 @@ mod tests { }, ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(vec![], opcodes, vec![], &solver, false); + let mut vm = VM::new(vec![], opcodes, &solver, false); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -1678,7 +1677,7 @@ mod tests { opcodes: &'a [Opcode], solver: &'a StubbedBlackBoxSolver, ) -> VM<'a, F, StubbedBlackBoxSolver> { - let mut vm = VM::new(calldata, opcodes, vec![], solver, false); + let mut vm = VM::new(calldata, opcodes, solver, false); brillig_execute(&mut vm); assert_eq!(vm.call_stack, vec![]); vm @@ -2366,7 +2365,7 @@ mod tests { ]; let solver = StubbedBlackBoxSolver::default(); - let mut vm = VM::new(calldata, &opcodes, vec![], &solver, false); + let mut vm = VM::new(calldata, &opcodes, &solver, false); vm.process_opcode(); vm.process_opcode(); diff --git a/compiler/noirc_evaluator/src/acir/acir_variable.rs b/compiler/noirc_evaluator/src/acir/acir_variable.rs index 6e1c2c450de..fdf19e77414 100644 --- a/compiler/noirc_evaluator/src/acir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/acir/acir_variable.rs @@ -1656,3 +1656,135 @@ fn fits_in_one_identity(expr: &Expression, width: ExpressionWid /// A Reference to an `AcirVarData` #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct AcirVar(usize); +<<<<<<< HEAD +||||||| parent of 91f98735b2 (feat: remove foreign calls array from `BrilligVM` constructor) + +/// Attempts to execute the provided [`Brillig`][`acvm::acir::brillig`] bytecode +/// +/// Returns the finished state of the Brillig VM if execution can complete. +/// +/// Returns `None` if complete execution of the Brillig bytecode is not possible. +fn execute_brillig>( + code: &[BrilligOpcode], + blackbox_solver: &B, + inputs: &[BrilligInputs], +) -> Option>> { + // Set input values + let mut calldata: Vec = Vec::new(); + + // Each input represents a constant or array of constants. + // Iterate over each input and push it into registers and/or memory. + for input in inputs { + match input { + BrilligInputs::Single(expr) => { + calldata.push(*expr.to_const()?); + } + BrilligInputs::Array(expr_arr) => { + // Attempt to fetch all array input values + for expr in expr_arr.iter() { + calldata.push(*expr.to_const()?); + } + } + BrilligInputs::MemoryArray(_) => { + return None; + } + } + } + + // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. + let profiling_active = false; + let mut vm = VM::new(calldata, code, Vec::new(), blackbox_solver, profiling_active); + + // Run the Brillig VM on these inputs, bytecode, etc! + let vm_status = vm.process_opcodes(); + + // Check the status of the Brillig VM. + // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. + // If it's finished then we can omit the opcode and just write in the return values. + match vm_status { + VMStatus::Finished { return_data_offset, return_data_size } => Some( + vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), + ), + VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), + VMStatus::Failure { .. } => { + // TODO: Return an error stating that the brillig function failed. + None + } + VMStatus::ForeignCallWait { .. } => { + // If execution can't complete then keep the opcode + + // TODO: We could bake in all the execution up to this point by replacing the inputs + // such that they initialize the registers/memory to the current values and then discard + // any opcodes prior to the one which performed this foreign call. + // + // Seems overkill for now however. + None + } + } +} +======= + +/// Attempts to execute the provided [`Brillig`][`acvm::acir::brillig`] bytecode +/// +/// Returns the finished state of the Brillig VM if execution can complete. +/// +/// Returns `None` if complete execution of the Brillig bytecode is not possible. +fn execute_brillig>( + code: &[BrilligOpcode], + blackbox_solver: &B, + inputs: &[BrilligInputs], +) -> Option>> { + // Set input values + let mut calldata: Vec = Vec::new(); + + // Each input represents a constant or array of constants. + // Iterate over each input and push it into registers and/or memory. + for input in inputs { + match input { + BrilligInputs::Single(expr) => { + calldata.push(*expr.to_const()?); + } + BrilligInputs::Array(expr_arr) => { + // Attempt to fetch all array input values + for expr in expr_arr.iter() { + calldata.push(*expr.to_const()?); + } + } + BrilligInputs::MemoryArray(_) => { + return None; + } + } + } + + // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. + let profiling_active = false; + let mut vm = VM::new(calldata, code, blackbox_solver, profiling_active); + + // Run the Brillig VM on these inputs, bytecode, etc! + let vm_status = vm.process_opcodes(); + + // Check the status of the Brillig VM. + // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. + // If it's finished then we can omit the opcode and just write in the return values. + match vm_status { + VMStatus::Finished { return_data_offset, return_data_size } => Some( + vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), + ), + VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), + VMStatus::Failure { .. } => { + // TODO: Return an error stating that the brillig function failed. + None + } + VMStatus::ForeignCallWait { .. } => { + // If execution can't complete then keep the opcode + + // TODO: We could bake in all the execution up to this point by replacing the inputs + // such that they initialize the registers/memory to the current values and then discard + // any opcodes prior to the one which performed this foreign call. + // + // Seems overkill for now however. + None + } + } +} +>>>>>>> 91f98735b2 (feat: remove foreign calls array from `BrilligVM` constructor) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 520fd5aad96..d25f7ddef85 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -353,7 +353,7 @@ pub(crate) mod tests { bytecode: &[BrilligOpcode], ) -> (VM<'_, FieldElement, DummyBlackBoxSolver>, usize, usize) { let profiling_active = false; - let mut vm = VM::new(calldata, bytecode, vec![], &DummyBlackBoxSolver, profiling_active); + let mut vm = VM::new(calldata, bytecode, &DummyBlackBoxSolver, profiling_active); let status = vm.process_opcodes(); if let VMStatus::Finished { return_data_offset, return_data_size } = status { @@ -427,15 +427,22 @@ pub(crate) mod tests { }); let bytecode: Vec> = context.artifact().finish().byte_code; + + let mut vm = VM::new(vec![], &bytecode, &DummyBlackBoxSolver, false); + let status = vm.process_opcodes(); + assert_eq!( + status, + VMStatus::ForeignCallWait { + function: "make_number_sequence".to_string(), + inputs: vec![ForeignCallParam::Single(FieldElement::from(12u128))] + } + ); + let number_sequence: Vec = (0_usize..12_usize).map(FieldElement::from).collect(); - let mut vm = VM::new( - vec![], - &bytecode, - vec![ForeignCallResult { values: vec![ForeignCallParam::Array(number_sequence)] }], - &DummyBlackBoxSolver, - false, - ); + let response = ForeignCallResult { values: vec![ForeignCallParam::Array(number_sequence)] }; + vm.resolve_foreign_call(response); + let status = vm.process_opcodes(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); } diff --git a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index 092b11ca3ee..4afbc036513 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -600,12 +600,10 @@ impl<'brillig> Context<'brillig> { } let bytecode = &generated_brillig.byte_code; - let foreign_call_results = Vec::new(); let pedantic_solving = true; let black_box_solver = Bn254BlackBoxSolver(pedantic_solving); let profiling_active = false; - let mut vm = - VM::new(calldata, bytecode, foreign_call_results, &black_box_solver, profiling_active); + let mut vm = VM::new(calldata, bytecode, &black_box_solver, profiling_active); let vm_status: VMStatus<_> = vm.process_opcodes(); let VMStatus::Finished { return_data_offset, return_data_size } = vm_status else { return EvaluationResult::CannotEvaluate; From eb817c448b2cbdb0865610f362db34f61ce644c3 Mon Sep 17 00:00:00 2001 From: Tom French Date: Mon, 10 Feb 2025 15:31:36 +0000 Subject: [PATCH 2/2] . --- .../noirc_evaluator/src/acir/acir_variable.rs | 132 ------------------ .../noirc_evaluator/src/acir/brillig_call.rs | 2 +- 2 files changed, 1 insertion(+), 133 deletions(-) diff --git a/compiler/noirc_evaluator/src/acir/acir_variable.rs b/compiler/noirc_evaluator/src/acir/acir_variable.rs index fdf19e77414..6e1c2c450de 100644 --- a/compiler/noirc_evaluator/src/acir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/acir/acir_variable.rs @@ -1656,135 +1656,3 @@ fn fits_in_one_identity(expr: &Expression, width: ExpressionWid /// A Reference to an `AcirVarData` #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct AcirVar(usize); -<<<<<<< HEAD -||||||| parent of 91f98735b2 (feat: remove foreign calls array from `BrilligVM` constructor) - -/// Attempts to execute the provided [`Brillig`][`acvm::acir::brillig`] bytecode -/// -/// Returns the finished state of the Brillig VM if execution can complete. -/// -/// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig>( - code: &[BrilligOpcode], - blackbox_solver: &B, - inputs: &[BrilligInputs], -) -> Option>> { - // Set input values - let mut calldata: Vec = Vec::new(); - - // Each input represents a constant or array of constants. - // Iterate over each input and push it into registers and/or memory. - for input in inputs { - match input { - BrilligInputs::Single(expr) => { - calldata.push(*expr.to_const()?); - } - BrilligInputs::Array(expr_arr) => { - // Attempt to fetch all array input values - for expr in expr_arr.iter() { - calldata.push(*expr.to_const()?); - } - } - BrilligInputs::MemoryArray(_) => { - return None; - } - } - } - - // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. - let profiling_active = false; - let mut vm = VM::new(calldata, code, Vec::new(), blackbox_solver, profiling_active); - - // Run the Brillig VM on these inputs, bytecode, etc! - let vm_status = vm.process_opcodes(); - - // Check the status of the Brillig VM. - // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. - // If it's finished then we can omit the opcode and just write in the return values. - match vm_status { - VMStatus::Finished { return_data_offset, return_data_size } => Some( - vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), - ), - VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), - VMStatus::Failure { .. } => { - // TODO: Return an error stating that the brillig function failed. - None - } - VMStatus::ForeignCallWait { .. } => { - // If execution can't complete then keep the opcode - - // TODO: We could bake in all the execution up to this point by replacing the inputs - // such that they initialize the registers/memory to the current values and then discard - // any opcodes prior to the one which performed this foreign call. - // - // Seems overkill for now however. - None - } - } -} -======= - -/// Attempts to execute the provided [`Brillig`][`acvm::acir::brillig`] bytecode -/// -/// Returns the finished state of the Brillig VM if execution can complete. -/// -/// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig>( - code: &[BrilligOpcode], - blackbox_solver: &B, - inputs: &[BrilligInputs], -) -> Option>> { - // Set input values - let mut calldata: Vec = Vec::new(); - - // Each input represents a constant or array of constants. - // Iterate over each input and push it into registers and/or memory. - for input in inputs { - match input { - BrilligInputs::Single(expr) => { - calldata.push(*expr.to_const()?); - } - BrilligInputs::Array(expr_arr) => { - // Attempt to fetch all array input values - for expr in expr_arr.iter() { - calldata.push(*expr.to_const()?); - } - } - BrilligInputs::MemoryArray(_) => { - return None; - } - } - } - - // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. - let profiling_active = false; - let mut vm = VM::new(calldata, code, blackbox_solver, profiling_active); - - // Run the Brillig VM on these inputs, bytecode, etc! - let vm_status = vm.process_opcodes(); - - // Check the status of the Brillig VM. - // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. - // If it's finished then we can omit the opcode and just write in the return values. - match vm_status { - VMStatus::Finished { return_data_offset, return_data_size } => Some( - vm.get_memory()[return_data_offset..(return_data_offset + return_data_size)].to_vec(), - ), - VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), - VMStatus::Failure { .. } => { - // TODO: Return an error stating that the brillig function failed. - None - } - VMStatus::ForeignCallWait { .. } => { - // If execution can't complete then keep the opcode - - // TODO: We could bake in all the execution up to this point by replacing the inputs - // such that they initialize the registers/memory to the current values and then discard - // any opcodes prior to the one which performed this foreign call. - // - // Seems overkill for now however. - None - } - } -} ->>>>>>> 91f98735b2 (feat: remove foreign calls array from `BrilligVM` constructor) diff --git a/compiler/noirc_evaluator/src/acir/brillig_call.rs b/compiler/noirc_evaluator/src/acir/brillig_call.rs index f927aabbdc2..f027a7b62f8 100644 --- a/compiler/noirc_evaluator/src/acir/brillig_call.rs +++ b/compiler/noirc_evaluator/src/acir/brillig_call.rs @@ -311,7 +311,7 @@ fn execute_brillig>( // Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode. let profiling_active = false; - let mut vm = VM::new(calldata, code, Vec::new(), blackbox_solver, profiling_active); + let mut vm = VM::new(calldata, code, blackbox_solver, profiling_active); // Run the Brillig VM on these inputs, bytecode, etc! let vm_status = vm.process_opcodes();