Skip to content

Commit 9d34c28

Browse files
committed
generate fewer basic blocks for variant switches
1 parent 298730e commit 9d34c28

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

src/librustc_mir/build/matches/mod.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ enum TestKind<'tcx> {
266266
// test the branches of enum
267267
Switch {
268268
adt_def: AdtDef<'tcx>,
269+
variants: Vec<bool>,
269270
},
270271

271272
// test the branches of enum
@@ -391,9 +392,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
391392

392393
fn join_otherwise_blocks(&mut self,
393394
span: Span,
394-
otherwise: Vec<BasicBlock>)
395+
mut otherwise: Vec<BasicBlock>)
395396
-> BasicBlock
396397
{
398+
otherwise.sort();
399+
otherwise.dedup(); // variant switches can introduce duplicate target blocks
397400
let scope_id = self.innermost_scope_id();
398401
if otherwise.len() == 1 {
399402
otherwise[0]
@@ -502,6 +505,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
502505
}
503506
}
504507
}
508+
TestKind::Switch { adt_def: _, ref mut variants} => {
509+
for candidate in candidates.iter() {
510+
if !self.add_variants_to_switch(&match_pair.lvalue,
511+
candidate,
512+
variants) {
513+
break;
514+
}
515+
}
516+
}
505517
_ => { }
506518
}
507519

@@ -525,6 +537,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
525537
&mut target_candidates))
526538
.count();
527539
assert!(tested_candidates > 0); // at least the last candidate ought to be tested
540+
debug!("tested_candidates: {}", tested_candidates);
541+
debug!("untested_candidates: {}", candidates.len() - tested_candidates);
528542

529543
// For each outcome of test, process the candidates that still
530544
// apply. Collect a list of blocks where control flow will

src/librustc_mir/build/matches/test.rs

+50-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
3333
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
3434
Test {
3535
span: match_pair.pattern.span,
36-
kind: TestKind::Switch { adt_def: adt_def.clone() },
36+
kind: TestKind::Switch {
37+
adt_def: adt_def.clone(),
38+
variants: vec![false; self.hir.num_variants(adt_def)],
39+
},
3740
}
3841
}
3942

@@ -125,9 +128,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
125128
});
126129
true
127130
}
128-
131+
PatternKind::Variant { .. } => {
132+
panic!("you should have called add_cases_to_switch_switch instead!");
133+
}
129134
PatternKind::Range { .. } |
130-
PatternKind::Variant { .. } |
131135
PatternKind::Slice { .. } |
132136
PatternKind::Array { .. } |
133137
PatternKind::Wild |
@@ -140,6 +144,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
140144
}
141145
}
142146

147+
pub fn add_variants_to_switch<'pat>(&mut self,
148+
test_lvalue: &Lvalue<'tcx>,
149+
candidate: &Candidate<'pat, 'tcx>,
150+
variants: &mut Vec<bool>)
151+
-> bool
152+
{
153+
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
154+
Some(match_pair) => match_pair,
155+
_ => { return false; }
156+
};
157+
158+
match *match_pair.pattern.kind {
159+
PatternKind::Variant { adt_def: _ , variant_index, .. } => {
160+
// Do I need to look at the PatternKind::Variant subpatterns?
161+
variants[variant_index] |= true;
162+
true
163+
}
164+
_ => {
165+
// don't know how to add these patterns to a switch
166+
false
167+
}
168+
}
169+
}
170+
143171
/// Generates the code to perform a test.
144172
pub fn perform_test(&mut self,
145173
block: BasicBlock,
@@ -148,11 +176,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
148176
-> Vec<BasicBlock> {
149177
let scope_id = self.innermost_scope_id();
150178
match test.kind {
151-
TestKind::Switch { adt_def } => {
179+
TestKind::Switch { adt_def, ref variants } => {
152180
let num_enum_variants = self.hir.num_variants(adt_def);
153-
let target_blocks: Vec<_> =
181+
debug!("num_enum_variants: {}", num_enum_variants);
182+
debug!("variants.len(): {}", variants.len());
183+
debug!("variants: {:?}", variants);
184+
let target_blocks: Vec<_> = if variants.into_iter().any(|b| {!b}) {
185+
let otherwise_block = self.cfg.start_new_block();
186+
debug!("basic block: {:?} is an otherwise block!", otherwise_block);
187+
(0..num_enum_variants).map(|i|
188+
if variants[i] {
189+
self.cfg.start_new_block()
190+
} else {
191+
otherwise_block
192+
}
193+
)
194+
.collect()
195+
} else {
154196
(0..num_enum_variants).map(|_| self.cfg.start_new_block())
155-
.collect();
197+
.collect()
198+
};
156199
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
157200
discr: lvalue.clone(),
158201
adt_def: adt_def,
@@ -383,7 +426,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
383426
match test.kind {
384427
// If we are performing a variant switch, then this
385428
// informs variant patterns, but nothing else.
386-
TestKind::Switch { adt_def: tested_adt_def } => {
429+
TestKind::Switch { adt_def: tested_adt_def , .. } => {
387430
match *match_pair.pattern.kind {
388431
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
389432
assert_eq!(adt_def, tested_adt_def);

0 commit comments

Comments
 (0)