Skip to content

Commit 6255817

Browse files
committed
Insert the inc_rc during ssa_gen
1 parent daf392b commit 6255817

3 files changed

Lines changed: 50 additions & 43 deletions

File tree

compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/call.rs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,6 @@ pub(super) fn simplify_call(
236236
vector.pop_front().expect("There are no elements in this vector to be removed")
237237
});
238238

239-
// The popped elements are reused by `ValueId` from the source vector, so any
240-
// array-typed element still aliases the source's underlying memory. Bump the
241-
// reference count so a subsequent mutation through the popped value does not
242-
// mutate the source in place. The same invariant is enforced for plain indexing
243-
// by the `ownership` pass (see `handle_index`).
244-
inc_rc_array_results(&results, dfg, block, call_stack);
245-
246239
let new_vector_length =
247240
decrement_vector_length(arguments[0], dfg, block, call_stack);
248241

@@ -325,12 +318,6 @@ pub(super) fn simplify_call(
325318
results.push(vector.remove(index));
326319
}
327320

328-
// The removed elements are reused by `ValueId` from the source vector, so any
329-
// array-typed element still aliases the source's memory. Bump the RC to preserve
330-
// copy-on-write semantics. See `inc_rc_array_results` for the matching invariant
331-
// in `pop_front` / `pop_back`.
332-
inc_rc_array_results(&results, dfg, block, call_stack);
333-
334321
let new_vector = make_array(dfg, vector, typ, block, call_stack);
335322
results.insert(0, new_vector);
336323

@@ -682,27 +669,6 @@ fn decrement_vector_length(
682669
update_vector_length(vector_len, dfg, BinaryOp::Sub { unchecked: true }, block, call_stack)
683670
}
684671

685-
/// Emit `inc_rc` for each value whose type is an array or vector. Used by vector intrinsic
686-
/// simplifications that hand back `ValueId`s of elements from the source vector: those elements
687-
/// still alias the source's memory, so the reference count must be bumped to preserve
688-
/// copy-on-write semantics. No-op under the ACIR runtime, which does not track reference counts.
689-
fn inc_rc_array_results(
690-
values: &[ValueId],
691-
dfg: &mut DataFlowGraph,
692-
block: BasicBlockId,
693-
call_stack: CallStackId,
694-
) {
695-
if dfg.runtime().is_acir() {
696-
return;
697-
}
698-
for value in values {
699-
if dfg.type_of_value(*value).is_array() {
700-
let instruction = Instruction::IncrementRc { value: *value };
701-
dfg.insert_instruction_and_results(instruction, block, None, call_stack);
702-
}
703-
}
704-
}
705-
706672
/// Simplify a vector push back when the length is not known to equal capacity, ie. we don't
707673
/// know whether we to push new items and grow the capacity of the vector, or overwrite the
708674
/// next padding item.
@@ -789,12 +755,6 @@ fn simplify_vector_pop_back(
789755
vector.pop_back();
790756
}
791757

792-
// The popped elements still alias the source vector's memory (`array_get` reads a value
793-
// without bumping its reference count). Bump the RC for any array-typed element so that a
794-
// subsequent mutation through the popped value triggers copy-on-write instead of mutating
795-
// the source. See `inc_rc_array_results` for the matching invariant in `pop_front`.
796-
inc_rc_array_results(results.make_contiguous(), dfg, block, call_stack);
797-
798758
let new_vector = make_array(dfg, vector, vector_type, block, call_stack);
799759
results.push_front(new_vector);
800760

compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,54 @@ impl FunctionContext<'_> {
13341334
}
13351335
}
13361336

1337-
Ok(self.insert_call(function, arguments, &call.return_type, call.location))
1337+
let result = self.insert_call(function, arguments, &call.return_type, call.location);
1338+
self.codegen_intrinsic_inc_rc_results(function, &call.return_type, &result);
1339+
Ok(result)
1340+
}
1341+
1342+
/// For vector intrinsics that hand back an element extracted from the source vector
1343+
/// (`pop_front`, `pop_back`, `remove`), bump the reference count of any array- or
1344+
/// vector-typed element value. The intrinsic's returned tuple component for the new
1345+
/// (post-pop) vector is skipped: it is a distinct result, not an alias of the source.
1346+
///
1347+
/// Without this bump the popped element shares its underlying memory with the source
1348+
/// vector, so a mutation through it would also mutate the source — breaking the
1349+
/// copy-on-write invariant the rest of the pipeline relies on. The `ownership` pass
1350+
/// enforces the same invariant for plain `array[i]` accesses (see `handle_index`),
1351+
/// but it does not see through these intrinsic calls.
1352+
fn codegen_intrinsic_inc_rc_results(
1353+
&mut self,
1354+
function: ValueId,
1355+
return_type: &ast::Type,
1356+
result: &Values,
1357+
) {
1358+
if self.builder.current_function.runtime().is_acir() {
1359+
return;
1360+
}
1361+
let Some(intrinsic) = self.builder.get_intrinsic_from_value(function) else {
1362+
return;
1363+
};
1364+
if !matches!(
1365+
intrinsic,
1366+
Intrinsic::VectorPopFront | Intrinsic::VectorPopBack | Intrinsic::VectorRemove
1367+
) {
1368+
return;
1369+
}
1370+
// All of these vector operations return either ([T], T) or (T, [T])
1371+
let (ast::Type::Tuple(types), Tree::Branch(value_trees)) = (return_type, result) else {
1372+
return;
1373+
};
1374+
// We are looking for the T in the tuple, ignoring the [T].
1375+
for (ty, subtree) in types.iter().zip_eq(value_trees.iter()) {
1376+
if matches!(ty, ast::Type::Vector(_)) {
1377+
continue;
1378+
}
1379+
for value in subtree.clone().into_value_list(self) {
1380+
if self.builder.type_of_value(value).is_array() {
1381+
self.builder.insert_inc_rc(value);
1382+
}
1383+
}
1384+
}
13381385
}
13391386

13401387
/// Generate SSA for a `multi_scalar_mul` blackbox call.

tooling/nargo_cli/tests/snapshots/execution_success/regression_12713/execute__tests__stdout.snap

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)