Skip to content

Commit 13ce5c8

Browse files
authored
fix(ssa): Tracking nested array aliases (#11378)
1 parent 5c27fae commit 13ce5c8

File tree

1 file changed

+79
-8
lines changed

1 file changed

+79
-8
lines changed

compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,10 @@ impl<'f> PerFunctionContext<'f> {
732732

733733
let expr = Expression::ArrayElement(array);
734734
references.expressions.insert(array, expr);
735-
let aliases = references.aliases.entry(expr).or_insert(AliasSet::known_empty());
736735

737-
self.add_array_aliases(elements, aliases);
736+
let new_aliases = self.collect_array_aliases(elements, references);
737+
let aliases = references.aliases.entry(expr).or_insert(AliasSet::known_empty());
738+
aliases.unify(&new_aliases);
738739
}
739740
}
740741
Instruction::IfElse { then_value, else_value, .. } => {
@@ -785,16 +786,23 @@ impl<'f> PerFunctionContext<'f> {
785786
}
786787
}
787788

788-
/// In order to handle nested arrays we need to recursively search whether there are any references
789-
/// contained within an array's elements.
790-
fn add_array_aliases(&self, elements: &im::Vector<ValueId>, aliases: &mut AliasSet) {
789+
/// In order to handle nested arrays we need to recursively search for whether there
790+
/// are any aliases contained within an array's elements.
791+
fn collect_array_aliases(
792+
&self,
793+
elements: &im::Vector<ValueId>,
794+
references: &Block,
795+
) -> AliasSet {
796+
let mut aliases = AliasSet::known_empty();
791797
for &element in elements {
792798
if let Some((elements, _)) = self.inserter.function.dfg.get_array_constant(element) {
793-
self.add_array_aliases(&elements, aliases);
794-
} else if self.inserter.function.dfg.value_is_reference(element) {
795-
aliases.insert(element);
799+
aliases.unify(&self.collect_array_aliases(&elements, references));
800+
} else if self.inserter.function.dfg.type_of_value(element).contains_reference() {
801+
// Handles both direct references and non-constant arrays (e.g., array_set results)
802+
aliases.unify(&references.get_aliases_for_value(element));
796803
}
797804
}
805+
aliases
798806
}
799807

800808
fn set_aliases(&self, references: &mut Block, address: ValueId, new_aliases: AliasSet) {
@@ -2886,4 +2894,67 @@ mod tests {
28862894
}
28872895
");
28882896
}
2897+
2898+
#[test]
2899+
fn missing_make_array_alias_from_array_set_result() {
2900+
let src = "
2901+
acir(inline) predicate_pure fn main f0 {
2902+
b0(v0: u32, v1: u8, v2: u8):
2903+
v3 = allocate -> &mut u8
2904+
store v1 at v3
2905+
v4 = allocate -> &mut [&mut u8; 1]
2906+
v5 = make_array [v3] : [&mut u8; 1]
2907+
store v5 at v4
2908+
constrain v0 == u32 0
2909+
v6 = load v4 -> [&mut u8; 1]
2910+
v7 = array_set v6, index v0, value v3
2911+
v8 = allocate -> &mut u8
2912+
store u8 0 at v8
2913+
v9 = make_array [v8] : [&mut u8; 1]
2914+
v10 = make_array [v7, v9] : [[&mut u8; 1]; 2]
2915+
v11 = array_get v10, index v0 -> [&mut u8; 1]
2916+
v12 = array_get v11, index u32 0 -> &mut u8
2917+
store v2 at v3
2918+
v13 = load v12 -> u8
2919+
constrain v13 == v2
2920+
return
2921+
}
2922+
";
2923+
2924+
let ssa = Ssa::from_str(src).unwrap();
2925+
let result = ssa.interpret(vec![Value::u32(0), Value::u8(0), Value::u8(0)]);
2926+
assert_eq!(result, Ok(vec![]));
2927+
let result = ssa.interpret(vec![Value::u32(0), Value::u8(0), Value::u8(1)]);
2928+
assert_eq!(result, Ok(vec![]));
2929+
2930+
let ssa = ssa.mem2reg();
2931+
// Alias tracking should prevent `store v2 at v3` from being removed
2932+
let result = ssa.interpret(vec![Value::u32(0), Value::u8(0), Value::u8(0)]);
2933+
assert_eq!(result, Ok(vec![]));
2934+
let result = ssa.interpret(vec![Value::u32(0), Value::u8(0), Value::u8(1)]);
2935+
assert_eq!(result, Ok(vec![]));
2936+
2937+
// Only `store v5 at v4` is safe to remove
2938+
assert_ssa_snapshot!(ssa, @r"
2939+
acir(inline) predicate_pure fn main f0 {
2940+
b0(v0: u32, v1: u8, v2: u8):
2941+
v3 = allocate -> &mut u8
2942+
store v1 at v3
2943+
v4 = allocate -> &mut [&mut u8; 1]
2944+
v5 = make_array [v3] : [&mut u8; 1]
2945+
constrain v0 == u32 0
2946+
v7 = array_set v5, index v0, value v3
2947+
v8 = allocate -> &mut u8
2948+
store u8 0 at v8
2949+
v10 = make_array [v8] : [&mut u8; 1]
2950+
v11 = make_array [v7, v10] : [[&mut u8; 1]; 2]
2951+
v12 = array_get v11, index v0 -> [&mut u8; 1]
2952+
v13 = array_get v12, index u32 0 -> &mut u8
2953+
store v2 at v3
2954+
v14 = load v13 -> u8
2955+
constrain v14 == v2
2956+
return
2957+
}
2958+
");
2959+
}
28892960
}

0 commit comments

Comments
 (0)