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

match lowering: consistently merge simple or-patterns #123067

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
28 changes: 18 additions & 10 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,10 @@ struct Candidate<'pat, 'tcx> {
/// If the candidate matches, bindings and ascriptions must be established.
extra_data: PatternExtraData<'tcx>,

/// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
// Invariant: it is `None` iff `subcandidates.is_empty()`.
or_span: Option<Span>,

/// The block before the `bindings` have been established.
pre_binding_block: Option<BasicBlock>,
/// The pre-binding block of the next candidate.
Expand All @@ -1028,6 +1032,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
extra_data: flat_pat.extra_data,
has_guard,
subcandidates: Vec::new(),
or_span: None,
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
Expand Down Expand Up @@ -1277,7 +1282,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
//
// only generates a single switch.
candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
candidate.match_pairs.pop();
let first_match_pair = candidate.match_pairs.pop().unwrap();
candidate.or_span = Some(first_match_pair.pattern.span);
split_or_candidate = true;
}
}
Expand All @@ -1287,8 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// At least one of the candidates has been split into subcandidates.
// We need to change the candidate list to include those.
let mut new_candidates = Vec::new();

for candidate in candidates {
for candidate in candidates.iter_mut() {
candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
}
self.match_simplified_candidates(
Expand All @@ -1298,6 +1303,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block,
&mut *new_candidates,
);

for candidate in candidates {
self.merge_trivial_subcandidates(candidate);
}
} else {
self.match_simplified_candidates(
span,
Expand Down Expand Up @@ -1531,16 +1540,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut or_candidate_refs,
);
candidate.subcandidates = or_candidates;
self.merge_trivial_subcandidates(candidate, self.source_info(or_span));
candidate.or_span = Some(or_span);
self.merge_trivial_subcandidates(candidate);
}

/// Try to merge all of the subcandidates of the given candidate into one.
/// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
fn merge_trivial_subcandidates(
&mut self,
candidate: &mut Candidate<'_, 'tcx>,
source_info: SourceInfo,
) {
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() || candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
return;
Expand All @@ -1550,7 +1556,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

// Not `Iterator::all` because we don't want to short-circuit.
for subcandidate in &mut candidate.subcandidates {
self.merge_trivial_subcandidates(subcandidate, source_info);
self.merge_trivial_subcandidates(subcandidate);

// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
can_merge &=
Expand All @@ -1559,6 +1565,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

if can_merge {
let any_matches = self.cfg.start_new_block();
let or_span = candidate.or_span.take().unwrap();
let source_info = self.source_info(or_span);
for subcandidate in mem::take(&mut candidate.subcandidates) {
let or_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(or_block, source_info, any_matches);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/build/matches/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&*candidate.match_pairs
{
candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
candidate.match_pairs.pop();
let first_match_pair = candidate.match_pairs.pop().unwrap();
candidate.or_span = Some(first_match_pair.pattern.span);
}
candidate
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,20 @@
_3 = _1;
_2 = move _3 as [u32; 4] (Transmute);
StorageDead(_3);
switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6];
switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb4];
}

bb1: {
switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6];
switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb4];
}

bb2: {
switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6];
switchInt(_2[2 of 4]) -> [0: bb3, 4294901760: bb3, otherwise: bb4];
}

bb3: {
StorageLive(_4);
_4 = _2[3 of 4];
StorageLive(_5);
StorageLive(_6);
_6 = _4;
Expand All @@ -46,27 +48,15 @@
_0 = Option::<[u8; 4]>::Some(move _5);
StorageDead(_5);
StorageDead(_4);
goto -> bb7;
goto -> bb5;
}

bb4: {
StorageLive(_4);
_4 = _2[3 of 4];
goto -> bb3;
}

bb5: {
StorageLive(_4);
_4 = _2[3 of 4];
goto -> bb3;
}

bb6: {
_0 = Option::<[u8; 4]>::None;
goto -> bb7;
goto -> bb5;
}

bb7: {
bb5: {
StorageDead(_2);
return;
}
Expand Down
Loading