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

chore(perf): try making AliasSet an enum #7057

Closed
wants to merge 3 commits into from
Closed
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
99 changes: 74 additions & 25 deletions compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,71 +9,116 @@ use crate::ssa::ir::value::ValueId;
/// Note that we distinguish between "definitely has no aliases" - `Some(BTreeSet::new())`, and
/// "unknown which aliases this may refer to" - `None`.
#[derive(Debug, Default, Clone)]
pub(super) struct AliasSet {
aliases: Option<BTreeSet<ValueId>>,
pub(super) enum AliasSet {
#[default]
Unknown,
Empty,
Known(ValueId),
KnownMultiple(BTreeSet<ValueId>),
}

impl AliasSet {
pub(super) fn unknown() -> AliasSet {
Self { aliases: None }
AliasSet::Unknown
}

pub(super) fn known(value: ValueId) -> AliasSet {
let mut aliases = BTreeSet::new();
aliases.insert(value);
Self { aliases: Some(aliases) }
AliasSet::Known(value)
}

pub(super) fn known_multiple(values: BTreeSet<ValueId>) -> AliasSet {
Self { aliases: Some(values) }
AliasSet::KnownMultiple(values)
}

/// In rare cases, such as when creating an empty array of references, the set of aliases for a
/// particular value will be known to be zero, which is distinct from being unknown and
/// possibly referring to any alias.
pub(super) fn known_empty() -> AliasSet {
Self { aliases: Some(BTreeSet::new()) }
AliasSet::Empty
}

pub(super) fn is_unknown(&self) -> bool {
self.aliases.is_none()
matches!(self, AliasSet::Unknown)
}

/// Return the single known alias if there is exactly one.
/// Otherwise, return None.
pub(super) fn single_alias(&self) -> Option<ValueId> {
self.aliases
.as_ref()
.and_then(|aliases| (aliases.len() == 1).then(|| *aliases.first().unwrap()))
if let AliasSet::Known(alias) = self {
Some(*alias)
} else {
None
}
}

/// Unify this alias set with another. The result of this set is empty if either set is empty.
/// Unify this alias set with another. The result of this set is unknown if either set is unknown.
/// Otherwise, it is the union of both alias sets.
pub(super) fn unify(&mut self, other: &Self) {
if let (Some(self_aliases), Some(other_aliases)) = (&mut self.aliases, &other.aliases) {
self_aliases.extend(other_aliases);
} else {
self.aliases = None;
match self {
AliasSet::Unknown => (),
AliasSet::Empty => *self = other.clone(),
AliasSet::Known(id) => match other {
AliasSet::Unknown => *self = AliasSet::Unknown,
AliasSet::Empty => (),
AliasSet::Known(other_id) => {
if id != other_id {
*self = AliasSet::KnownMultiple([*id, *other_id].iter().copied().collect());
}
}
AliasSet::KnownMultiple(other_values) => {
let mut values = other_values.clone();
values.insert(*id);
*self = AliasSet::KnownMultiple(values);
}
},
AliasSet::KnownMultiple(values) => match other {
AliasSet::Unknown => *self = AliasSet::Unknown,
AliasSet::Empty => (),
AliasSet::Known(other_id) => {
values.insert(*other_id);
}
AliasSet::KnownMultiple(other_values) => {
values.extend(other_values);
}
},
}
}

/// 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 {
aliases.insert(new_alias);
match self {
AliasSet::Unknown => (),
AliasSet::Empty => *self = AliasSet::Known(new_alias),
AliasSet::Known(id) => {
if *id != new_alias {
*self = AliasSet::KnownMultiple([*id, new_alias].iter().copied().collect());
}
}
AliasSet::KnownMultiple(values) => {
values.insert(new_alias);
}
}
}

/// Returns `Some(true)` if `f` returns true for any known alias in this set.
/// If this alias set is unknown, None is returned.
pub(super) fn any(&self, f: impl FnMut(ValueId) -> bool) -> Option<bool> {
self.aliases.as_ref().map(|aliases| aliases.iter().copied().any(f))
pub(super) fn any(&self, mut f: impl FnMut(ValueId) -> bool) -> Option<bool> {
match self {
AliasSet::Unknown => None,
AliasSet::Empty => Some(false),
AliasSet::Known(id) => Some(f(*id)),
AliasSet::KnownMultiple(values) => Some(values.iter().copied().any(f)),
}
}

pub(super) fn for_each(&self, mut f: impl FnMut(ValueId)) {
if let Some(aliases) = &self.aliases {
for alias in aliases {
f(*alias);
match self {
AliasSet::Unknown | AliasSet::Empty => (),
AliasSet::Known(id) => f(*id),
AliasSet::KnownMultiple(values) => {
for value in values {
f(*value);
}
}
}
}
Expand All @@ -82,6 +127,10 @@ impl AliasSet {
/// The ordering is arbitrary (by lowest ValueId) so this method should only be
/// used when you need an arbitrary ValueId from the alias set.
pub(super) fn first(&self) -> Option<ValueId> {
self.aliases.as_ref().and_then(|aliases| aliases.first().copied())
match self {
AliasSet::Unknown | AliasSet::Empty => None,
AliasSet::Known(id) => Some(*id),
AliasSet::KnownMultiple(values) => values.first().copied(),
}
}
}
Loading