mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 03:23:25 +00:00
generate fewer basic blocks for variant switches
This commit is contained in:
parent
298730e703
commit
9d34c280d9
@ -266,6 +266,7 @@ enum TestKind<'tcx> {
|
|||||||
// test the branches of enum
|
// test the branches of enum
|
||||||
Switch {
|
Switch {
|
||||||
adt_def: AdtDef<'tcx>,
|
adt_def: AdtDef<'tcx>,
|
||||||
|
variants: Vec<bool>,
|
||||||
},
|
},
|
||||||
|
|
||||||
// test the branches of enum
|
// test the branches of enum
|
||||||
@ -391,9 +392,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn join_otherwise_blocks(&mut self,
|
fn join_otherwise_blocks(&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
otherwise: Vec<BasicBlock>)
|
mut otherwise: Vec<BasicBlock>)
|
||||||
-> BasicBlock
|
-> BasicBlock
|
||||||
{
|
{
|
||||||
|
otherwise.sort();
|
||||||
|
otherwise.dedup(); // variant switches can introduce duplicate target blocks
|
||||||
let scope_id = self.innermost_scope_id();
|
let scope_id = self.innermost_scope_id();
|
||||||
if otherwise.len() == 1 {
|
if otherwise.len() == 1 {
|
||||||
otherwise[0]
|
otherwise[0]
|
||||||
@ -502,6 +505,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TestKind::Switch { adt_def: _, ref mut variants} => {
|
||||||
|
for candidate in candidates.iter() {
|
||||||
|
if !self.add_variants_to_switch(&match_pair.lvalue,
|
||||||
|
candidate,
|
||||||
|
variants) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => { }
|
_ => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,6 +537,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
&mut target_candidates))
|
&mut target_candidates))
|
||||||
.count();
|
.count();
|
||||||
assert!(tested_candidates > 0); // at least the last candidate ought to be tested
|
assert!(tested_candidates > 0); // at least the last candidate ought to be tested
|
||||||
|
debug!("tested_candidates: {}", tested_candidates);
|
||||||
|
debug!("untested_candidates: {}", candidates.len() - tested_candidates);
|
||||||
|
|
||||||
// For each outcome of test, process the candidates that still
|
// For each outcome of test, process the candidates that still
|
||||||
// apply. Collect a list of blocks where control flow will
|
// apply. Collect a list of blocks where control flow will
|
||||||
|
@ -33,7 +33,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
|
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
|
||||||
Test {
|
Test {
|
||||||
span: match_pair.pattern.span,
|
span: match_pair.pattern.span,
|
||||||
kind: TestKind::Switch { adt_def: adt_def.clone() },
|
kind: TestKind::Switch {
|
||||||
|
adt_def: adt_def.clone(),
|
||||||
|
variants: vec![false; self.hir.num_variants(adt_def)],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,9 +128,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
});
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
PatternKind::Variant { .. } => {
|
||||||
|
panic!("you should have called add_cases_to_switch_switch instead!");
|
||||||
|
}
|
||||||
PatternKind::Range { .. } |
|
PatternKind::Range { .. } |
|
||||||
PatternKind::Variant { .. } |
|
|
||||||
PatternKind::Slice { .. } |
|
PatternKind::Slice { .. } |
|
||||||
PatternKind::Array { .. } |
|
PatternKind::Array { .. } |
|
||||||
PatternKind::Wild |
|
PatternKind::Wild |
|
||||||
@ -140,6 +144,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_variants_to_switch<'pat>(&mut self,
|
||||||
|
test_lvalue: &Lvalue<'tcx>,
|
||||||
|
candidate: &Candidate<'pat, 'tcx>,
|
||||||
|
variants: &mut Vec<bool>)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
|
||||||
|
Some(match_pair) => match_pair,
|
||||||
|
_ => { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
match *match_pair.pattern.kind {
|
||||||
|
PatternKind::Variant { adt_def: _ , variant_index, .. } => {
|
||||||
|
// Do I need to look at the PatternKind::Variant subpatterns?
|
||||||
|
variants[variant_index] |= true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// don't know how to add these patterns to a switch
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates the code to perform a test.
|
/// Generates the code to perform a test.
|
||||||
pub fn perform_test(&mut self,
|
pub fn perform_test(&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
@ -148,11 +176,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
-> Vec<BasicBlock> {
|
-> Vec<BasicBlock> {
|
||||||
let scope_id = self.innermost_scope_id();
|
let scope_id = self.innermost_scope_id();
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::Switch { adt_def } => {
|
TestKind::Switch { adt_def, ref variants } => {
|
||||||
let num_enum_variants = self.hir.num_variants(adt_def);
|
let num_enum_variants = self.hir.num_variants(adt_def);
|
||||||
let target_blocks: Vec<_> =
|
debug!("num_enum_variants: {}", num_enum_variants);
|
||||||
|
debug!("variants.len(): {}", variants.len());
|
||||||
|
debug!("variants: {:?}", variants);
|
||||||
|
let target_blocks: Vec<_> = if variants.into_iter().any(|b| {!b}) {
|
||||||
|
let otherwise_block = self.cfg.start_new_block();
|
||||||
|
debug!("basic block: {:?} is an otherwise block!", otherwise_block);
|
||||||
|
(0..num_enum_variants).map(|i|
|
||||||
|
if variants[i] {
|
||||||
|
self.cfg.start_new_block()
|
||||||
|
} else {
|
||||||
|
otherwise_block
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
(0..num_enum_variants).map(|_| self.cfg.start_new_block())
|
(0..num_enum_variants).map(|_| self.cfg.start_new_block())
|
||||||
.collect();
|
.collect()
|
||||||
|
};
|
||||||
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
|
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
|
||||||
discr: lvalue.clone(),
|
discr: lvalue.clone(),
|
||||||
adt_def: adt_def,
|
adt_def: adt_def,
|
||||||
@ -383,7 +426,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
match test.kind {
|
match test.kind {
|
||||||
// If we are performing a variant switch, then this
|
// If we are performing a variant switch, then this
|
||||||
// informs variant patterns, but nothing else.
|
// informs variant patterns, but nothing else.
|
||||||
TestKind::Switch { adt_def: tested_adt_def } => {
|
TestKind::Switch { adt_def: tested_adt_def , .. } => {
|
||||||
match *match_pair.pattern.kind {
|
match *match_pair.pattern.kind {
|
||||||
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
|
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
|
||||||
assert_eq!(adt_def, tested_adt_def);
|
assert_eq!(adt_def, tested_adt_def);
|
||||||
|
Loading…
Reference in New Issue
Block a user