about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-07-31 23:25:27 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-08-01 00:12:30 +0300
commit85c102757a744956989e5217484a6f650eed3146 (patch)
tree9cc163e837f8b8fb9c1202f82edd32f66887ff0b
parent1447daa01ddc6536724eb4f3e10972404da0cd56 (diff)
downloadrust-85c102757a744956989e5217484a6f650eed3146.tar.gz
rust-85c102757a744956989e5217484a6f650eed3146.zip
rustc_mir: don't build unused unwind cleanup blocks
The unused blocks are removed by SimplifyCfg, but they can cause a
significant performance slowdown before they are removed.
-rw-r--r--src/librustc_mir/build/scope.rs89
-rw-r--r--src/test/mir-opt/basic_assignment.rs26
-rw-r--r--src/test/mir-opt/end_region_4.rs38
-rw-r--r--src/test/mir-opt/end_region_5.rs27
-rw-r--r--src/test/mir-opt/end_region_6.rs28
-rw-r--r--src/test/mir-opt/end_region_7.rs36
-rw-r--r--src/test/mir-opt/end_region_8.rs75
-rw-r--r--src/test/mir-opt/issue-41110.rs15
8 files changed, 181 insertions, 153 deletions
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 2b52198c250..bf39e52bd1b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -200,6 +200,15 @@ pub struct BreakableScope<'tcx> {
     pub break_destination: Lvalue<'tcx>,
 }
 
