Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,7 @@ mod tests {
";

let ssa = Ssa::from_str(src).unwrap();
// Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation.
let mut ssa = ssa.dead_instruction_elimination();

let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

assert_eq!(
brillig.globals.len(),
Expand Down Expand Up @@ -443,11 +439,9 @@ mod tests {
let ssa = Ssa::from_str(src).unwrap();
// Need to run SSA pass that sets up Brillig array gets
let ssa = ssa.brillig_array_get_and_set();
// Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation.
let mut ssa = ssa.dead_instruction_elimination();
dbg!(ssa.used_globals_in_brillig_functions());

let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

assert_eq!(
brillig.globals.len(),
Expand Down Expand Up @@ -527,8 +521,6 @@ mod tests {
";

let ssa = Ssa::from_str(src).unwrap();
// Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation.
let mut ssa = ssa.dead_instruction_elimination();

// Show that the constants in each function have different SSA value IDs
for (func_id, function) in &ssa.functions {
Expand Down Expand Up @@ -557,8 +549,7 @@ mod tests {
}
}

let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

assert_eq!(brillig.globals.len(), 1, "Should have a single entry point");
for (func_id, artifact) in brillig.globals {
Expand Down Expand Up @@ -617,11 +608,8 @@ mod tests {
";

let ssa = Ssa::from_str(src).unwrap();
// Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation.
let mut ssa = ssa.dead_instruction_elimination();

let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

assert_eq!(
brillig.globals.len(),
Expand Down
13 changes: 3 additions & 10 deletions compiler/noirc_evaluator/src/brillig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::ssa::{
},
ssa_gen::Ssa,
};
use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet};
use fxhash::FxHashMap as HashMap;
use std::{borrow::Cow, collections::BTreeSet};

pub use self::brillig_ir::procedures::ProcedureId;
Expand Down Expand Up @@ -129,18 +129,11 @@ impl std::ops::Index<FunctionId> for Brillig {
}

impl Ssa {
/// Compile Brillig functions and ACIR functions reachable from them
#[tracing::instrument(level = "trace", skip_all)]
pub fn to_brillig(&self, options: &BrilligOptions) -> Brillig {
self.to_brillig_with_globals(options, HashMap::default())
}
let used_globals_map = self.used_globals_in_brillig_functions();

/// Compile Brillig functions and ACIR functions reachable from them
#[tracing::instrument(level = "trace", skip_all)]
pub(crate) fn to_brillig_with_globals(
&self,
options: &BrilligOptions,
used_globals_map: HashMap<FunctionId, HashSet<ValueId>>,
) -> Brillig {
// Collect all the function ids that are reachable from brillig
// That means all the functions marked as brillig and ACIR functions called by them
let brillig_reachable_function_ids = self
Expand Down
5 changes: 2 additions & 3 deletions compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,13 @@ where
let mut builder = builder.with_skip_passes(options.skip_passes.clone()).run_passes(primary)?;
let passed = std::mem::take(&mut builder.passed);
let files = builder.files;
let mut ssa = builder.finish();
let ssa = builder.finish();

let mut ssa_level_warnings = vec![];
drop(ssa_gen_span_guard);

let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = time("SSA to Brillig", options.print_codegen_timings, || {
ssa.to_brillig_with_globals(&options.brillig_options, used_globals_map)
ssa.to_brillig(&options.brillig_options)
});

let ssa_gen_span = span!(Level::TRACE, "ssa_generation");
Expand Down
8 changes: 2 additions & 6 deletions compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1537,9 +1537,7 @@ mod test {
}
";
let ssa = Ssa::from_str(src).unwrap();
let mut ssa = ssa.dead_instruction_elimination();
let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

let ssa = ssa.fold_constants_with_brillig(&brillig);
let ssa = ssa.remove_unreachable_functions();
Expand Down Expand Up @@ -1577,9 +1575,7 @@ mod test {
}
";
let ssa = Ssa::from_str(src).unwrap();
let mut ssa = ssa.dead_instruction_elimination();
let used_globals_map = std::mem::take(&mut ssa.used_globals);
let brillig = ssa.to_brillig_with_globals(&BrilligOptions::default(), used_globals_map);
let brillig = ssa.to_brillig(&BrilligOptions::default());

let ssa = ssa.fold_constants_with_brillig(&brillig);
let ssa = ssa.remove_unreachable_functions();
Expand Down
38 changes: 5 additions & 33 deletions compiler/noirc_evaluator/src/ssa/opt/die.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,45 +96,22 @@ impl Ssa {
flattened: bool,
skip_brillig: bool,
) -> (Ssa, DIEResult) {
let mut result = self
let result = self
.functions
.par_iter_mut()
.map(|(id, func)| {
let (used_globals, unused_params) =
func.dead_instruction_elimination(flattened, skip_brillig);
let unused_params = func.dead_instruction_elimination(flattened, skip_brillig);
let mut result = DIEResult::default();

if func.runtime().is_brillig() {
result.used_globals.insert(*id, used_globals);
}
result.unused_parameters.insert(*id, unused_params);

result
})
.reduce(DIEResult::default, |mut a, b| {
a.used_globals.extend(b.used_globals);
a.unused_parameters.extend(b.unused_parameters);
a
});

let globals = &self.functions[&self.main_id].dfg.globals;
for used_global_values in result.used_globals.values_mut() {
// DIE only tracks used instruction results, however, globals include constants.
// Back track globals for internal values which may be in use.
for (id, value) in globals.values_iter().rev() {
if used_global_values.contains(&id) {
if let Value::Instruction { instruction, .. } = &value {
let instruction = &globals[*instruction];
instruction.for_each_value(|value_id| {
used_global_values.insert(value_id);
});
}
}
}
}

self.used_globals = std::mem::take(&mut result.used_globals);

(self, result)
}
}
Expand All @@ -154,17 +131,16 @@ impl Function {
/// of its instructions are needed elsewhere.
///
/// # Returns
/// - The set of globals that were used in this function.
/// After processing all functions, the union of these sets enables determining the unused globals.
/// - A mapping of (block id -> unused parameters) for the given function.
/// This can be used by follow-up passes to prune unused parameters from blocks.
fn dead_instruction_elimination(
&mut self,
flattened: bool,
skip_brillig: bool,
) -> (HashSet<ValueId>, HashMap<BasicBlockId, Vec<ValueId>>) {
) -> HashMap<BasicBlockId, Vec<ValueId>> {
if skip_brillig && self.dfg.runtime().is_brillig() {
return (HashSet::default(), HashMap::default());
return HashMap::default();
}

let mut context = Context { flattened, ..Default::default() };
Expand Down Expand Up @@ -198,16 +174,12 @@ impl Function {

context.remove_rc_instructions(&mut self.dfg);

(
context.used_values.into_iter().filter(|value| self.dfg.is_global(*value)).collect(),
unused_params_per_block,
)
unused_params_per_block
}
}

#[derive(Default)]
struct DIEResult {
used_globals: HashMap<FunctionId, HashSet<ValueId>>,
unused_parameters: HashMap<FunctionId, HashMap<BasicBlockId, Vec<ValueId>>>,
}
/// Per function context for tracking unused values and which instructions to remove.
Expand Down
74 changes: 73 additions & 1 deletion compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use serde_with::serde_as;
use crate::ssa::ir::{
function::{Function, FunctionId},
map::AtomicCounter,
value::Value,
};
use noirc_frontend::hir_def::types::Type as HirType;

Expand All @@ -20,7 +21,7 @@ use super::ValueId;
pub struct Ssa {
#[serde_as(as = "Vec<(_, _)>")]
pub functions: BTreeMap<FunctionId, Function>,
pub used_globals: HashMap<FunctionId, HashSet<ValueId>>,
used_globals: HashMap<FunctionId, HashSet<ValueId>>,
pub main_id: FunctionId,
#[serde(skip)]
pub next_id: AtomicCounter<Function>,
Expand Down Expand Up @@ -101,6 +102,77 @@ impl Ssa {
pub(crate) fn is_entry_point(&self, function: FunctionId) -> bool {
function == self.main_id || self.functions[&function].runtime().is_entry_point()
}

pub(crate) fn used_globals_in_brillig_functions(
&self,
) -> HashMap<FunctionId, HashSet<ValueId>> {
fn add_value_to_globals_if_global(
function: &Function,
value_id: ValueId,
used_globals: &mut HashSet<ValueId>,
) {
if !function.dfg.is_global(value_id) {
return;
}

if !used_globals.insert(value_id) {
return;
}

// If we found a new global, its value could be an instruction that points to other globals.
let globals = &function.dfg.globals;
if let Value::Instruction { instruction, .. } = globals[value_id] {
let instruction = &globals[instruction];
instruction.for_each_value(|value_id| {
add_value_to_globals_if_global(function, value_id, used_globals);
});
}
}

let mut used_globals = HashMap::default();

for (function_id, function) in &self.functions {
if !function.runtime().is_brillig() {
continue;
}

let mut used_globals_in_function = HashSet::default();

for call_data in &function.dfg.data_bus.call_data {
add_value_to_globals_if_global(
function,
call_data.array_id,
&mut used_globals_in_function,
);
}

for block_id in function.reachable_blocks() {
let block = &function.dfg[block_id];
for instruction_id in block.instructions() {
let instruction = &function.dfg[*instruction_id];
instruction.for_each_value(|value_id| {
add_value_to_globals_if_global(
function,
value_id,
&mut used_globals_in_function,
);
});
}

block.unwrap_terminator().for_each_value(|value_id| {
add_value_to_globals_if_global(
function,
value_id,
&mut used_globals_in_function,
);
});
}

used_globals.insert(*function_id, used_globals_in_function);
}

used_globals
}
}

#[cfg(test)]
Expand Down
Loading