From 55999ffb796390997a55745da51e4c8b91f091e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Fri, 2 Aug 2024 09:38:41 +0200 Subject: [PATCH] feat(profiler): Add support for brillig functions in opcodes-flamegraph (#7698) The opcodes-flamegraph command of the profiler now also profiles brillig opcode generation. Sample output: ![0_brillig_opcodes](https://github.com/user-attachments/assets/52bc6413-f3e0-4972-b2fb-156f908cc8b1) --- .../profiler/src/cli/gates_flamegraph_cmd.rs | 34 ++++- .../src/cli/opcodes_flamegraph_cmd.rs | 143 ++++++++++++++++-- .../tooling/profiler/src/flamegraph.rs | 111 ++++++++------ .../tooling/profiler/src/opcode_formatter.rs | 121 +++++++++++++-- 4 files changed, 330 insertions(+), 79 deletions(-) diff --git a/noir/noir-repo/tooling/profiler/src/cli/gates_flamegraph_cmd.rs b/noir/noir-repo/tooling/profiler/src/cli/gates_flamegraph_cmd.rs index f465408a8d8..e072c63f274 100644 --- a/noir/noir-repo/tooling/profiler/src/cli/gates_flamegraph_cmd.rs +++ b/noir/noir-repo/tooling/profiler/src/cli/gates_flamegraph_cmd.rs @@ -1,13 +1,15 @@ use std::path::{Path, PathBuf}; +use acir::circuit::OpcodeLocation; use clap::Args; use color_eyre::eyre::{self, Context}; use noirc_artifacts::debug::DebugArtifact; -use crate::flamegraph::{FlamegraphGenerator, InfernoFlamegraphGenerator}; +use crate::flamegraph::{FlamegraphGenerator, InfernoFlamegraphGenerator, Sample}; use crate::fs::read_program_from_file; use crate::gates_provider::{BackendGatesProvider, GatesProvider}; +use crate::opcode_formatter::AcirOrBrilligOpcode; #[derive(Debug, Clone, Args)] pub(crate) struct GatesFlamegraphCommand { @@ -76,9 +78,20 @@ fn run_with_provider( func_gates.circuit_size ); + let samples = func_gates + .gates_per_opcode + .into_iter() + .zip(bytecode.opcodes) + .enumerate() + .map(|(index, (gates, opcode))| Sample { + opcode: AcirOrBrilligOpcode::Acir(opcode), + call_stack: vec![OpcodeLocation::Acir(index)], + count: gates, + }) + .collect(); + flamegraph_generator.generate_flamegraph( - func_gates.gates_per_opcode, - bytecode.opcodes, + samples, &debug_artifact.debug_symbols[func_idx], &debug_artifact, artifact_path.to_str().unwrap(), @@ -92,7 +105,10 @@ fn run_with_provider( #[cfg(test)] mod tests { - use acir::circuit::{Circuit, Opcode, Program}; + use acir::{ + circuit::{Circuit, Program}, + AcirField, + }; use color_eyre::eyre::{self}; use fm::codespan_files::Files; use noirc_artifacts::program::ProgramArtifact; @@ -102,7 +118,10 @@ mod tests { path::{Path, PathBuf}, }; - use crate::gates_provider::{BackendGatesReport, BackendGatesResponse, GatesProvider}; + use crate::{ + flamegraph::Sample, + gates_provider::{BackendGatesReport, BackendGatesResponse, GatesProvider}, + }; struct TestGateProvider { mock_responses: HashMap, @@ -123,10 +142,9 @@ mod tests { struct TestFlamegraphGenerator {} impl super::FlamegraphGenerator for TestFlamegraphGenerator { - fn generate_flamegraph<'files, F>( + fn generate_flamegraph<'files, F: AcirField>( &self, - _samples_per_opcode: Vec, - _opcodes: Vec>, + _samples: Vec>, _debug_symbols: &DebugInfo, _files: &'files impl Files<'files, FileId = fm::FileId>, _artifact_name: &str, diff --git a/noir/noir-repo/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs b/noir/noir-repo/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs index e1dc1464f6f..8515cf24ef7 100644 --- a/noir/noir-repo/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs +++ b/noir/noir-repo/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs @@ -1,12 +1,14 @@ use std::path::{Path, PathBuf}; +use acir::circuit::{Circuit, Opcode, OpcodeLocation}; use clap::Args; use color_eyre::eyre::{self, Context}; use noirc_artifacts::debug::DebugArtifact; -use crate::flamegraph::{FlamegraphGenerator, InfernoFlamegraphGenerator}; +use crate::flamegraph::{FlamegraphGenerator, InfernoFlamegraphGenerator, Sample}; use crate::fs::read_program_from_file; +use crate::opcode_formatter::AcirOrBrilligOpcode; #[derive(Debug, Clone, Args)] pub(crate) struct OpcodesFlamegraphCommand { @@ -17,6 +19,10 @@ pub(crate) struct OpcodesFlamegraphCommand { /// The output folder for the flamegraph svg files #[clap(long, short)] output: String, + + /// Wether to skip brillig functions + #[clap(long, short, action)] + skip_brillig: bool, } pub(crate) fn run(args: OpcodesFlamegraphCommand) -> eyre::Result<()> { @@ -24,6 +30,7 @@ pub(crate) fn run(args: OpcodesFlamegraphCommand) -> eyre::Result<()> { &PathBuf::from(args.artifact_path), &InfernoFlamegraphGenerator { count_name: "opcodes".to_string() }, &PathBuf::from(args.output), + args.skip_brillig, ) } @@ -31,6 +38,7 @@ fn run_with_generator( artifact_path: &Path, flamegraph_generator: &Generator, output_path: &Path, + skip_brillig: bool, ) -> eyre::Result<()> { let mut program = read_program_from_file(artifact_path).context("Error reading program from file")?; @@ -42,41 +50,113 @@ fn run_with_generator( let debug_artifact: DebugArtifact = program.into(); for (func_idx, (func_name, bytecode)) in - function_names.into_iter().zip(bytecode.functions).enumerate() + function_names.into_iter().zip(bytecode.functions.iter()).enumerate() { - println!("Opcode count: {}", bytecode.opcodes.len()); + println!("Opcode count for {}: {}", func_name, bytecode.opcodes.len()); + + let samples = bytecode + .opcodes + .iter() + .enumerate() + .map(|(index, opcode)| Sample { + opcode: AcirOrBrilligOpcode::Acir(opcode.clone()), + call_stack: vec![OpcodeLocation::Acir(index)], + count: 1, + }) + .collect(); flamegraph_generator.generate_flamegraph( - bytecode.opcodes.iter().map(|_op| 1).collect(), - bytecode.opcodes, + samples, &debug_artifact.debug_symbols[func_idx], &debug_artifact, artifact_path.to_str().unwrap(), &func_name, - &Path::new(&output_path).join(Path::new(&format!("{}_opcodes.svg", &func_name))), + &Path::new(&output_path).join(Path::new(&format!("{}_acir_opcodes.svg", &func_name))), )?; } + if !skip_brillig { + for (brillig_fn_index, brillig_bytecode) in + bytecode.unconstrained_functions.into_iter().enumerate() + { + let acir_location = locate_brillig_call(brillig_fn_index, &bytecode.functions); + let Some((acir_fn_index, acir_opcode_index)) = acir_location else { + continue; + }; + + println!( + "Opcode count for brillig_{}: {}", + brillig_fn_index, + brillig_bytecode.bytecode.len() + ); + + let samples = brillig_bytecode + .bytecode + .into_iter() + .enumerate() + .map(|(brillig_index, opcode)| Sample { + opcode: AcirOrBrilligOpcode::Brillig(opcode), + call_stack: vec![OpcodeLocation::Brillig { + acir_index: acir_opcode_index, + brillig_index, + }], + count: 1, + }) + .collect(); + + flamegraph_generator.generate_flamegraph( + samples, + &debug_artifact.debug_symbols[acir_fn_index], + &debug_artifact, + artifact_path.to_str().unwrap(), + &format!("brillig_{}", brillig_fn_index), + &Path::new(&output_path) + .join(Path::new(&format!("{}_brillig_opcodes.svg", &brillig_fn_index))), + )?; + } + } + Ok(()) } +fn locate_brillig_call( + brillig_fn_index: usize, + acir_functions: &[Circuit], +) -> Option<(usize, usize)> { + for (acir_fn_index, acir_fn) in acir_functions.iter().enumerate() { + for (acir_opcode_index, acir_opcode) in acir_fn.opcodes.iter().enumerate() { + match acir_opcode { + Opcode::BrilligCall { id, .. } if (*id) as usize == brillig_fn_index => { + return Some((acir_fn_index, acir_opcode_index)) + } + _ => {} + } + } + } + None +} + #[cfg(test)] mod tests { - use acir::circuit::{Circuit, Opcode, Program}; + use acir::{ + circuit::{brillig::BrilligBytecode, Circuit, Opcode, Program}, + AcirField, FieldElement, + }; use color_eyre::eyre::{self}; use fm::codespan_files::Files; use noirc_artifacts::program::ProgramArtifact; use noirc_errors::debug_info::{DebugInfo, ProgramDebugInfo}; use std::{collections::BTreeMap, path::Path}; + use crate::flamegraph::Sample; + #[derive(Default)] struct TestFlamegraphGenerator {} impl super::FlamegraphGenerator for TestFlamegraphGenerator { - fn generate_flamegraph<'files, F>( + fn generate_flamegraph<'files, F: AcirField>( &self, - _samples_per_opcode: Vec, - _opcodes: Vec>, + _samples: Vec>, _debug_symbols: &DebugInfo, _files: &'files impl Files<'files, FileId = fm::FileId>, _artifact_name: &str, @@ -113,11 +193,50 @@ mod tests { let flamegraph_generator = TestFlamegraphGenerator::default(); - super::run_with_generator(&artifact_path, &flamegraph_generator, temp_dir.path()) + super::run_with_generator(&artifact_path, &flamegraph_generator, temp_dir.path(), true) .expect("should run without errors"); // Check that the output file was written to - let output_file = temp_dir.path().join("main_opcodes.svg"); + let output_file = temp_dir.path().join("main_acir_opcodes.svg"); + assert!(output_file.exists()); + } + + #[test] + fn brillig_test() { + let temp_dir = tempfile::tempdir().unwrap(); + + let artifact_path = temp_dir.path().join("test.json"); + + let acir: Vec> = + vec![Opcode::BrilligCall { id: 0, inputs: vec![], outputs: vec![], predicate: None }]; + + let artifact = ProgramArtifact { + noir_version: "0.0.0".to_string(), + hash: 27, + abi: noirc_abi::Abi::default(), + bytecode: Program { + functions: vec![Circuit { opcodes: acir, ..Circuit::default() }], + unconstrained_functions: vec![BrilligBytecode::default()], + }, + debug_symbols: ProgramDebugInfo { debug_infos: vec![DebugInfo::default()] }, + file_map: BTreeMap::default(), + names: vec!["main".to_string()], + }; + + // Write the artifact to a file + let artifact_file = std::fs::File::create(&artifact_path).unwrap(); + serde_json::to_writer(artifact_file, &artifact).unwrap(); + + let flamegraph_generator = TestFlamegraphGenerator::default(); + + super::run_with_generator(&artifact_path, &flamegraph_generator, temp_dir.path(), false) + .expect("should run without errors"); + + // Check that the output files ware written to + let output_file = temp_dir.path().join("main_acir_opcodes.svg"); + assert!(output_file.exists()); + + let output_file = temp_dir.path().join("0_brillig_opcodes.svg"); assert!(output_file.exists()); } } diff --git a/noir/noir-repo/tooling/profiler/src/flamegraph.rs b/noir/noir-repo/tooling/profiler/src/flamegraph.rs index 6b5a06405b3..17d39968117 100644 --- a/noir/noir-repo/tooling/profiler/src/flamegraph.rs +++ b/noir/noir-repo/tooling/profiler/src/flamegraph.rs @@ -1,7 +1,8 @@ use std::path::Path; use std::{collections::BTreeMap, io::BufWriter}; -use acir::circuit::{Opcode, OpcodeLocation}; +use acir::circuit::OpcodeLocation; +use acir::AcirField; use color_eyre::eyre::{self}; use fm::codespan_files::Files; use inferno::flamegraph::{from_lines, Options, TextTruncateDirection}; @@ -9,8 +10,17 @@ use noirc_errors::debug_info::DebugInfo; use noirc_errors::reporter::line_and_column_from_span; use noirc_errors::Location; +use crate::opcode_formatter::AcirOrBrilligOpcode; + use super::opcode_formatter::format_opcode; +#[derive(Debug)] +pub(crate) struct Sample { + pub(crate) opcode: AcirOrBrilligOpcode, + pub(crate) call_stack: Vec, + pub(crate) count: usize, +} + #[derive(Debug, Default)] pub(crate) struct FoldedStackItem { pub(crate) total_samples: usize, @@ -19,10 +29,9 @@ pub(crate) struct FoldedStackItem { pub(crate) trait FlamegraphGenerator { #[allow(clippy::too_many_arguments)] - fn generate_flamegraph<'files, F>( + fn generate_flamegraph<'files, F: AcirField>( &self, - samples_per_opcode: Vec, - opcodes: Vec>, + samples: Vec>, debug_symbols: &DebugInfo, files: &'files impl Files<'files, FileId = fm::FileId>, artifact_name: &str, @@ -36,19 +45,16 @@ pub(crate) struct InfernoFlamegraphGenerator { } impl FlamegraphGenerator for InfernoFlamegraphGenerator { - fn generate_flamegraph<'files, F>( + fn generate_flamegraph<'files, F: AcirField>( &self, - samples_per_opcode: Vec, - opcodes: Vec>, + samples: Vec>, debug_symbols: &DebugInfo, files: &'files impl Files<'files, FileId = fm::FileId>, artifact_name: &str, function_name: &str, output_path: &Path, ) -> eyre::Result<()> { - let folded_lines = - generate_folded_sorted_lines(samples_per_opcode, opcodes, debug_symbols, files); - + let folded_lines = generate_folded_sorted_lines(samples, debug_symbols, files); let flamegraph_file = std::fs::File::create(output_path)?; let flamegraph_writer = BufWriter::new(flamegraph_file); @@ -72,28 +78,29 @@ impl FlamegraphGenerator for InfernoFlamegraphGenerator { } } -fn generate_folded_sorted_lines<'files, F>( - samples_per_opcode: Vec, - opcodes: Vec>, +fn generate_folded_sorted_lines<'files, F: AcirField>( + samples: Vec>, debug_symbols: &DebugInfo, files: &'files impl Files<'files, FileId = fm::FileId>, ) -> Vec { // Create a nested hashmap with the stack items, folding the gates for all the callsites that are equal let mut folded_stack_items = BTreeMap::new(); - samples_per_opcode.into_iter().enumerate().for_each(|(opcode_index, gates)| { - let call_stack = debug_symbols.locations.get(&OpcodeLocation::Acir(opcode_index)); - let location_names = if let Some(call_stack) = call_stack { - call_stack - .iter() - .map(|location| location_to_callsite_label(*location, files)) - .chain(std::iter::once(format_opcode(&opcodes[opcode_index]))) - .collect::>() - } else { - vec!["unknown".to_string()] - }; + samples.into_iter().for_each(|sample| { + let mut location_names: Vec = sample + .call_stack + .into_iter() + .flat_map(|opcode_location| debug_symbols.locations.get(&opcode_location)) + .flatten() + .map(|location| location_to_callsite_label(*location, files)) + .collect(); + + if location_names.is_empty() { + location_names.push("unknown".to_string()); + } + location_names.push(format_opcode(&sample.opcode)); - add_locations_to_folded_stack_items(&mut folded_stack_items, location_names, gates); + add_locations_to_folded_stack_items(&mut folded_stack_items, location_names, sample.count); }); to_folded_sorted_lines(&folded_stack_items, Default::default()) @@ -129,7 +136,7 @@ fn location_to_callsite_label<'files>( fn add_locations_to_folded_stack_items( stack_items: &mut BTreeMap, locations: Vec, - gates: usize, + count: usize, ) { let mut child_map = stack_items; for (index, location) in locations.iter().enumerate() { @@ -138,7 +145,7 @@ fn add_locations_to_folded_stack_items( child_map = &mut current_item.nested_items; if index == locations.len() - 1 { - current_item.total_samples += gates; + current_item.total_samples += count; } } } @@ -180,7 +187,7 @@ fn to_folded_sorted_lines( #[cfg(test)] mod tests { use acir::{ - circuit::{opcodes::BlockId, Opcode, OpcodeLocation}, + circuit::{opcodes::BlockId, Opcode as AcirOpcode, OpcodeLocation}, native_types::Expression, FieldElement, }; @@ -188,6 +195,8 @@ mod tests { use noirc_errors::{debug_info::DebugInfo, Location, Span}; use std::{collections::BTreeMap, path::Path}; + use crate::{flamegraph::Sample, opcode_formatter::AcirOrBrilligOpcode}; + use super::generate_folded_sorted_lines; fn find_spans_for(source: &str, needle: &str) -> Vec { @@ -271,30 +280,36 @@ mod tests { BTreeMap::default(), ); - let samples_per_opcode = vec![10, 20, 30]; - - let expected_folded_sorted_lines = vec![ - "main.nr:2:9::fn main();main.nr:3:13::foo();main.nr:8:13::baz();main.nr:14:13::whatever();opcode::arithmetic 10".to_string(), - "main.nr:2:9::fn main();main.nr:4:13::bar();main.nr:11:13::whatever();opcode::arithmetic 20".to_string(), - "main.nr:2:9::fn main();main.nr:5:13::whatever();opcode::memory::init 30".to_string(), + let samples: Vec> = vec![ + Sample { + opcode: AcirOrBrilligOpcode::Acir(AcirOpcode::AssertZero(Expression::default())), + call_stack: vec![OpcodeLocation::Acir(0)], + count: 10, + }, + Sample { + opcode: AcirOrBrilligOpcode::Acir(AcirOpcode::AssertZero(Expression::default())), + call_stack: vec![OpcodeLocation::Acir(1)], + count: 20, + }, + Sample { + opcode: AcirOrBrilligOpcode::Acir(AcirOpcode::MemoryInit { + block_id: BlockId(0), + init: vec![], + block_type: acir::circuit::opcodes::BlockType::Memory, + }), + call_stack: vec![OpcodeLocation::Acir(2)], + count: 30, + }, ]; - let opcodes: Vec> = vec![ - Opcode::AssertZero(Expression::default()), - Opcode::AssertZero(Expression::default()), - Opcode::MemoryInit { - block_id: BlockId(0), - init: vec![], - block_type: acir::circuit::opcodes::BlockType::Memory, - }, + let expected_folded_sorted_lines = vec![ + "main.nr:2:9::fn main();main.nr:3:13::foo();main.nr:8:13::baz();main.nr:14:13::whatever();acir::arithmetic 10".to_string(), + "main.nr:2:9::fn main();main.nr:4:13::bar();main.nr:11:13::whatever();acir::arithmetic 20".to_string(), + "main.nr:2:9::fn main();main.nr:5:13::whatever();acir::memory::init 30".to_string(), ]; - let actual_folded_sorted_lines = generate_folded_sorted_lines( - samples_per_opcode, - opcodes, - &debug_info, - fm.as_file_map(), - ); + let actual_folded_sorted_lines = + generate_folded_sorted_lines(samples, &debug_info, fm.as_file_map()); assert_eq!(expected_folded_sorted_lines, actual_folded_sorted_lines); } diff --git a/noir/noir-repo/tooling/profiler/src/opcode_formatter.rs b/noir/noir-repo/tooling/profiler/src/opcode_formatter.rs index a33de42a0ff..772c87ad1cb 100644 --- a/noir/noir-repo/tooling/profiler/src/opcode_formatter.rs +++ b/noir/noir-repo/tooling/profiler/src/opcode_formatter.rs @@ -1,4 +1,12 @@ -use acir::circuit::{directives::Directive, opcodes::BlackBoxFuncCall, Opcode}; +use acir::brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode}; +use acir::circuit::{directives::Directive, opcodes::BlackBoxFuncCall, Opcode as AcirOpcode}; +use acir::AcirField; + +#[derive(Debug)] +pub(crate) enum AcirOrBrilligOpcode { + Acir(AcirOpcode), + Brillig(BrilligOpcode), +} fn format_blackbox_function(call: &BlackBoxFuncCall) -> String { match call { @@ -30,24 +38,115 @@ fn format_blackbox_function(call: &BlackBoxFuncCall) -> String { } } +fn format_blackbox_op(call: &BlackBoxOp) -> String { + match call { + BlackBoxOp::AES128Encrypt { .. } => "aes128_encrypt".to_string(), + BlackBoxOp::Sha256 { .. } => "sha256".to_string(), + BlackBoxOp::Blake2s { .. } => "blake2s".to_string(), + BlackBoxOp::Blake3 { .. } => "blake3".to_string(), + BlackBoxOp::SchnorrVerify { .. } => "schnorr_verify".to_string(), + BlackBoxOp::PedersenCommitment { .. } => "pedersen_commitment".to_string(), + BlackBoxOp::PedersenHash { .. } => "pedersen_hash".to_string(), + BlackBoxOp::EcdsaSecp256k1 { .. } => "ecdsa_secp256k1".to_string(), + BlackBoxOp::EcdsaSecp256r1 { .. } => "ecdsa_secp256r1".to_string(), + BlackBoxOp::MultiScalarMul { .. } => "multi_scalar_mul".to_string(), + BlackBoxOp::EmbeddedCurveAdd { .. } => "embedded_curve_add".to_string(), + BlackBoxOp::Keccak256 { .. } => "keccak256".to_string(), + BlackBoxOp::Keccakf1600 { .. } => "keccakf1600".to_string(), + BlackBoxOp::BigIntAdd { .. } => "big_int_add".to_string(), + BlackBoxOp::BigIntSub { .. } => "big_int_sub".to_string(), + BlackBoxOp::BigIntMul { .. } => "big_int_mul".to_string(), + BlackBoxOp::BigIntDiv { .. } => "big_int_div".to_string(), + BlackBoxOp::BigIntFromLeBytes { .. } => "big_int_from_le_bytes".to_string(), + BlackBoxOp::BigIntToLeBytes { .. } => "big_int_to_le_bytes".to_string(), + BlackBoxOp::Poseidon2Permutation { .. } => "poseidon2_permutation".to_string(), + BlackBoxOp::Sha256Compression { .. } => "sha256_compression".to_string(), + BlackBoxOp::ToRadix { .. } => "to_radix".to_string(), + } +} + fn format_directive_kind(directive: &Directive) -> String { match directive { Directive::ToLeRadix { .. } => "to_le_radix".to_string(), } } -fn format_opcode_kind(opcode: &Opcode) -> String { +fn format_acir_opcode_kind(opcode: &AcirOpcode) -> String { + match opcode { + AcirOpcode::AssertZero(_) => "arithmetic".to_string(), + AcirOpcode::BlackBoxFuncCall(call) => { + format!("blackbox::{}", format_blackbox_function(call)) + } + AcirOpcode::MemoryOp { .. } => "memory::op".to_string(), + AcirOpcode::MemoryInit { .. } => "memory::init".to_string(), + AcirOpcode::Directive(directive) => { + format!("directive::{}", format_directive_kind(directive)) + } + AcirOpcode::BrilligCall { id, .. } => format!("brillig_call({id})"), + AcirOpcode::Call { .. } => "acir_call".to_string(), + } +} + +fn format_binary_field_op(op: &BinaryFieldOp) -> String { + match op { + BinaryFieldOp::Add => "add".to_string(), + BinaryFieldOp::Sub => "sub".to_string(), + BinaryFieldOp::Mul => "mul".to_string(), + BinaryFieldOp::Div => "fdiv".to_string(), + BinaryFieldOp::IntegerDiv => "div".to_string(), + BinaryFieldOp::Equals => "eq".to_string(), + BinaryFieldOp::LessThan => "lt".to_string(), + BinaryFieldOp::LessThanEquals => "lte".to_string(), + } +} + +fn format_binary_int(op: &acir::brillig::BinaryIntOp) -> String { + match op { + BinaryIntOp::Add => "add".to_string(), + BinaryIntOp::Sub => "sub".to_string(), + BinaryIntOp::Mul => "mul".to_string(), + BinaryIntOp::Div => "div".to_string(), + BinaryIntOp::Equals => "eq".to_string(), + BinaryIntOp::LessThan => "lt".to_string(), + BinaryIntOp::LessThanEquals => "lte".to_string(), + BinaryIntOp::And => "and".to_string(), + BinaryIntOp::Or => "or".to_string(), + BinaryIntOp::Xor => "xor".to_string(), + BinaryIntOp::Shl => "shl".to_string(), + BinaryIntOp::Shr => "shr".to_string(), + } +} + +fn format_brillig_opcode_kind(opcode: &BrilligOpcode) -> String { match opcode { - Opcode::AssertZero(_) => "arithmetic".to_string(), - Opcode::BlackBoxFuncCall(call) => format!("blackbox::{}", format_blackbox_function(call)), - Opcode::MemoryOp { .. } => "memory::op".to_string(), - Opcode::MemoryInit { .. } => "memory::init".to_string(), - Opcode::Directive(directive) => format!("directive::{}", format_directive_kind(directive)), - Opcode::BrilligCall { .. } => "brillig_call".to_string(), - Opcode::Call { .. } => "acir_call".to_string(), + BrilligOpcode::BinaryFieldOp { op, .. } => format!("field::{}", format_binary_field_op(op)), + BrilligOpcode::BinaryIntOp { op, bit_size, .. } => { + format!("{bit_size}::{}", format_binary_int(op)) + } + BrilligOpcode::BlackBox(func) => format!("blackbox::{}", format_blackbox_op(func)), + BrilligOpcode::Call { .. } => "call".to_string(), + BrilligOpcode::CalldataCopy { .. } => "calldata_copy".to_string(), + BrilligOpcode::Cast { .. } => "cast".to_string(), + BrilligOpcode::ConditionalMov { .. } => "cmov".to_string(), + BrilligOpcode::Const { .. } => "const".to_string(), + BrilligOpcode::ForeignCall { function, .. } => format!("foreign_call({})", function), + BrilligOpcode::Jump { .. } => "jump".to_string(), + BrilligOpcode::JumpIf { .. } => "jump_if".to_string(), + BrilligOpcode::JumpIfNot { .. } => "jump_if_not".to_string(), + BrilligOpcode::Load { .. } => "load".to_string(), + BrilligOpcode::Mov { .. } => "mov".to_string(), + BrilligOpcode::Return => "return".to_string(), + BrilligOpcode::Stop { .. } => "stop".to_string(), + BrilligOpcode::Store { .. } => "store".to_string(), + BrilligOpcode::Trap { .. } => "trap".to_string(), } } -pub(crate) fn format_opcode(opcode: &Opcode) -> String { - format!("opcode::{}", format_opcode_kind(opcode)) +pub(crate) fn format_opcode(opcode: &AcirOrBrilligOpcode) -> String { + match opcode { + AcirOrBrilligOpcode::Acir(opcode) => format!("acir::{}", format_acir_opcode_kind(opcode)), + AcirOrBrilligOpcode::Brillig(opcode) => { + format!("brillig::{}", format_brillig_opcode_kind(opcode)) + } + } }