Skip to content

Commit 85c1027

Browse files
committed
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.
1 parent 1447daa commit 85c1027

File tree

8 files changed

+181
-153
lines changed

8 files changed

+181
-153
lines changed

src/librustc_mir/build/scope.rs

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ pub struct BreakableScope<'tcx> {
200200
pub break_destination: Lvalue<'tcx>,
201201
}
202202

203+
impl DropKind {
204+
fn may_panic(&self) -> bool {
205+
match *self {
206+
DropKind::Value { .. } => true,
207+
DropKind::Storage => false
208+
}
209+
}
210+
}
211+
203212
impl<'tcx> Scope<'tcx> {
204213
/// Invalidate all the cached blocks in the scope.
205214
///
@@ -337,9 +346,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
337346
mut block: BasicBlock)
338347
-> BlockAnd<()> {
339348
debug!("pop_scope({:?}, {:?})", extent, block);
340-
// We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
341-
// to make sure all the `cached_block`s are filled in.
342-
self.diverge_cleanup();
349+
// If we are emitting a `drop` statement, we need to have the cached
350+
// diverge cleanup pads ready in case that drop panics.
351+
let may_panic =
352+
self.scopes.last().unwrap().drops.iter().any(|s| s.kind.may_panic());
353+
if may_panic {
354+
self.diverge_cleanup();
355+
}
343356
let scope = self.scopes.pop().unwrap();
344357
assert_eq!(scope.extent, extent.0);
345358
unpack!(block = build_scope_drops(&mut self.cfg,
@@ -370,6 +383,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
370383
let len = self.scopes.len();
371384
assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
372385
let tmp = self.get_unit_temp();
386+
387+
// If we are emitting a `drop` statement, we need to have the cached
388+
// diverge cleanup pads ready in case that drop panics.
389+
let may_panic =
390+
self.scopes[(len - scope_count)..].iter().any(|s| s.drops.iter().any(|s| s.kind.may_panic()));
391+
if may_panic {
392+
self.diverge_cleanup();
393+
}
394+
373395
{
374396
let mut rest = &mut self.scopes[(len - scope_count)..];
375397
while let Some((scope, rest_)) = {rest}.split_last_mut() {
@@ -736,45 +758,48 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
736758
mut block: BasicBlock,
737759
arg_count: usize)
738760
-> BlockAnd<()> {
761+
debug!("build_scope_drops({:?} -> {:?})", block, scope);
739762
let mut iter = scope.drops.iter().rev().peekable();
740763
while let Some(drop_data) = iter.next() {
741764
let source_info = scope.source_info(drop_data.span);
742-
if let DropKind::Value { .. } = drop_data.kind {
743-
// Try to find the next block with its cached block
744-
// for us to diverge into in case the drop panics.
745-
let on_diverge = iter.peek().iter().filter_map(|dd| {
746-
match dd.kind {
747-
DropKind::Value { cached_block } => cached_block,
748-
DropKind::Storage => None
749-
}
750-
}).next();
751-
// If there’s no `cached_block`s within current scope,
752-
// we must look for one in the enclosing scope.
753-
let on_diverge = on_diverge.or_else(||{
754-
earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
755-
});
756-
let next = cfg.start_new_block();
757-
cfg.terminate(block, source_info, TerminatorKind::Drop {
758-
location: drop_data.location.clone(),
759-
target: next,
760-
unwind: on_diverge
761-
});
762-
block = next;
763-
}
764765
match drop_data.kind {
765-
DropKind::Value { .. } |
766-
DropKind::Storage => {
767-
// Only temps and vars need their storage dead.
768-
match drop_data.location {
769-
Lvalue::Local(index) if index.index() > arg_count => {}
770-
_ => continue
771-
}
766+
DropKind::Value { .. } => {
767+
// Try to find the next block with its cached block
768+
// for us to diverge into in case the drop panics.
769+
let on_diverge = iter.peek().iter().filter_map(|dd| {
770+
match dd.kind {
771+
DropKind::Value { cached_block: None } =>
772+
span_bug!(drop_data.span, "cached block not present?"),
773+
DropKind::Value { cached_block } => cached_block,
774+
DropKind::Storage => None
775+
}
776+
}).next();
777+
// If there’s no `cached_block`s within current scope,
778+
// we must look for one in the enclosing scope.
779+
let on_diverge = on_diverge.or_else(|| {
780+
earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
781+
});
782+
let next = cfg.start_new_block();
783+
cfg.terminate(block, source_info, TerminatorKind::Drop {
784+
location: drop_data.location.clone(),
785+
target: next,
786+
unwind: on_diverge
787+
});
788+
block = next;
789+
}
790+
DropKind::Storage => {}
791+
}
772792

793+
// Drop the storage for both value and storage drops.
794+
// Only temps and vars need their storage dead.
795+
match drop_data.location {
796+
Lvalue::Local(index) if index.index() > arg_count => {
773797
cfg.push(block, Statement {
774798
source_info: source_info,
775799
kind: StatementKind::StorageDead(drop_data.location.clone())
776800
});
777801
}
802+
_ => continue
778803
}
779804
}
780805
block.unit()

src/test/mir-opt/basic_assignment.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,39 @@ fn main() {
4747
// StorageDead(_3);
4848
// StorageLive(_4);
4949
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
50+
// StorageLive(_5);
5051
// StorageLive(_6);
51-
// StorageLive(_7);
52-
// _7 = _4;
53-
// replace(_6 <- _7) -> [return: bb6, unwind: bb7];
52+
// _6 = _4;
53+
// replace(_5 <- _6) -> [return: bb1, unwind: bb7];
5454
// }
5555
// bb1: {
56-
// resume;
56+
// drop(_6) -> [return: bb8, unwind: bb5];
5757
// }
5858
// bb2: {
59-
// drop(_4) -> bb1;
59+
// resume;
6060
// }
6161
// bb3: {
62-
// goto -> bb2;
62+
// drop(_4) -> bb2;
6363
// }
6464
// bb4: {
65-
// drop(_6) -> bb3;
65+
// goto -> bb3;
6666
// }
6767
// bb5: {
68-
// goto -> bb4;
68+
// drop(_5) -> bb4;
6969
// }
7070
// bb6: {
71-
// drop(_7) -> [return: bb8, unwind: bb4];
71+
// goto -> bb5;
7272
// }
7373
// bb7: {
74-
// drop(_7) -> bb5;
74+
// drop(_6) -> bb6;
7575
// }
7676
// bb8: {
77-
// StorageDead(_7);
77+
// StorageDead(_6);
7878
// _0 = ();
79-
// drop(_6) -> [return: bb9, unwind: bb2];
79+
// drop(_5) -> [return: bb9, unwind: bb3];
8080
// }
8181
// bb9: {
82-
// StorageDead(_6);
82+
// StorageDead(_5);
8383
// drop(_4) -> bb10;
8484
// }
8585
// bb10: {

src/test/mir-opt/end_region_4.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,41 +32,41 @@ fn foo(i: i32) {
3232
// START rustc.node4.SimplifyCfg-qualify-consts.after.mir
3333
// let mut _0: ();
3434
// let _1: D;
35-
// let _3: i32;
36-
// let _4: &'6_2rce i32;
35+
// let _2: i32;
36+
// let _3: &'6_2rce i32;
3737
// let _7: &'6_4rce i32;
38-
// let mut _5: ();
39-
// let mut _6: i32;
40-
//
38+
// let mut _4: ();
39+
// let mut _5: i32;
40+
// let mut _6: ();
4141
// bb0: {
4242
// StorageLive(_1);
4343
// _1 = D::{{constructor}}(const 0i32,);
44+
// StorageLive(_2);
45+
// _2 = const 0i32;
4446
// StorageLive(_3);
45-
// _3 = const 0i32;
46-
// StorageLive(_4);
47-
// _4 = &'6_2rce _3;
48-
// StorageLive(_6);
49-
// _6 = (*_4);
50-
// _5 = const foo(_6) -> [return: bb2, unwind: bb3];
47+
// _3 = &'6_2rce _2;
48+
// StorageLive(_5);
49+
// _5 = (*_3);
50+
// _4 = const foo(_5) -> [return: bb1, unwind: bb3];
5151
// }
5252
// bb1: {
53-
// resume;
54-
// }
55-
// bb2: {
56-
// StorageDead(_6);
53+
// StorageDead(_5);
5754
// StorageLive(_7);
58-
// _7 = &'6_4rce _3;
55+
// _7 = &'6_4rce _2;
5956
// _0 = ();
6057
// StorageDead(_7);
6158
// EndRegion('6_4rce);
62-
// StorageDead(_4);
63-
// EndRegion('6_2rce);
6459
// StorageDead(_3);
60+
// EndRegion('6_2rce);
61+
// StorageDead(_2);
6562
// drop(_1) -> bb4;
6663
// }
64+
// bb2: {
65+
// resume;
66+
// }
6767
// bb3: {
6868
// EndRegion('6_2rce);
69-
// drop(_1) -> bb1;
69+
// drop(_1) -> bb2;
7070
// }
7171
// bb4: {
7272
// StorageDead(_1);

src/test/mir-opt/end_region_5.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,31 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
3131
// let mut _0: ();
3232
// let _1: D;
3333
// let mut _2: ();
34-
// let mut _3: ();
35-
// let mut _4: [closure@NodeId(18) d: &'19mce D];
36-
// let mut _5: &'19mce D;
37-
//
34+
// let mut _3: [closure@NodeId(18) d:&'19mce D];
35+
// let mut _4: &'19mce D;
36+
// let mut _5: ();
3837
// bb0: {
3938
// StorageLive(_1);
4039
// _1 = D::{{constructor}}(const 0i32,);
40+
// StorageLive(_3);
4141
// StorageLive(_4);
42-
// StorageLive(_5);
43-
// _5 = &'19mce _1;
44-
// _4 = [closure@NodeId(18)] { d: _5 };
45-
// StorageDead(_5);
46-
// _3 = const foo(_4) -> [return: bb2, unwind: bb3];
42+
// _4 = &'19mce _1;
43+
// _3 = [closure@NodeId(18)] { d: _4 };
44+
// StorageDead(_4);
45+
// _2 = const foo(_3) -> [return: bb1, unwind: bb3];
4746
// }
4847
// bb1: {
49-
// resume;
50-
// }
51-
// bb2: {
52-
// StorageDead(_4);
48+
// StorageDead(_3);
5349
// EndRegion('19mce);
5450
// _0 = ();
5551
// drop(_1) -> bb4;
5652
// }
53+
// bb2: {
54+
// resume;
55+
// }
5756
// bb3: {
5857
// EndRegion('19mce);
59-
// drop(_1) -> bb1;
58+
// drop(_1) -> bb2;
6059
// }
6160
// bb4: {
6261
// StorageDead(_1);

src/test/mir-opt/end_region_6.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,35 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
2727

2828
// END RUST SOURCE
2929
// START rustc.node4.SimplifyCfg-qualify-consts.after.mir
30+
// fn main() -> () {
3031
// let mut _0: ();
3132
// let _1: D;
3233
// let mut _2: ();
33-
// let mut _3: ();
34-
// let mut _4: [closure@NodeId(22) d:&'23mce D];
35-
// let mut _5: &'23mce D;
36-
//
34+
// let mut _3: [closure@NodeId(22) d:&'23mce D];
35+
// let mut _4: &'23mce D;
36+
// let mut _5: ();
3737
// bb0: {
3838
// StorageLive(_1);
3939
// _1 = D::{{constructor}}(const 0i32,);
40+
// StorageLive(_3);
4041
// StorageLive(_4);
41-
// StorageLive(_5);
42-
// _5 = &'23mce _1;
43-
// _4 = [closure@NodeId(22)] { d: _5 };
44-
// StorageDead(_5);
45-
// _3 = const foo(_4) -> [return: bb2, unwind: bb3];
42+
// _4 = &'23mce _1;
43+
// _3 = [closure@NodeId(22)] { d: _4 };
44+
// StorageDead(_4);
45+
// _2 = const foo(_3) -> [return: bb1, unwind: bb3];
4646
// }
4747
// bb1: {
48-
// resume;
49-
// }
50-
// bb2: {
51-
// StorageDead(_4);
48+
// StorageDead(_3);
5249
// EndRegion('23mce);
5350
// _0 = ();
5451
// drop(_1) -> bb4;
5552
// }
53+
// bb2: {
54+
// resume;
55+
// }
5656
// bb3: {
5757
// EndRegion('23mce);
58-
// drop(_1) -> bb1;
58+
// drop(_1) -> bb2;
5959
// }
6060
// bb4: {
6161
// StorageDead(_1);

0 commit comments

Comments
 (0)