+impl DropKind {
+    fn may_panic(&self) -> bool {
+        match *self {
+            DropKind::Value { .. } => true,
+            DropKind::Storage => false
+        }
+    }
+}
+
 impl<'tcx> Scope<'tcx> {
     /// Invalidate all the cached blocks in the scope.
     ///
@@ -337,9 +346,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                      mut block: BasicBlock)
                      -> BlockAnd<()> {
         debug!("pop_scope({:?}, {:?})", extent, block);
-        // We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
-        // to make sure all the `cached_block`s are filled in.
-        self.diverge_cleanup();
+        // If we are emitting a `drop` statement, we need to have the cached
+        // diverge cleanup pads ready in case that drop panics.
+        let may_panic =
+            self.scopes.last().unwrap().drops.iter().any(|s| s.kind.may_panic());
+        if may_panic {
+            self.diverge_cleanup();
+        }
         let scope = self.scopes.pop().unwrap();
         assert_eq!(scope.extent, extent.0);
         unpack!(block = build_scope_drops(&mut self.cfg,
@@ -370,6 +383,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let len = self.scopes.len();
         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
         let tmp = self.get_unit_temp();
+
+        // If we are emitting a `drop` statement, we need to have the cached
+        // diverge cleanup pads ready in case that drop panics.
+        let may_panic =
+            self.scopes[(len - scope_count)..].iter().any(|s| s.drops.iter().any(|s| s.kind.may_panic()));
+        if may_panic {
+            self.diverge_cleanup();
+        }
+
         {
         let mut rest = &mut self.scopes[(len - scope_count)..];
         while let Some((scope, rest_)) = {rest}.split_last_mut() {
@@ -736,45 +758,48 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
                            mut block: BasicBlock,
                            arg_count: usize)
                            -> BlockAnd<()> {
+    debug!("build_scope_drops({:?} -> {:?})", block, scope);
     let mut iter = scope.drops.iter().rev().peekable();
     while let Some(drop_data) = iter.next() {
         let source_info = scope.source_info(drop_data.span);
-        if let DropKind::Value { .. } = drop_data.kind {
-            // Try to find the next block with its cached block
-            // for us to diverge into in case the drop panics.
-            let on_diverge = iter.peek().iter().filter_map(|dd| {
-                match dd.kind {
-                    DropKind::Value { cached_block } => cached_block,
-                    DropKind::Storage => None
-                }
-            }).next();
-            // If there’s no `cached_block`s within current scope,
-            // we must look for one in the enclosing scope.
-            let on_diverge = on_diverge.or_else(||{
-                earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
-            });
-            let next = cfg.start_new_block();
-            cfg.terminate(block, source_info, TerminatorKind::Drop {
-                location: drop_data.location.clone(),
-                target: next,
-                unwind: on_diverge
-            });
-            block = next;
-        }
         match drop_data.kind {
-            DropKind::Value { .. } |
-            DropKind::Storage => {
-                // Only temps and vars need their storage dead.
-                match drop_data.location {
-                    Lvalue::Local(index) if index.index() > arg_count => {}
-                    _ => continue
-                }
+            DropKind::Value { .. } => {
+                // Try to find the next block with its cached block
+                // for us to diverge into in case the drop panics.
+                let on_diverge = iter.peek().iter().filter_map(|dd| {
+                    match dd.kind {
+                        DropKind::Value { cached_block: None } =>
+                            span_bug!(drop_data.span, "cached block not present?"),
+                        DropKind::Value { cached_block } => cached_block,
+                        DropKind::Storage => None
+                    }
+                }).next();
+                // If there’s no `cached_block`s within current scope,
+                // we must look for one in the enclosing scope.
+                let on_diverge = on_diverge.or_else(|| {
+                    earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
+                });
+                let next = cfg.start_new_block();
+                cfg.terminate(block, source_info, TerminatorKind::Drop {
+                    location: drop_data.location.clone(),
+                    target: next,
+                    unwind: on_diverge
+                });
+                block = next;
+            }
+            DropKind::Storage => {}
+        }
 
+        // Drop the storage for both value and storage drops.
+        // Only temps and vars need their storage dead.
+        match drop_data.location {
+            Lvalue::Local(index) if index.index() > arg_count => {
                 cfg.push(block, Statement {
                     source_info: source_info,
                     kind: StatementKind::StorageDead(drop_data.location.clone())
                 });
             }
+            _ => continue
         }
     }
     block.unit()
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index ef5158a403a..6afc344ced8 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -47,39 +47,39 @@ fn main() {
 //         StorageDead(_3);
 //         StorageLive(_4);
 //         _4 = std::option::Option<std::boxed::Box<u32>>::None;
+//         StorageLive(_5);
 //         StorageLive(_6);
-//         StorageLive(_7);
-//         _7 = _4;
-//         replace(_6 <- _7) -> [return: bb6, unwind: bb7];
+//         _6 = _4;
+//         replace(_5 <- _6) -> [return: bb1, unwind: bb7];
 //     }
 //     bb1: {
-//         resume;
+//         drop(_6) -> [return: bb8, unwind: bb5];
 //     }
 //     bb2: {
-//         drop(_4) -> bb1;
+//         resume;
 //     }
 //     bb3: {
-//         goto -> bb2;
+//         drop(_4) -> bb2;
 //     }
 //     bb4: {
-//         drop(_6) -> bb3;
+//         goto -> bb3;
 //     }
 //     bb5: {
-//         goto -> bb4;
+//         drop(_5) -> bb4;
 //     }
 //     bb6: {
-//         drop(_7) -> [return: bb8, unwind: bb4];
+//         goto -> bb5;
 //     }
 //     bb7: {
-//         drop(_7) -> bb5;
+//         drop(_6) -> bb6;
 //     }
 //     bb8: {
-//         StorageDead(_7);
+//         StorageDead(_6);
 //         _0 = ();
-//         drop(_6) -> [return: bb9, unwind: bb2];
+//         drop(_5) -> [return: bb9, unwind: bb3];
 //     }
 //     bb9: {
-//         StorageDead(_6);
+//         StorageDead(_5);
 //         drop(_4) -> bb10;
 //     }
 //     bb10: {
diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs
index 16ade9f96fd..bfb1b3b6528 100644
--- a/src/test/mir-opt/end_region_4.rs
+++ b/src/test/mir-opt/end_region_4.rs
@@ -32,41 +32,41 @@ fn foo(i: i32) {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     let _1: D;
-//     let _3: i32;
-//     let _4: &'6_2rce i32;
+//     let _2: i32;
+//     let _3: &'6_2rce i32;
 //     let _7: &'6_4rce i32;
-//     let mut _5: ();
-//     let mut _6: i32;
-//
+//     let mut _4: ();
+//     let mut _5: i32;
+//     let mut _6: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
+//         StorageLive(_2);
+//         _2 = const 0i32;
 //         StorageLive(_3);
-//         _3 = const 0i32;
-//         StorageLive(_4);
-//         _4 = &'6_2rce _3;
-//         StorageLive(_6);
-//         _6 = (*_4);
-//         _5 = const foo(_6) -> [return: bb2, unwind: bb3];
+//         _3 = &'6_2rce _2;
+//         StorageLive(_5);
+//         _5 = (*_3);
+//         _4 = const foo(_5) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
-//         resume;
-//     }
-//     bb2: {
-//         StorageDead(_6);
+//         StorageDead(_5);
 //         StorageLive(_7);
-//         _7 = &'6_4rce _3;
+//         _7 = &'6_4rce _2;
 //         _0 = ();
 //         StorageDead(_7);
 //         EndRegion('6_4rce);
-//         StorageDead(_4);
-//         EndRegion('6_2rce);
 //         StorageDead(_3);
+//         EndRegion('6_2rce);
+//         StorageDead(_2);
 //         drop(_1) -> bb4;
 //     }
+//     bb2: {
+//         resume;
+//     }
 //     bb3: {
 //         EndRegion('6_2rce);
-//         drop(_1) -> bb1;
+//         drop(_1) -> bb2;
 //     }
 //     bb4: {
 //         StorageDead(_1);
diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs
index 513632a4cdf..773a348a939 100644
--- a/src/test/mir-opt/end_region_5.rs
+++ b/src/test/mir-opt/end_region_5.rs
@@ -31,32 +31,31 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _0: ();
 //     let _1: D;
 //     let mut _2: ();
-//     let mut _3: ();
-//     let mut _4: [closure@NodeId(18) d: &'19mce D];
-//     let mut _5: &'19mce D;
-//
+//     let mut _3: [closure@NodeId(18) d:&'19mce D];
+//     let mut _4: &'19mce D;
+//     let mut _5: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
+//         StorageLive(_3);
 //         StorageLive(_4);
-//         StorageLive(_5);
-//         _5 = &'19mce _1;
-//         _4 = [closure@NodeId(18)] { d: _5 };
-//         StorageDead(_5);
-//         _3 = const foo(_4) -> [return: bb2, unwind: bb3];
+//         _4 = &'19mce _1;
+//         _3 = [closure@NodeId(18)] { d: _4 };
+//         StorageDead(_4);
+//         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
-//         resume;
-//     }
-//     bb2: {
-//         StorageDead(_4);
+//         StorageDead(_3);
 //         EndRegion('19mce);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
+//     bb2: {
+//         resume;
+//     }
 //     bb3: {
 //         EndRegion('19mce);
-//         drop(_1) -> bb1;
+//         drop(_1) -> bb2;
 //     }
 //     bb4: {
 //         StorageDead(_1);
diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs
index e82556f3ce4..112c93843e0 100644
--- a/src/test/mir-opt/end_region_6.rs
+++ b/src/test/mir-opt/end_region_6.rs
@@ -27,35 +27,35 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
+// fn main() -> () {
 //     let mut _0: ();
 //     let _1: D;
 //     let mut _2: ();
-//     let mut _3: ();
-//     let mut _4: [closure@NodeId(22) d:&'23mce D];
-//     let mut _5: &'23mce D;
-//
+//     let mut _3: [closure@NodeId(22) d:&'23mce D];
+//     let mut _4: &'23mce D;
+//     let mut _5: ();
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
+//         StorageLive(_3);
 //         StorageLive(_4);
-//         StorageLive(_5);
-//         _5 = &'23mce _1;
-//         _4 = [closure@NodeId(22)] { d: _5 };
-//         StorageDead(_5);
-//         _3 = const foo(_4) -> [return: bb2, unwind: bb3];
+//         _4 = &'23mce _1;
+//         _3 = [closure@NodeId(22)] { d: _4 };
+//         StorageDead(_4);
+//         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
-//         resume;
-//     }
-//     bb2: {
-//         StorageDead(_4);
+//         StorageDead(_3);
 //         EndRegion('23mce);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
+//     bb2: {
+//         resume;
+//     }
 //     bb3: {
 //         EndRegion('23mce);
-//         drop(_1) -> bb1;
+//         drop(_1) -> bb2;
 //     }
 //     bb4: {
 //         StorageDead(_1);
diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs
index 3fbd3f36865..913986ae816 100644
--- a/src/test/mir-opt/end_region_7.rs
+++ b/src/test/mir-opt/end_region_7.rs
@@ -31,18 +31,18 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _0: ();
 //     let _1: D;
 //     let mut _2: ();
-//     let mut _3: ();
-//     let mut _4: [closure@NodeId(22) d:D];
-//     let mut _5: D;
+//     let mut _3: [closure@NodeId(22) d:D];
+//     let mut _4: D;
+//     let mut _5: ();
 //
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
+//         StorageLive(_3);
 //         StorageLive(_4);
-//         StorageLive(_5);
-//         _5 = _1;
-//         _4 = [closure@NodeId(22)] { d: _5 };
-//         drop(_5) -> [return: bb4, unwind: bb3];
+//         _4 = _1;
+//         _3 = [closure@NodeId(22)] { d: _4 };
+//         drop(_4) -> [return: bb4, unwind: bb3];
 //     }
 //     bb1: {
 //         resume;
@@ -51,17 +51,17 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         drop(_1) -> bb1;
 //     }
 //     bb3: {
-//         drop(_4) -> bb2;
+//         drop(_3) -> bb2;
 //     }
 //     bb4: {
-//         StorageDead(_5);
-//         _3 = const foo(_4) -> [return: bb5, unwind: bb3];
+//         StorageDead(_4);
+//         _2 = const foo(_3) -> [return: bb5, unwind: bb3];
 //     }
 //     bb5: {
-//         drop(_4) -> [return: bb6, unwind: bb2];
+//         drop(_3) -> [return: bb6, unwind: bb2];
 //     }
 //     bb6: {
-//         StorageDead(_4);
+//         StorageDead(_3);
 //         _0 = ();
 //         drop(_1) -> bb7;
 //     }
@@ -76,16 +76,16 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
 //     let mut _0: i32;
 //     let _2: &'14_0rce D;
-//     let mut _3: ();
-//     let mut _4: i32;
+//     let mut _3: i32;
+//     let mut _4: ();
 //
 //     bb0: {
 //         StorageLive(_2);
 //         _2 = &'14_0rce (_1.0: D);
-//         StorageLive(_4);
-//         _4 = ((*_2).0: i32);
-//         _0 = _4;
-//         StorageDead(_4);
+//         StorageLive(_3);
+//         _3 = ((*_2).0: i32);
+//         _0 = _3;
+//         StorageDead(_3);
 //         StorageDead(_2);
 //         EndRegion('14_0rce);
 //         drop(_1) -> bb1;
diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs
index 7fb3f0b9118..dc8f8ea11f5 100644
--- a/src/test/mir-opt/end_region_8.rs
+++ b/src/test/mir-opt/end_region_8.rs
@@ -29,44 +29,43 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
-//     let mut _0: ();
-//     let _1: D;
-//     let _3: &'6_1rce D;
-//     let mut _2: ();
-//     let mut _4: ();
-//     let mut _5: [closure@NodeId(22) r:&'6_1rce D];
-//     let mut _6: &'6_1rce D;
-//
-//     bb0: {
-//         StorageLive(_1);
-//         _1 = D::{{constructor}}(const 0i32,);
-//         StorageLive(_3);
-//         _3 = &'6_1rce _1;
-//         StorageLive(_5);
-//         StorageLive(_6);
-//         _6 = _3;
-//         _5 = [closure@NodeId(22)] { r: _6 };
-//         StorageDead(_6);
-//         _4 = const foo(_5) -> [return: bb2, unwind: bb3];
-//     }
-//     bb1: {
-//         resume;
-//     }
-//     bb2: {
-//         StorageDead(_5);
-//         _0 = ();
-//         StorageDead(_3);
-//         EndRegion('6_1rce);
-//         drop(_1) -> bb4;
-//     }
-//     bb3: {
-//         EndRegion('6_1rce);
-//         drop(_1) -> bb1;
-//     }
-//     bb4: {
-//         StorageDead(_1);
-//         return;
-//     }
+//    let mut _0: ();
+//    let _1: D;
+//    let _2: &'6_1rce D;
+//    let mut _3: ();
+//    let mut _4: [closure@NodeId(22) r:&'6_1rce D];
+//    let mut _5: &'6_1rce D;
+//    let mut _6: ();
+//    bb0: {
+//        StorageLive(_1);
+//        _1 = D::{{constructor}}(const 0i32,);
+//        StorageLive(_2);
+//        _2 = &'6_1rce _1;
+//        StorageLive(_4);
+//        StorageLive(_5);
+//        _5 = _2;
+//        _4 = [closure@NodeId(22)] { r: _5 };
+//        StorageDead(_5);
+//        _3 = const foo(_4) -> [return: bb1, unwind: bb3];
+//    }
+//    bb1: {
+//        StorageDead(_4);
+//        _0 = ();
+//        StorageDead(_2);
+//        EndRegion('6_1rce);
+//        drop(_1) -> bb4;
+//    }
+//    bb2: {
+//        resume;
+//    }
+//    bb3: {
+//        EndRegion('6_1rce);
+//        drop(_1) -> bb2;
+//    }
+//    bb4: {
+//        StorageDead(_1);
+//        return;
+//    }
 // }
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
 
diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs
index fec635b3abf..1daa18256dc 100644
--- a/src/test/mir-opt/issue-41110.rs
+++ b/src/test/mir-opt/issue-41110.rs
@@ -34,18 +34,23 @@ impl S {
 
 // END RUST SOURCE
 // START rustc.node4.ElaborateDrops.after.mir
+//    let mut _0: ();
+//    let _1: ();
 //    let mut _2: S;
-//    let mut _3: ();
+//    let mut _3: S;
 //    let mut _4: S;
-//    let mut _5: S;
+//    let mut _5: ();
 //    let mut _6: bool;
 //
 //    bb0: {
 // END rustc.node4.ElaborateDrops.after.mir
 // START rustc.node13.ElaborateDrops.after.mir
-//    let mut _2: ();
-//    let mut _4: ();
-//    let mut _5: S;
+//    let mut _0: ();
+//    let _1: S;
+//    let mut _2: S;
+//    let mut _3: ();
+//    let mut _4: S;
+//    let mut _5: ();
 //    let mut _6: S;
 //    let mut _7: bool;
 //