Skip to content

Commit f1f5c04

Browse files
committed
Auto merge of #29763 - nikomatsakis:mir-29227, r=nikomatsakis
The older algorithm was pretty inefficient for big matches. Fixes #29227. (On my computer, MIR construction on this test case goes from 9.9s to 0.025s.) Whereas before we had a loop like: - for all outcomes of the test we are performing - for all candidates - check whether candidate is relevant to outcome We now do: - for all candidates - determine which outcomes the candidate is relevant to Since the number of outcomes in this case is proportional to the number of candidates, the original algorithm turned out to be O(n^2), and the newer one is just O(n). This PR also does some minor speedups by eagerly mirroring all patterns, so that we can just pass around `&Pattern<'tcx>`, which makes cloning cheaper. We could probably go a bit further in this direction. r? @Aatch
2 parents 8c743a9 + 38cf175 commit f1f5c04

File tree

14 files changed

+570
-550
lines changed

14 files changed

+570
-550
lines changed

src/librustc_mir/build/matches/mod.rs

+52-50
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
4444
// be unreachable or reachable multiple times.
4545
let var_extent = self.extent_of_innermost_scope().unwrap();
4646
for arm in &arms {
47-
self.declare_bindings(var_extent, arm.patterns[0].clone());
47+
self.declare_bindings(var_extent, &arm.patterns[0]);
4848
}
4949

