Skip to content

Commit c64d27e

Browse files
committed
Abstract over a single step
1 parent 4d1bd0d commit c64d27e

File tree

2 files changed

+98
-56
lines changed

2 files changed

+98
-56
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,33 @@ pub(crate) struct Test<'tcx> {
10631063
#[derive(Copy, Clone, Debug)]
10641064
pub(crate) struct ArmHasGuard(pub(crate) bool);
10651065

1066+
/// A single step in the match algorithm.
1067+
pub(crate) struct MatchAutomatonStep<'a, 'c, 'pat, 'tcx> {
1068+
/// FIXME: probably the span of the match.
1069+
span: Span,
1070+
/// Perform this test...
1071+
test: Test<'tcx>,
1072+
/// ... on this place...
1073+
place: PlaceBuilder<'tcx>,
1074+
/// ... depending on the result, branch to one of these candidate lists...
1075+
target_candidates: Vec<Vec<&'a mut Candidate<'pat, 'tcx>>>,
1076+
/// ... if it doesn't match, continue with these...
1077+
remaining_candidates: &'a mut [&'c mut Candidate<'pat, 'tcx>],
1078+
/// ... and if nothing matches, continue to this block.
1079+
otherwise_block: &'a mut Option<BasicBlock>,
1080+
/// Track places that need fake borrows.
1081+
fake_borrows: &'a mut Option<FxIndexSet<Place<'tcx>>>,
1082+
}
1083+
1084+
impl<'b, 'c, 'pat, 'tcx> std::fmt::Debug for MatchAutomatonStep<'b, 'c, 'pat, 'tcx> {
1085+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1086+
f.debug_struct("MatchAutomatonStep")
1087+
.field("test", &self.test)
1088+
.field("place", &self.place)
1089+
.finish()
1090+
}
1091+
}
1092+
10661093
///////////////////////////////////////////////////////////////////////////
10671094
// Main matching algorithm
10681095

@@ -1699,59 +1726,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16991726
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
17001727
debug!("untested_candidates: {}", candidates.len());
17011728

1702-
// HACK(matthewjasper) This is a closure so that we can let the test
1703-
// create its blocks before the rest of the match. This currently
1704-
// improves the speed of llvm when optimizing long string literal
1705-
// matches
1706-
let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
1707-
// The block that we should branch to if none of the
1708-
// `target_candidates` match. This is either the block where we
1709-
// start matching the untested candidates if there are any,
1710-
// otherwise it's the `otherwise_block`.
1711-
let remainder_start = &mut None;
1712-
let remainder_start =
1713-
if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
1714-
1715-
// For each outcome of test, process the candidates that still
1716-
// apply. Collect a list of blocks where control flow will
1717-
// branch if one of the `target_candidate` sets is not
1718-
// exhaustive.
1719-
let target_blocks: Vec<_> = target_candidates
1720-
.into_iter()
1721-
.map(|mut candidates| {
1722-
if !candidates.is_empty() {
1723-
let candidate_start = this.cfg.start_new_block();
1724-
this.match_candidates(
1725-
span,
1726-
scrutinee_span,
1727-
candidate_start,
1728-
remainder_start,
1729-
&mut *candidates,
1730-
fake_borrows,
1731-
);
1732-
candidate_start
1733-
} else {
1734-
*remainder_start.get_or_insert_with(|| this.cfg.start_new_block())
1735-
}
1736-
})
1737-
.collect();
1738-
1739-
if !candidates.is_empty() {
1740-
let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
1741-
this.match_candidates(
1742-
span,
1743-
scrutinee_span,
1744-
remainder_start,
1745-
otherwise_block,
1746-
candidates,
1747-
fake_borrows,
1748-
);
1749-
};
1750-
1751-
target_blocks
1729+
let step = MatchAutomatonStep {
1730+
span,
1731+
test,
1732+
place: match_place,
1733+
remaining_candidates: candidates,
1734+
target_candidates,
1735+
otherwise_block,
1736+
fake_borrows,
17521737
};
1753-
1754-
self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks);
1738+
self.perform_test(span, scrutinee_span, block, step);
17551739
}
17561740

17571741
/// Determine the fake borrows that are needed from a set of places that

compiler/rustc_mir_build/src/build/matches/test.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use rustc_target::abi::VariantIdx;
2323

2424
use std::cmp::Ordering;
2525

26+
use super::MatchAutomatonStep;
27+
2628
impl<'a, 'tcx> Builder<'a, 'tcx> {
2729
/// Identifies what test is needed to decide if `match_pair` is applicable.
2830
///
@@ -147,16 +149,72 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
147149
}
148150
}
149151

150-
#[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
152+
#[instrument(skip(self), level = "debug")]
151153
pub(super) fn perform_test(
152154
&mut self,
153155
match_start_span: Span,
154156
scrutinee_span: Span,
155157
block: BasicBlock,
156-
place_builder: &PlaceBuilder<'tcx>,
157-
test: &Test<'tcx>,
158-
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
158+
step: MatchAutomatonStep<'_, '_, '_, 'tcx>,
159159
) {
160+
let test = &step.test;
161+
let place_builder = &step.place;
162+
// HACK(matthewjasper) This is a closure so that we can let the test
163+
// create its blocks before the rest of the match. This currently
164+
// improves the speed of llvm when optimizing long string literal
165+
// matches
166+
let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
167+
// The block that we should branch to if none of the
168+
// `target_candidates` match. This is either the block where we
169+
// start matching the untested candidates if there are any,
170+
// otherwise it's the `otherwise_block`.
171+
let remainder_start = &mut None;
172+
let remainder_start = if step.remaining_candidates.is_empty() {
173+
&mut *step.otherwise_block
174+
} else {
175+
remainder_start
176+
};
177+
178+
// For each outcome of test, process the candidates that still
179+
// apply. Collect a list of blocks where control flow will
180+
// branch if one of the `target_candidate` sets is not
181+
// exhaustive.
182+
let target_blocks: Vec<_> = step
183+
.target_candidates
184+
.into_iter()
185+
.map(|mut candidates| {
186+
if !candidates.is_empty() {
187+
let candidate_start = this.cfg.start_new_block();
188+
this.match_candidates(
189+
step.span,
190+
scrutinee_span,
191+
candidate_start,
192+
remainder_start,
193+
&mut *candidates,
194+
step.fake_borrows,
195+
);
196+
candidate_start
197+
} else {
198+
*remainder_start.get_or_insert_with(|| this.cfg.start_new_block())
199+
}
200+
})
201+
.collect();
202+
203+
if !step.remaining_candidates.is_empty() {
204+
let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
205+
this.match_candidates(
206+
step.span,
207+
scrutinee_span,
208+
remainder_start,
209+
step.otherwise_block,
210+
step.remaining_candidates,
211+
step.fake_borrows,
212+
);
213+
};
214+
215+
target_blocks
216+
};
217+
160218
let place = place_builder.to_place(self);
161219
let place_ty = place.ty(&self.local_decls, self.tcx);
162220
debug!(?place, ?place_ty,);

0 commit comments

Comments
 (0)