]> git.lizzy.rs Git - rust.git/commitdiff
generate fewer basic blocks for variant switches
authorScott A Carr <s.carr1024@gmail.com>
Wed, 1 Jun 2016 00:08:00 +0000 (17:08 -0700)
committerScott A Carr <s.carr1024@gmail.com>
Wed, 1 Jun 2016 00:08:00 +0000 (17:08 -0700)
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs

index c1a0e1f9a6900b622122e2b153cce60180a30eed..bdaaafc1d8f0e01fd11657fa7364abb4f904c519 100644 (file)
@@ -266,6 +266,7 @@ enum TestKind<'tcx> {
     // test the branches of enum
     Switch {
         adt_def: AdtDef<'tcx>,
+        variants: Vec<bool>,
     },
 
     // test the branches of enum
@@ -391,9 +392,11 @@ fn match_candidates<'pat>(&mut self,
 
     fn join_otherwise_blocks(&mut self,
                              span: Span,
-                             otherwise: Vec<BasicBlock>)
+                             mut otherwise: Vec<BasicBlock>)
                              -> BasicBlock
     {
+        otherwise.sort();
+        otherwise.dedup(); // variant switches can introduce duplicate target blocks
         let scope_id = self.innermost_scope_id();
         if otherwise.len() == 1 {
             otherwise[0]
@@ -502,6 +505,15 @@ fn test_candidates<'pat>(&mut self,
                     }
                 }
             }
+            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 @@ fn test_candidates<'pat>(&mut self,
                                                           &mut target_candidates))
                       .count();
         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
         // apply. Collect a list of blocks where control flow will
index e53584a3f8b11ee42b733572caaa30f1b1da8631..307c8ecd832007c82054b5ea57db904e9d364dab 100644 (file)
@@ -33,7 +33,10 @@ pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
             PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
                 Test {
                     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 @@ pub fn add_cases_to_switch<'pat>(&mut self,
                        });
                 true
             }
-
+            PatternKind::Variant { .. } => {
+                panic!("you should have called add_cases_to_switch_switch instead!");
+            }
             PatternKind::Range { .. } |
-            PatternKind::Variant { .. } |
             PatternKind::Slice { .. } |
             PatternKind::Array { .. } |
             PatternKind::Wild |
@@ -140,6 +144,30 @@ pub fn add_cases_to_switch<'pat>(&mut self,
         }
     }
 
+    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.
     pub fn perform_test(&mut self,
                         block: BasicBlock,
@@ -148,11 +176,26 @@ pub fn perform_test(&mut self,
                         -> Vec<BasicBlock> {
         let scope_id = self.innermost_scope_id();
         match test.kind {
-            TestKind::Switch { adt_def } => {
+            TestKind::Switch { adt_def, ref variants } => {
                 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())
-                                          .collect();
+                                          .collect()
+                };
                 self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
                     discr: lvalue.clone(),
                     adt_def: adt_def,
@@ -383,7 +426,7 @@ pub fn sort_candidate<'pat>(&mut self,
         match test.kind {
             // If we are performing a variant switch, then this
             // 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 {
                     PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
                         assert_eq!(adt_def, tested_adt_def);