5050
let mut arm_blocks = ArmBlocks {
@@ -64,18 +64,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
6464
// highest priority candidate comes last in the list. This the
6565
// reverse of the order in which candidates are written in the
6666
// source.
67-
let candidates: Vec<Candidate<'tcx>> =
67+
let candidates: Vec<_> =
6868
arms.iter()
6969
.enumerate()
7070
.rev() // highest priority comes last
7171
.flat_map(|(arm_index, arm)| {
7272
arm.patterns.iter()
7373
.rev()
74-
.map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
74+
.map(move |pat| (arm_index, pat, arm.guard.clone()))
7575
})
7676
.map(|(arm_index, pattern, guard)| {
7777
Candidate {
78-
match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
78+
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
7979
bindings: vec![],
8080
guard: guard,
8181
arm_index: arm_index,
@@ -102,12 +102,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
102102
pub fn expr_into_pattern(&mut self,
103103
mut block: BasicBlock,
104104
var_extent: CodeExtent, // lifetime of vars
105-
irrefutable_pat: PatternRef<'tcx>,
105+
irrefutable_pat: Pattern<'tcx>,
106106
initializer: ExprRef<'tcx>)
107107
-> BlockAnd<()> {
108108
// optimize the case of `let x = ...`
109-
let irrefutable_pat = self.hir.mirror(irrefutable_pat);
110-
match irrefutable_pat.kind {
109+
match *irrefutable_pat.kind {
111110
PatternKind::Binding { mutability,
112111
name,
113112
mode: BindingMode::ByValue,
@@ -128,22 +127,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
128127
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
129128
self.lvalue_into_pattern(block,
130129
var_extent,
131-
PatternRef::Mirror(Box::new(irrefutable_pat)),
130+
irrefutable_pat,
132131
&lvalue)
133132
}
134133

135134
pub fn lvalue_into_pattern(&mut self,
136135
mut block: BasicBlock,
137136
var_extent: CodeExtent,
138-
irrefutable_pat: PatternRef<'tcx>,
137+
irrefutable_pat: Pattern<'tcx>,
139138
initializer: &Lvalue<'tcx>)
140139
-> BlockAnd<()> {
141140
// first, creating the bindings
142-
self.declare_bindings(var_extent, irrefutable_pat.clone());
141+
self.declare_bindings(var_extent, &irrefutable_pat);
143142

144143
// create a dummy candidate
145-
let mut candidate = Candidate::<'tcx> {
146-
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
144+
let mut candidate = Candidate {
145+
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
147146
bindings: vec![],
148147
guard: None,
149148
arm_index: 0, // since we don't call `match_candidates`, this field is unused
@@ -166,29 +165,29 @@ impl<'a,'tcx> Builder<'a,'tcx> {
166165
block.unit()
167166
}
168167

169-
pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: PatternRef<'tcx>) {
170-
let pattern = self.hir.mirror(pattern);
171-
match pattern.kind {
172-
PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
168+
pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: &Pattern<'tcx>) {
169+
match *pattern.kind {
170+
PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
173171
self.declare_binding(var_extent, mutability, name, var, ty, pattern.span);
174-
if let Some(subpattern) = subpattern {
172+
if let Some(subpattern) = subpattern.as_ref() {
175173
self.declare_bindings(var_extent, subpattern);
176174
}
177175
}
178-
PatternKind::Array { prefix, slice, suffix } |
179-
PatternKind::Slice { prefix, slice, suffix } => {
180-
for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
176+
PatternKind::Array { ref prefix, ref slice, ref suffix } |
177+
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
178+
for subpattern in prefix.iter().chain(slice).chain(suffix) {
181179
self.declare_bindings(var_extent, subpattern);
182180
}
183181
}
184-
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
185-
PatternKind::Deref { subpattern } => {
182+
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
183+
}
184+
PatternKind::Deref { ref subpattern } => {
186185
self.declare_bindings(var_extent, subpattern);
187186
}
188-
PatternKind::Leaf { subpatterns } |
189-
PatternKind::Variant { subpatterns, .. } => {
187+
PatternKind::Leaf { ref subpatterns } |
188+
PatternKind::Variant { ref subpatterns, .. } => {
190189
for subpattern in subpatterns {
191-
self.declare_bindings(var_extent, subpattern.pattern);
190+
self.declare_bindings(var_extent, &subpattern.pattern);
192191
}
193192
}
194193
}
@@ -202,9 +201,9 @@ struct ArmBlocks {
202201
}
203202

204203
#[derive(Clone, Debug)]
205-
struct Candidate<'tcx> {
204+
struct Candidate<'pat, 'tcx:'pat> {
206205
// all of these must be satisfied...
207-
match_pairs: Vec<MatchPair<'tcx>>,
206+
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
208207

209208
// ...these bindings established...
210209
bindings: Vec<Binding<'tcx>>,
@@ -228,12 +227,12 @@ struct Binding<'tcx> {
228227
}
229228

230229
#[derive(Clone, Debug)]
231-
struct MatchPair<'tcx> {
230+
struct MatchPair<'pat, 'tcx:'pat> {
232231
// this lvalue...
233232
lvalue: Lvalue<'tcx>,
234233

235234
// ... must match this pattern.
236-
pattern: Pattern<'tcx>,
235+
pattern: &'pat Pattern<'tcx>,
237236
}
238237

239238
#[derive(Clone, Debug, PartialEq)]
@@ -280,11 +279,11 @@ struct Test<'tcx> {
280279
// Main matching algorithm
281280

282281
impl<'a,'tcx> Builder<'a,'tcx> {
283-
fn match_candidates(&mut self,
284-
span: Span,
285-
arm_blocks: &mut ArmBlocks,
286-
mut candidates: Vec<Candidate<'tcx>>,
287-
mut block: BasicBlock)
282+
fn match_candidates<'pat>(&mut self,
283+
span: Span,
284+
arm_blocks: &mut ArmBlocks,
285+
mut candidates: Vec<Candidate<'pat, 'tcx>>,
286+
mut block: BasicBlock)
288287
{
289288
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
290289
span, block, candidates);
@@ -346,17 +345,20 @@ impl<'a,'tcx> Builder<'a,'tcx> {
346345
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
347346
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
348347

349-
for (outcome, target_block) in target_blocks.into_iter().enumerate() {
350-
let applicable_candidates: Vec<Candidate<'tcx>> =
351-
candidates.iter()
352-
.filter_map(|candidate| {
353-
self.candidate_under_assumption(&match_pair.lvalue,
354-
&test.kind,
355-
outcome,
356-
candidate)
357-
})
358-
.collect();
359-
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
348+
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
349+
350+
for candidate in &candidates {
351+
self.sort_candidate(&match_pair.lvalue,
352+
&test,
353+
candidate,
354+
&mut target_candidates);
355+
}
356+
357+
for (target_block, target_candidates) in
358+
target_blocks.into_iter()
359+
.zip(target_candidates.into_iter())
360+
{
361+
self.match_candidates(span, arm_blocks, target_candidates, target_block);
360362
}
361363
}
362364

@@ -372,11 +374,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
372374
/// bindings, further tests would be a use-after-move (which would
373375
/// in turn be detected by the borrowck code that runs on the
374376
/// MIR).
375-
fn bind_and_guard_matched_candidate(&mut self,
376-
mut block: BasicBlock,
377-
arm_blocks: &mut ArmBlocks,
378-
candidate: Candidate<'tcx>)
379-
-> Option<BasicBlock> {
377+
fn bind_and_guard_matched_candidate<'pat>(&mut self,
378+
mut block: BasicBlock,
379+
arm_blocks: &mut ArmBlocks,
380+
candidate: Candidate<'pat, 'tcx>)
381+
-> Option<BasicBlock> {
380382
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
381383
block, candidate);
382384

src/librustc_mir/build/matches/simplify.rs

+16-18
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ use repr::*;
3030
use std::mem;
3131

3232
impl<'a,'tcx> Builder<'a,'tcx> {
33-
pub fn simplify_candidate(&mut self,
34-
mut block: BasicBlock,
35-
candidate: &mut Candidate<'tcx>)
36-
-> BlockAnd<()> {
33+
pub fn simplify_candidate<'pat>(&mut self,
34+
mut block: BasicBlock,
35+
candidate: &mut Candidate<'pat, 'tcx>)
36+
-> BlockAnd<()> {
3737
// repeatedly simplify match pairs until fixed point is reached
3838
loop {
3939
let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
@@ -60,18 +60,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
6060
/// have been pushed into the candidate. If no simplification is
6161
/// possible, Err is returned and no changes are made to
6262
/// candidate.
63-
fn simplify_match_pair(&mut self,
64-
mut block: BasicBlock,
65-
match_pair: MatchPair<'tcx>,
66-
candidate: &mut Candidate<'tcx>)
67-
-> Result<BasicBlock, MatchPair<'tcx>> {
68-
match match_pair.pattern.kind {
63+
fn simplify_match_pair<'pat>(&mut self,
64+
mut block: BasicBlock,
65+
match_pair: MatchPair<'pat, 'tcx>,
66+
candidate: &mut Candidate<'pat, 'tcx>)
67+
-> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
68+
match *match_pair.pattern.kind {
6969
PatternKind::Wild(..) => {
7070
// nothing left to do
7171
Ok(block)
7272
}
7373

74-
PatternKind::Binding { name, mutability, mode, var, ty, subpattern } => {
74+
PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
7575
candidate.bindings.push(Binding {
7676
name: name,
7777
mutability: mutability,
@@ -82,9 +82,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
8282
binding_mode: mode,
8383
});
8484

85-
if let Some(subpattern) = subpattern {
85+
if let Some(subpattern) = subpattern.as_ref() {
8686
// this is the `x @ P` case; have to keep matching against `P` now
87-
let subpattern = self.hir.mirror(subpattern);
8887
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
8988
}
9089

@@ -96,12 +95,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
9695
Err(match_pair)
9796
}
9897

99-
PatternKind::Array { prefix, slice, suffix } => {
98+
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
10099
unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
101100
block,
102101
match_pair.lvalue.clone(),
103102
prefix,
104-
slice,
103+
slice.as_ref(),
105104
suffix));
106105
Ok(block)
107106
}
@@ -113,16 +112,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
113112
Err(match_pair)
114113
}
115114

116-
PatternKind::Leaf { subpatterns } => {
115+
PatternKind::Leaf { ref subpatterns } => {
117116
// tuple struct, match subpats (if any)
118117
candidate.match_pairs
119118
.extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
120119
Ok(block)
121120
}
122121

123-
PatternKind::Deref { subpattern } => {
122+
PatternKind::Deref { ref subpattern } => {
124123
let lvalue = match_pair.lvalue.deref();
125-
let subpattern = self.hir.mirror(subpattern);
126124
candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
127125
Ok(block)
128126
}

0 commit comments

Comments
 (0)