Skip to content

Commit

Permalink
feat: When debugging, step into Brillig blocks and execute opcode by …
Browse files Browse the repository at this point in the history
…opcode
  • Loading branch information
ggiraldez committed Oct 13, 2023
1 parent f20d0e1 commit 621b160
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 26 deletions.
9 changes: 9 additions & 0 deletions acvm-repo/acvm/src/pwg/brillig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,20 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
Ok(Self { vm, acir_index })
}

pub(super) fn program_counter(&self) -> usize {
self.vm.program_counter()
}

pub(super) fn solve(&mut self) -> Result<BrilligSolverStatus, OpcodeResolutionError> {
let status = self.vm.process_opcodes();
self.handle_vm_status(status)
}

pub(super) fn step(&mut self) -> Result<BrilligSolverStatus, OpcodeResolutionError> {
let status = self.vm.process_opcode();
self.handle_vm_status(status)
}

fn handle_vm_status(
&self,
vm_status: VMStatus,
Expand Down
71 changes: 71 additions & 0 deletions acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,20 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
self.instruction_pointer
}

pub fn location(&self) -> Option<OpcodeLocation> {
if self.instruction_pointer >= self.opcodes.len() {
// evaluation finished
None
} else if let Some(solver) = &self.brillig_solver {
Some(OpcodeLocation::Brillig {
acir_index: self.instruction_pointer,
brillig_index: solver.program_counter(),
})
} else {
Some(OpcodeLocation::Acir(self.instruction_pointer))
}
}

/// Finalize the ACVM execution, returning the resulting [`WitnessMap`].
pub fn finalize(self) -> WitnessMap {
if self.status != ACVMStatus::Solved {
Expand Down Expand Up @@ -263,6 +277,28 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
res => res.map(|_| ()),
},
};
self.handle_resolution(resolution)
}

pub fn step_opcode(&mut self) -> ACVMStatus {
match &self.opcodes[self.instruction_pointer] {
Opcode::Brillig(_) => {
let resolution = match self.step_brillig_opcode() {
Ok(BrilligSolverStatus::ForeignCallWait(foreign_call)) => {
return self.wait_for_foreign_call(foreign_call)
}
Ok(BrilligSolverStatus::InProgress) => {
return self.status(ACVMStatus::InProgress)
}
res => res.map(|_| ()),
};
self.handle_resolution(resolution)
}
_ => self.solve_opcode(),
}
}

fn handle_resolution(&mut self, resolution: Result<(), OpcodeResolutionError>) -> ACVMStatus {
match resolution {
Ok(()) => {
self.instruction_pointer += 1;
Expand Down Expand Up @@ -331,6 +367,41 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}
}
}

fn step_brillig_opcode(&mut self) -> Result<BrilligSolverStatus, OpcodeResolutionError> {
let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else {
unreachable!("Not executing a Brillig opcode");
};
let witness = &mut self.witness_map;

// Try to use the cached `BrilligSolver` when stepping through opcodes
let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() {
Some(solver) => solver,
None => {
if BrilligSolver::<B>::should_skip(witness, brillig)? {
return BrilligSolver::<B>::zero_out_brillig_outputs(witness, brillig)
.map(|_| BrilligSolverStatus::Finished);
}
BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?
}
};
let status = solver.step()?;
match status {
BrilligSolverStatus::ForeignCallWait(_) => {
// Cache the current state of the solver
self.brillig_solver = Some(solver);
}
BrilligSolverStatus::InProgress => {
// Cache the current state of the solver
self.brillig_solver = Some(solver);
}
BrilligSolverStatus::Finished => {
// Write execution outputs
solver.finalize(witness, brillig)?;
}
};
Ok(status)
}
}

// Returns the concrete value for a particular witness
Expand Down
55 changes: 31 additions & 24 deletions tooling/debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ struct DebugContext<'backend, B: BlackBoxFunctionSolver> {

impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> {
fn step_opcode(&mut self) -> Result<SolveResult, NargoError> {
let solver_status = self.acvm.as_mut().unwrap().solve_opcode();
let solver_status = self.acvm.as_mut().unwrap().step_opcode();

match solver_status {
self.handle_acvm_status(solver_status)
}

fn handle_acvm_status(&mut self, status: ACVMStatus) -> Result<SolveResult, NargoError> {
match status {
ACVMStatus::Solved => Ok(SolveResult::Done),
ACVMStatus::InProgress => Ok(SolveResult::Ok),
ACVMStatus::Failure(error) => {
Expand Down Expand Up @@ -67,30 +71,36 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> {

fn show_current_vm_status(&self) {
let acvm = self.acvm.as_ref().unwrap();
let ip = acvm.instruction_pointer();
let location = acvm.location();
let opcodes = acvm.opcodes();
if ip >= opcodes.len() {
println!("Finished execution");
} else {
println!("Stopped at opcode {}: {}", ip, opcodes[ip]);
Self::show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact);
match location {
None => println!("Finished execution"),
Some(location) => {
match location {
OpcodeLocation::Acir(ip) => {
println!("Stopped at opcode {}: {}", ip, opcodes[ip])
}
OpcodeLocation::Brillig { acir_index: ip, brillig_index } => println!(
"Stopped at opcode {} in Brillig block {}: {}",
brillig_index, ip, opcodes[ip]
),
}
Self::show_source_code_location(&location, &self.debug_artifact);
}
}
}

fn show_source_code_location(location: &OpcodeLocation, debug_artifact: &DebugArtifact) {
let locations = debug_artifact.debug_symbols[0].opcode_location(&location);
match locations {
Some(locations) => {
for loc in locations {
let file = &debug_artifact.file_map[&loc.file];
let source = &file.source.as_str();
let start = loc.span.start() as usize;
let end = loc.span.end() as usize;
println!("At {}:{start}-{end}", file.path.as_path().display());
println!("\n{}\n", &source[start..end]);
}
let locations = debug_artifact.debug_symbols[0].opcode_location(location);
if let Some(locations) = locations {
for loc in locations {
let file = &debug_artifact.file_map[&loc.file];
let source = &file.source.as_str();
let start = loc.span.start() as usize;
let end = loc.span.end() as usize;
println!("At {}:{start}-{end}", file.path.as_path().display());
println!("\n{}\n", &source[start..end]);
}
None => {}
}
}

Expand Down Expand Up @@ -140,10 +150,7 @@ pub fn debug_circuit<B: BlackBoxFunctionSolver>(
context.borrow().show_current_vm_status();

let handle_result = |result| {
solved.set(match result {
SolveResult::Done => true,
_ => false,
});
solved.set(matches!(result, SolveResult::Done));
Ok(map_command_status(result))
};

Expand Down
2 changes: 0 additions & 2 deletions tooling/nargo_cli/src/cli/debug_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use noirc_abi::InputMap;
use noirc_driver::{CompileOptions, CompiledProgram};
use noirc_frontend::graph::CrateName;

use noir_debugger;

use super::compile_cmd::compile_bin_package;
use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir};
use super::NargoConfig;
Expand Down

0 comments on commit 621b160

Please sign in to comment.