diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs index e32eaa70186..51b9cfba381 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs @@ -57,6 +57,20 @@ impl AliasSet { } } + /// Returns true if calling `unify` would change something in this alias set. + /// + /// This is an optimization to avoid having to look up an entry ready to be modified in the [Block](crate::ssa::opt::mem2reg::block::Block), + /// because doing so would involve calling `Arc::make_mut` which clones the entry, ready for modification. + pub(super) fn should_unify(&self, other: &Self) -> bool { + if let (Some(self_aliases), Some(other_aliases)) = (&self.aliases, &other.aliases) { + // `unify` would extend `self_aliases` with `other_aliases`, so if `other_aliases` is a subset, then nothing would happen. + !other_aliases.is_subset(self_aliases) + } else { + // `unify` would set `aliases` to `None`, so if it's not `Some`, then nothing would happen. + self.aliases.is_some() + } + } + /// Inserts a new alias into this set if it is not unknown pub(super) fn insert(&mut self, new_alias: ValueId) { if let Some(aliases) = &mut self.aliases { diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs index f4265b2466d..91e27f07b8e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs @@ -128,6 +128,12 @@ impl Block { } for (expression, new_aliases) in &other.aliases { + // If nothing would change, then don't call `.entry(...).and_modify(...)` as it involves creating more `Arc`s. + if let Some(aliases) = self.aliases.get(expression) { + if !aliases.should_unify(new_aliases) { + continue; + } + } let expression = expression.clone(); self.aliases