Skip to content

Commit

Permalink
Merge 63aa63d into 046fec7
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Nov 11, 2024
2 parents 046fec7 + 63aa63d commit e2ec5c9
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 64 deletions.
115 changes: 73 additions & 42 deletions compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use noirc_frontend::{
hir_def::{function::FunctionSignature, types::Type as HirType},
monomorphization::ast::Program,
};
use opt::unrolling::UnrollMode;
use tracing::{span, Level};

use self::{
Expand Down Expand Up @@ -86,48 +87,14 @@ pub(crate) fn optimize_into_acir(
let ssa_gen_span = span!(Level::TRACE, "ssa_generation");
let ssa_gen_span_guard = ssa_gen_span.enter();

let mut ssa = SsaBuilder::new(
let builder = SsaBuilder::new(
program,
options.enable_ssa_logging,
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:")
// 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")
.try_run_pass(
Ssa::evaluate_static_assert_and_assert_constant,
"After `static_assert` and `assert_constant`:",
)?
.try_run_pass(Ssa::unroll_loops_iteratively, "After 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 mem2reg once more with the flattened CFG to catch any remaining loads/stores
.run_pass(Ssa::mem2reg, "After 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:",
)
.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:")
.finish();
)?;
let mut ssa = optimize_ssa(builder, options.inliner_aggressiveness)?;

let ssa_level_warnings = if options.skip_underconstrained_check {
vec![]
Expand All @@ -149,6 +116,71 @@ pub(crate) fn optimize_into_acir(
Ok(ArtifactsAndWarnings(artifacts, ssa_level_warnings))
}

fn optimize_ssa(builder: SsaBuilder, inliner_aggressiveness: i64) -> Result<Ssa, RuntimeError> {
let builder = builder
.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(inliner_aggressiveness), "After Inlining:")
.run_pass(
|ssa| ssa.inline_const_brillig_calls(inliner_aggressiveness),
"After Inlining Const Brillig Calls:",
);
let ssa = optimize_ssa_after_inline_const_brillig_calls(
builder,
inliner_aggressiveness,
true, // inline functions with no predicates
UnrollMode::Acir,
)?;
Ok(ssa)
}

fn optimize_ssa_after_inline_const_brillig_calls(
builder: SsaBuilder,
inliner_aggressiveness: i64,
inline_functions_with_no_predicates: bool,
unroll_mode: UnrollMode,
) -> Result<Ssa, RuntimeError> {
let builder = builder
// 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")
.try_run_pass(
Ssa::evaluate_static_assert_and_assert_constant,
"After `static_assert` and `assert_constant`:",
)?
.try_run_pass(|ssa| Ssa::unroll_loops_iteratively(ssa, unroll_mode), "After 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 mem2reg once more with the flattened CFG to catch any remaining loads/stores
.run_pass(Ssa::mem2reg, "After Mem2Reg (2nd):");
let builder = if inline_functions_with_no_predicates {
// 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.
builder.run_pass(
|ssa| ssa.inline_functions_with_no_predicates(inliner_aggressiveness),
"After Inlining:",
)
} else {
builder
};
let ssa = builder
.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:")
.finish();
Ok(ssa)
}

// Helper to time SSA passes
fn time<T>(name: &str, print_timings: bool, f: impl FnOnce() -> T) -> T {
let start_time = chrono::Utc::now().time();
Expand Down Expand Up @@ -428,11 +460,10 @@ impl SsaBuilder {
}

/// The same as `run_pass` but for passes that may fail
fn try_run_pass(
mut self,
pass: fn(Ssa) -> Result<Ssa, RuntimeError>,
msg: &str,
) -> Result<Self, RuntimeError> {
fn try_run_pass<F>(mut self, pass: F, msg: &str) -> Result<Self, RuntimeError>
where
F: FnOnce(Ssa) -> Result<Ssa, RuntimeError>,
{
self.ssa = time(msg, self.print_codegen_timings, || pass(self.ssa))?;
Ok(self.print(msg))
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ struct ConditionalContext {
call_stack: CallStack,
}

fn flatten_function_cfg(function: &mut Function, no_predicates: &HashMap<FunctionId, bool>) {
pub(crate) fn flatten_function_cfg(
function: &mut Function,
no_predicates: &HashMap<FunctionId, bool>,
) {
// This pass may run forever on a brillig function.
// Analyze will check if the predecessors have been processed and push the block to the back of
// the queue. This loops forever if there are still any loops present in the program.
Expand Down
Loading

0 comments on commit e2ec5c9

Please sign in to comment.