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: Avoid incrementing reference counts in some cases #6568

Merged
merged 8 commits into from
Nov 21, 2024
23 changes: 15 additions & 8 deletions compiler/noirc_evaluator/src/ssa/function_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,37 +442,44 @@ impl FunctionBuilder {
/// within the given value. If the given value is not an array and does not contain
/// any arrays, this does nothing.
pub(crate) fn increment_array_reference_count(&mut self, value: ValueId) {
self.update_array_reference_count(value, true);
self.update_array_reference_count(value, true, true);
}

/// Insert instructions to decrement the reference count of any array(s) stored
/// within the given value. If the given value is not an array and does not contain
/// any arrays, this does nothing.
pub(crate) fn decrement_array_reference_count(&mut self, value: ValueId) {
self.update_array_reference_count(value, false);
self.update_array_reference_count(value, false, true);
}

/// Increment or decrement the given value's reference count if it is an array.
/// If it is not an array, this does nothing. Note that inc_rc and dec_rc instructions
/// are ignored outside of unconstrained code.
fn update_array_reference_count(&mut self, value: ValueId, increment: bool) {
pub(crate) fn update_array_reference_count(
&mut self,
value: ValueId,
increment: bool,
found_ref: bool,
) {
match self.type_of_value(value) {
Type::Numeric(_) => (),
Type::Function => (),
Type::Reference(element) => {
if element.contains_an_array() {
let reference = value;
let value = self.insert_load(reference, element.as_ref().clone());
self.update_array_reference_count(value, increment);
self.update_array_reference_count(value, increment, true);
}
}
Type::Array(..) | Type::Slice(..) => {
// If there are nested arrays or slices, we wait until ArrayGet
// is issued to increment the count of that array.
if increment {
self.insert_inc_rc(value);
} else {
self.insert_dec_rc(value);
if found_ref {
if increment {
self.insert_inc_rc(value);
} else {
self.insert_dec_rc(value);
}
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ impl<'a> FunctionContext<'a> {
/// Always returns a Value::Mutable wrapping the allocate instruction.
pub(super) fn new_mutable_variable(&mut self, value_to_store: ValueId) -> Value {
let element_type = self.builder.current_function.dfg.type_of_value(value_to_store);
self.builder.increment_array_reference_count(value_to_store);
let alloc = self.builder.insert_allocate(element_type);
self.builder.insert_store(alloc, value_to_store);
let typ = self.builder.type_of_value(value_to_store);
Expand Down Expand Up @@ -735,7 +736,7 @@ impl<'a> FunctionContext<'a> {
// Reference counting in brillig relies on us incrementing reference
// counts when arrays/slices are constructed or indexed.
// Thus, if we dereference an lvalue which happens to be array/slice we should increment its reference counter.
self.builder.increment_array_reference_count(reference);
// self.builder.increment_array_reference_count(reference);
self.builder.insert_load(reference, element_type).into()
})
}
Expand Down Expand Up @@ -916,7 +917,9 @@ impl<'a> FunctionContext<'a> {
let parameters = self.builder.current_function.dfg.block_parameters(entry).to_vec();

for parameter in parameters {
self.builder.increment_array_reference_count(parameter);
// Use `update_array_reference_count` here to avoid reference counts for
// immutable arrays that aren't behind references.
self.builder.update_array_reference_count(parameter, true, false);
}

entry
Expand All @@ -933,7 +936,7 @@ impl<'a> FunctionContext<'a> {
dropped_parameters.retain(|parameter| !terminator_args.contains(parameter));

for parameter in dropped_parameters {
self.builder.decrement_array_reference_count(parameter);
self.builder.update_array_reference_count(parameter, false, false);
}
}

Expand Down
5 changes: 2 additions & 3 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@
/// br loop_entry(v0)
/// loop_entry(i: Field):
/// v2 = lt i v1
/// brif v2, then: loop_body, else: loop_end

Check warning on line 475 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// loop_body():
/// v3 = ... codegen body ...
/// v4 = add 1, i
Expand Down Expand Up @@ -533,7 +533,7 @@
///
/// ```text
/// v0 = ... codegen cond ...
/// brif v0, then: then_block, else: else_block

Check warning on line 536 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// then_block():
/// v1 = ... codegen a ...
/// br end_if(v1)
Expand All @@ -548,7 +548,7 @@
///
/// ```text
/// v0 = ... codegen cond ...
/// brif v0, then: then_block, else: end_if

Check warning on line 551 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// then_block:
/// v1 = ... codegen a ...
/// br end_if()
Expand Down Expand Up @@ -665,12 +665,11 @@
values = values.map(|value| {
let value = value.eval(self);

// Make sure to increment array reference counts on each let binding
self.builder.increment_array_reference_count(value);

Tree::Leaf(if let_expr.mutable {
self.new_mutable_variable(value)
} else {
// `new_mutable_variable` already increments rcs internally
self.builder.increment_array_reference_count(value);
value::Value::Normal(value)
})
});
Expand Down
Loading