Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow filtering which SSA passes are printed #6636

Merged
merged 5 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use noirc_abi::{AbiParameter, AbiType, AbiValue};
use noirc_errors::{CustomDiagnostic, FileDiagnostic};
use noirc_evaluator::create_program;
use noirc_evaluator::errors::RuntimeError;
use noirc_evaluator::ssa::SsaProgramArtifact;
use noirc_evaluator::ssa::{SsaLogging, SsaProgramArtifact};
use noirc_frontend::debug::build_debug_crate_file;
use noirc_frontend::hir::def_map::{Contract, CrateDefMap};
use noirc_frontend::hir::Context;
Expand Down Expand Up @@ -70,6 +70,11 @@ pub struct CompileOptions {
#[arg(long, hide = true)]
pub show_ssa: bool,

/// Only show SSA passes whose name contains the provided string.
/// This setting takes precedence over `show_ssa` if it's not empty.
#[arg(long, hide = true)]
pub show_ssa_pass_name: Option<String>,

/// Emit the unoptimized SSA IR to file.
/// The IR will be dumped into the workspace target directory,
/// under `[compiled-package].ssa.json`.
Expand Down Expand Up @@ -585,7 +590,16 @@ pub fn compile_no_check(
}
let return_visibility = program.return_visibility;
let ssa_evaluator_options = noirc_evaluator::ssa::SsaEvaluatorOptions {
enable_ssa_logging: options.show_ssa,
ssa_logging: match &options.show_ssa_pass_name {
Some(string) => SsaLogging::Contains(string.clone()),
None => {
if options.show_ssa {
SsaLogging::All
} else {
SsaLogging::None
}
}
},
enable_brillig_logging: options.show_brillig,
force_brillig_output: options.force_brillig,
print_codegen_timings: options.benchmark_codegen,
Expand Down
86 changes: 50 additions & 36 deletions compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ mod opt;
pub(crate) mod parser;
pub mod ssa_gen;

#[derive(Debug, Clone)]
pub enum SsaLogging {
None,
All,
Contains(String),
}

pub struct SsaEvaluatorOptions {
/// Emit debug information for the intermediate SSA IR
pub enable_ssa_logging: bool,
pub ssa_logging: SsaLogging,

pub enable_brillig_logging: bool,

Expand Down Expand Up @@ -90,49 +97,49 @@ pub(crate) fn optimize_into_acir(

let mut ssa = SsaBuilder::new(
program,
options.enable_ssa_logging,
options.ssa_logging.clone(),
options.force_brillig_output,
options.print_codegen_timings,
&options.emit_ssa,
)?
.run_pass(Ssa::defunctionalize, "After Defunctionalization:")
.run_pass(Ssa::remove_paired_rc, "After Removing Paired rc_inc & rc_decs:")
.run_pass(Ssa::separate_runtime, "After Runtime Separation:")
.run_pass(Ssa::resolve_is_unconstrained, "After Resolving IsUnconstrained:")
.run_pass(|ssa| ssa.inline_functions(options.inliner_aggressiveness), "After Inlining (1st):")
.run_pass(Ssa::defunctionalize, "Defunctionalization")
aakoshh marked this conversation as resolved.
Show resolved Hide resolved
.run_pass(Ssa::remove_paired_rc, "Removing Paired rc_inc & rc_decs")
.run_pass(Ssa::separate_runtime, "Runtime Separation")
.run_pass(Ssa::resolve_is_unconstrained, "Resolving IsUnconstrained")
.run_pass(|ssa| ssa.inline_functions(options.inliner_aggressiveness), "Inlining (1st)")
// Run mem2reg with the CFG separated into blocks
.run_pass(Ssa::mem2reg, "After Mem2Reg (1st):")
.run_pass(Ssa::simplify_cfg, "After Simplifying (1st):")
.run_pass(Ssa::as_slice_optimization, "After `as_slice` optimization")
.run_pass(Ssa::mem2reg, "Mem2Reg (1st)")
.run_pass(Ssa::simplify_cfg, "Simplifying (1st)")
.run_pass(Ssa::as_slice_optimization, "`as_slice` optimization")
.try_run_pass(
Ssa::evaluate_static_assert_and_assert_constant,
"After `static_assert` and `assert_constant`:",
"`static_assert` and `assert_constant`",
)?
.run_pass(Ssa::loop_invariant_code_motion, "After Loop Invariant Code Motion:")
.run_pass(Ssa::loop_invariant_code_motion, "Loop Invariant Code Motion")
.try_run_pass(
|ssa| ssa.unroll_loops_iteratively(options.max_bytecode_increase_percent),
"After Unrolling:",
"Unrolling",
)?
.run_pass(Ssa::simplify_cfg, "After Simplifying (2nd):")
.run_pass(Ssa::flatten_cfg, "After Flattening:")
.run_pass(Ssa::remove_bit_shifts, "After Removing Bit Shifts:")
.run_pass(Ssa::simplify_cfg, "Simplifying (2nd)")
.run_pass(Ssa::flatten_cfg, "Flattening")
.run_pass(Ssa::remove_bit_shifts, "After Removing Bit Shifts")
// Run mem2reg once more with the flattened CFG to catch any remaining loads/stores
.run_pass(Ssa::mem2reg, "After Mem2Reg (2nd):")
.run_pass(Ssa::mem2reg, "Mem2Reg (2nd)")
// Run the inlining pass again to handle functions with `InlineType::NoPredicates`.
// Before flattening is run, we treat functions marked with the `InlineType::NoPredicates` as an entry point.
// This pass must come immediately following `mem2reg` as the succeeding passes
// may create an SSA which inlining fails to handle.
.run_pass(
|ssa| ssa.inline_functions_with_no_predicates(options.inliner_aggressiveness),
"After Inlining (2nd):",
"Inlining (2nd)",
)
.run_pass(Ssa::remove_if_else, "After Remove IfElse:")
.run_pass(Ssa::fold_constants, "After Constant Folding:")
.run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffectsIf removal:")
.run_pass(Ssa::fold_constants_using_constraints, "After Constraint Folding:")
.run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:")
.run_pass(Ssa::simplify_cfg, "After Simplifying:")
.run_pass(Ssa::array_set_optimization, "After Array Set Optimizations:")
.run_pass(Ssa::remove_if_else, "Remove IfElse")
.run_pass(Ssa::fold_constants, "Constant Folding")
.run_pass(Ssa::remove_enable_side_effects, "EnableSideEffectsIf removal")
.run_pass(Ssa::fold_constants_using_constraints, "Constraint Folding")
.run_pass(Ssa::dead_instruction_elimination, "Dead Instruction Elimination (1st)")
.run_pass(Ssa::simplify_cfg, "Simplifying:")
.run_pass(Ssa::array_set_optimization, "Array Set Optimizations")
.finish();

let ssa_level_warnings = if options.skip_underconstrained_check {
Expand All @@ -154,14 +161,11 @@ pub(crate) fn optimize_into_acir(

let ssa = SsaBuilder {
ssa,
print_ssa_passes: options.enable_ssa_logging,
ssa_logging: options.ssa_logging.clone(),
print_codegen_timings: options.print_codegen_timings,
}
.run_pass(
|ssa| ssa.fold_constants_with_brillig(&brillig),
"After Constant Folding with Brillig:",
)
.run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:")
.run_pass(|ssa| ssa.fold_constants_with_brillig(&brillig), "Inlining Brillig Calls Inlining")
.run_pass(Ssa::dead_instruction_elimination, "Dead Instruction Elimination (2nd)")
.finish();

drop(ssa_gen_span_guard);
Expand Down Expand Up @@ -419,14 +423,14 @@ fn split_public_and_private_inputs(
// This is just a convenience object to bundle the ssa with `print_ssa_passes` for debug printing.
struct SsaBuilder {
ssa: Ssa,
print_ssa_passes: bool,
ssa_logging: SsaLogging,
print_codegen_timings: bool,
}

impl SsaBuilder {
fn new(
program: Program,
print_ssa_passes: bool,
ssa_logging: SsaLogging,
force_brillig_runtime: bool,
print_codegen_timings: bool,
emit_ssa: &Option<PathBuf>,
Expand All @@ -441,7 +445,7 @@ impl SsaBuilder {
let ssa_path = emit_ssa.with_extension("ssa.json");
write_to_file(&serde_json::to_vec(&ssa).unwrap(), &ssa_path);
}
Ok(SsaBuilder { print_ssa_passes, print_codegen_timings, ssa }.print("Initial SSA:"))
Ok(SsaBuilder { ssa_logging, print_codegen_timings, ssa }.print("Initial SSA:"))
}

fn finish(self) -> Ssa {
Expand All @@ -467,9 +471,19 @@ impl SsaBuilder {
}

fn print(mut self, msg: &str) -> Self {
if self.print_ssa_passes {
let print_ssa_pass = match &self.ssa_logging {
SsaLogging::None => false,
SsaLogging::All => true,
SsaLogging::Contains(string) => {
let string = string.to_lowercase();
let string = string.strip_prefix("after ").unwrap_or(&string);
let string = string.strip_suffix(':').unwrap_or(string);
msg.to_lowercase().contains(string)
}
};
if print_ssa_pass {
self.ssa.normalize_ids();
println!("{msg}\n{}", self.ssa);
println!("After {msg}:\n{}", self.ssa);
}
self
}
Expand Down
Loading