Skip to content
Closed
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
86 changes: 59 additions & 27 deletions acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
self.instruction_pointer
}

/// Returns the location for the next opcode to execute, or None if execution is finished
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 @@ -242,6 +257,10 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}

pub fn solve_opcode(&mut self) -> ACVMStatus {
self.step_opcode(false)
}

pub fn step_opcode(&mut self, step_into_brillig: bool) -> ACVMStatus {
let opcode = &self.opcodes[self.instruction_pointer];

let resolution = match opcode {
Expand All @@ -258,11 +277,15 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
let solver = self.block_solvers.entry(*block_id).or_default();
solver.solve_memory_op(op, &mut self.witness_map, predicate)
}
Opcode::Brillig(_) => match self.solve_brillig_opcode() {
Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call),
Opcode::Brillig(_) => match self.step_brillig_opcode(step_into_brillig) {
Ok(BrilligSolverStatus::ForeignCallWait(foreign_call)) => {
return self.wait_for_foreign_call(foreign_call)
}
Ok(BrilligSolverStatus::InProgress) => return self.status(ACVMStatus::InProgress),
res => res.map(|_| ()),
},
};

match resolution {
Ok(()) => {
self.instruction_pointer += 1;
Expand Down Expand Up @@ -296,40 +319,49 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}
}

fn solve_brillig_opcode(
fn step_brillig_opcode(
&mut self,
) -> Result<Option<ForeignCallWaitInfo>, OpcodeResolutionError> {
step_into: bool,
) -> 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;
if BrilligSolver::<B>::should_skip(witness, brillig)? {
BrilligSolver::<B>::zero_out_brillig_outputs(witness, brillig).map(|_| None)
} else {
// If we're resuming execution after resolving a foreign call then
// there will be a cached `BrilligSolver` to avoid recomputation.
let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() {
Some(solver) => solver,
None => {
BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?
}
};
match solver.solve()? {
BrilligSolverStatus::ForeignCallWait(foreign_call) => {
// Cache the current state of the solver
self.brillig_solver = Some(solver);
Ok(Some(foreign_call))

// Try to use the cached `BrilligSolver` which we will have if:
// - stepping into a Brillig block
// - resuming execution from a foreign call
let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() {
Some(solver) => solver,
None => {
if BrilligSolver::<B>::should_skip(witness, brillig)? {
// Exit early if the block doesn't need to be executed (false predicate)
return BrilligSolver::<B>::zero_out_brillig_outputs(witness, brillig)
.map(|_| BrilligSolverStatus::Finished);
}
BrilligSolverStatus::InProgress => {
BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?
}
};

let status = if step_into { solver.step()? } else { solver.solve()? };
match status {
BrilligSolverStatus::ForeignCallWait(_) => {
// Cache the current state of the solver
self.brillig_solver = Some(solver);
}
BrilligSolverStatus::InProgress => {
if !step_into {
unreachable!("Brillig solver still in progress")
}
BrilligSolverStatus::Finished => {
// Write execution outputs
solver.finalize(witness, brillig)?;
Ok(None)
}
// Cache the current state of the solver
self.brillig_solver = Some(solver);
}
}
BrilligSolverStatus::Finished => {
// Write execution outputs
solver.finalize(witness, brillig)?;
}
};
Ok(status)
}
}

Expand Down
21 changes: 18 additions & 3 deletions compiler/noirc_errors/src/debug_info.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use acvm::acir::circuit::OpcodeLocation;
use acvm::compiler::AcirTransformationMap;
use fm::FileId;

use serde_with::serde_as;
use serde_with::DisplayFromStr;
use std::collections::BTreeMap;
use std::collections::{BTreeMap,HashMap};
use std::mem;

use crate::Location;
Expand All @@ -17,11 +18,15 @@ pub struct DebugInfo {
/// that they should be serialized to/from strings.
#[serde_as(as = "BTreeMap<DisplayFromStr, _>")]
pub locations: BTreeMap<OpcodeLocation, Vec<Location>>,
pub variables: HashMap<String, u32>,
}

impl DebugInfo {
pub fn new(locations: BTreeMap<OpcodeLocation, Vec<Location>>) -> Self {
DebugInfo { locations }
pub fn new(
locations: BTreeMap<OpcodeLocation, Vec<Location>>,
variables: HashMap<String, u32>,
) -> Self {
Self { locations, variables }
}

/// Updates the locations map when the [`Circuit`][acvm::acir::circuit::Circuit] is modified.
Expand All @@ -42,4 +47,14 @@ impl DebugInfo {
pub fn opcode_location(&self, loc: &OpcodeLocation) -> Option<Vec<Location>> {
self.locations.get(loc).cloned()
}

pub fn get_file_ids(&self) -> Vec<FileId> {
self
.locations
.values()
.filter_map(|call_stack| {
call_stack.last().map(|location| location.file)
})
.collect()
}
}
3 changes: 2 additions & 1 deletion compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ pub fn create_circuit(
.map(|(index, locations)| (index, locations.into_iter().collect()))
.collect();

let mut debug_info = DebugInfo::new(locations);
let variables = context.debug_state.get_variables();
let mut debug_info = DebugInfo::new(locations, variables);

// Perform any ACIR-level optimizations
let (optimized_circuit, transformation_map) = acvm::compiler::optimize(circuit);
Expand Down
Loading