Skip to content

Commit 84f1942

Browse files
committed
Auto merge of #33999 - scottcarr:master, r=nikomatsakis
generate fewer basic blocks for variant switches CC #33567 Adds a new field to TestKind::Switch that tracks the variants that are actually matched against. The other candidates target a common "otherwise" block.
2 parents 7de2e6d + d4551ec commit 84f1942

File tree

3 files changed

+65
-10
lines changed

3 files changed

+65
-10
lines changed

src/librustc_data_structures/bitvec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use std::iter::FromIterator;
1212

1313
/// A very simple BitVector type.
14-
#[derive(Clone)]
14+
#[derive(Clone, Debug, PartialEq)]
1515
pub struct BitVector {
1616
data: Vec<u64>,
1717
}

src/librustc_mir/build/matches/mod.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
1616
use build::{BlockAnd, BlockAndExtension, Builder};
1717
use rustc_data_structures::fnv::FnvHashMap;
18+
use rustc_data_structures::bitvec::BitVector;
1819
use rustc::middle::const_val::ConstVal;
1920
use rustc::ty::{AdtDef, Ty};
2021
use rustc::mir::repr::*;
@@ -266,6 +267,7 @@ enum TestKind<'tcx> {
266267
// test the branches of enum
267268
Switch {
268269
adt_def: AdtDef<'tcx>,
270+
variants: BitVector,
269271
},
270272

271273
// test the branches of enum
@@ -391,9 +393,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
391393

392394
fn join_otherwise_blocks(&mut self,
393395
span: Span,
394-
otherwise: Vec<BasicBlock>)
396+
mut otherwise: Vec<BasicBlock>)
395397
-> BasicBlock
396398
{
399+
otherwise.sort();
400+
otherwise.dedup(); // variant switches can introduce duplicate target blocks
397401
let scope_id = self.innermost_scope_id();
398402
if otherwise.len() == 1 {
399403
otherwise[0]
@@ -502,6 +506,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
502506
}
503507
}
504508
}
509+
TestKind::Switch { adt_def: _, ref mut variants} => {
510+
for candidate in candidates.iter() {
511+
if !self.add_variants_to_switch(&match_pair.lvalue,
512+
candidate,
513+
variants) {
514+
break;
515+
}
516+
}
517+
}
505518
_ => { }
506519
}
507520

@@ -525,6 +538,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
525538
&mut target_candidates))
526539
.count();
527540
assert!(tested_candidates > 0); // at least the last candidate ought to be tested
541+
debug!("tested_candidates: {}", tested_candidates);
542+
debug!("untested_candidates: {}", candidates.len() - tested_candidates);
528543

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

src/librustc_mir/build/matches/test.rs

+48-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use build::Builder;
1919
use build::matches::{Candidate, MatchPair, Test, TestKind};
2020
use hair::*;
2121
use rustc_data_structures::fnv::FnvHashMap;
22+
use rustc_data_structures::bitvec::BitVector;
2223
use rustc::middle::const_val::ConstVal;
2324
use rustc::ty::{self, Ty};
2425
use rustc::mir::repr::*;
@@ -33,7 +34,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
3334
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
3435
Test {
3536
span: match_pair.pattern.span,
36-
kind: TestKind::Switch { adt_def: adt_def.clone() },
37+
kind: TestKind::Switch {
38+
adt_def: adt_def.clone(),
39+
variants: BitVector::new(self.hir.num_variants(adt_def)),
40+
},
3741
}
3842
}
3943

@@ -125,9 +129,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
125129
});
126130
true
127131
}
128-
132+
PatternKind::Variant { .. } => {
133+
panic!("you should have called add_variants_to_switch instead!");
134+
}
129135
PatternKind::Range { .. } |
130-
PatternKind::Variant { .. } |
131136
PatternKind::Slice { .. } |
132137
PatternKind::Array { .. } |
133138
PatternKind::Wild |
@@ -140,6 +145,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
140145
}
141146
}
142147

148+
pub fn add_variants_to_switch<'pat>(&mut self,
149+
test_lvalue: &Lvalue<'tcx>,
150+
candidate: &Candidate<'pat, 'tcx>,
151+
variants: &mut BitVector)
152+
-> bool
153+
{
154+
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
155+
Some(match_pair) => match_pair,
156+
_ => { return false; }
157+
};
158+
159+
match *match_pair.pattern.kind {
160+
PatternKind::Variant { adt_def: _ , variant_index, .. } => {
161+
// We have a pattern testing for variant `variant_index`
162+
// set the corresponding index to true
163+
variants.insert(variant_index);
164+
true
165+
}
166+
_ => {
167+
// don't know how to add these patterns to a switch
168+
false
169+
}
170+
}
171+
}
172+
143173
/// Generates the code to perform a test.
144174
pub fn perform_test(&mut self,
145175
block: BasicBlock,
@@ -148,11 +178,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
148178
-> Vec<BasicBlock> {
149179
let scope_id = self.innermost_scope_id();
150180
match test.kind {
151-
TestKind::Switch { adt_def } => {
181+
TestKind::Switch { adt_def, ref variants } => {
152182
let num_enum_variants = self.hir.num_variants(adt_def);
153-
let target_blocks: Vec<_> =
154-
(0..num_enum_variants).map(|_| self.cfg.start_new_block())
155-
.collect();
183+
let mut otherwise_block = None;
184+
let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| {
185+
if variants.contains(i) {
186+
self.cfg.start_new_block()
187+
} else {
188+
if otherwise_block.is_none() {
189+
otherwise_block = Some(self.cfg.start_new_block());
190+
}
191+
otherwise_block.unwrap()
192+
}
193+
}).collect();
194+
debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
195+
num_enum_variants, variants.iter().count(), variants);
156196
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
157197
discr: lvalue.clone(),
158198
adt_def: adt_def,
@@ -415,7 +455,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
415455
match test.kind {
416456
// If we are performing a variant switch, then this
417457
// informs variant patterns, but nothing else.
418-
TestKind::Switch { adt_def: tested_adt_def } => {
458+
TestKind::Switch { adt_def: tested_adt_def , .. } => {
419459
match *match_pair.pattern.kind {
420460
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
421461
assert_eq!(adt_def, tested_adt_def);

0 commit comments

Comments
 (0)