Skip to content

Commit 9dc3967

Browse files
committed
funnel all unwind paths through a single Resume block
This simplifies analysis and borrow-checking because liveness at the resume point can always be simply propagated. Later on, the "dead" Resumes are removed.
1 parent 485476c commit 9dc3967

25 files changed

+261
-261
lines changed

src/librustc_mir/build/expr/into.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
255255
this.cfg.terminate(block, source_info, TerminatorKind::Call {
256256
func: fun,
257257
args,
258-
cleanup,
258+
cleanup: Some(cleanup),
259259
destination: if diverges {
260260
None
261261
} else {

src/librustc_mir/build/matches/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
315315
}),
316316
args: vec![val, expect],
317317
destination: Some((eq_result.clone(), eq_block)),
318-
cleanup,
318+
cleanup: Some(cleanup),
319319
});
320320

321321
// check the result

src/librustc_mir/build/scope.rs

+38-27
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
383383
assert_eq!(scope.region_scope, region_scope.0);
384384

385385
self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
386+
let resume_block = self.resume_block();
386387
unpack!(block = build_scope_drops(&mut self.cfg,
388+
resume_block,
387389
&scope,
388390
&self.scopes,
389391
block,
@@ -422,6 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
422424
}
423425

424426
{
427+
let resume_block = self.resume_block();
425428
let mut rest = &mut self.scopes[(len - scope_count)..];
426429
while let Some((scope, rest_)) = {rest}.split_last_mut() {
427430
rest = rest_;
@@ -441,6 +444,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
441444
self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
442445

443446
unpack!(block = build_scope_drops(&mut self.cfg,
447+
resume_block,
444448
scope,
445449
rest,
446450
block,
@@ -468,6 +472,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
468472
let src_info = self.scopes[0].source_info(self.fn_span);
469473
let mut block = self.cfg.start_new_block();
470474
let result = block;
475+
let resume_block = self.resume_block();
471476
let mut rest = &mut self.scopes[..];
472477

473478
while let Some((scope, rest_)) = {rest}.split_last_mut() {
@@ -491,6 +496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
491496
self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope);
492497

493498
unpack!(block = build_scope_drops(&mut self.cfg,
499+
resume_block,
494500
scope,
495501
rest,
496502
block,
@@ -701,18 +707,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
701707
/// This path terminates in Resume. Returns the start of the path.
702708
/// See module comment for more details. None indicates there’s no
703709
/// cleanup to do at this point.
704-
pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
710+
pub fn diverge_cleanup(&mut self) -> BasicBlock {
705711
self.diverge_cleanup_gen(false)
706712
}
707713

708-
fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
709-
if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
710-
return None;
714+
fn resume_block(&mut self) -> BasicBlock {
715+
if let Some(target) = self.cached_resume_block {
716+
target
717+
} else {
718+
let resumeblk = self.cfg.start_new_cleanup_block();
719+
self.cfg.terminate(resumeblk,
720+
SourceInfo {
721+
scope: ARGUMENT_VISIBILITY_SCOPE,
722+
span: self.fn_span
723+
},
724+
TerminatorKind::Resume);
725+
self.cached_resume_block = Some(resumeblk);
726+
resumeblk
711727
}
712-
assert!(!self.scopes.is_empty()); // or `any` above would be false
728+
}
729+
730+
fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
731+
// To start, create the resume terminator.
732+
let mut target = self.resume_block();
713733

714-
let Builder { ref mut cfg, ref mut scopes,
715-
ref mut cached_resume_block, .. } = *self;
734+
let Builder { ref mut cfg, ref mut scopes, .. } = *self;
716735

717736
// Build up the drops in **reverse** order. The end result will
718737
// look like:
@@ -725,23 +744,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
725744
// store caches. If everything is cached, we'll just walk right
726745
// to left reading the cached results but never created anything.
727746

728-
// To start, create the resume terminator.
729-
let mut target = if let Some(target) = *cached_resume_block {
730-
target
731-
} else {
732-
let resumeblk = cfg.start_new_cleanup_block();
733-
cfg.terminate(resumeblk,
734-
scopes[0].source_info(self.fn_span),
735-
TerminatorKind::Resume);
736-
*cached_resume_block = Some(resumeblk);
737-
resumeblk
738-
};
739-
740-
for scope in scopes.iter_mut() {
741-
target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
742-
scope, target, generator_drop);
747+
if scopes.iter().any(|scope| scope.needs_cleanup) {
748+
for scope in scopes.iter_mut() {
749+
target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
750+
scope, target, generator_drop);
751+
}
743752
}
744-
Some(target)
753+
754+
target
745755
}
746756

747757
/// Utility function for *non*-scope code to build their own drops
@@ -760,7 +770,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
760770
TerminatorKind::Drop {
761771
location,
762772
target: next_target,
763-
unwind: diverge_target,
773+
unwind: Some(diverge_target),
764774
});
765775
next_target.unit()
766776
}
@@ -779,7 +789,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
779789
location,
780790
value,
781791
target: next_target,
782-
unwind: diverge_target,
792+
unwind: Some(diverge_target),
783793
});
784794
next_target.unit()
785795
}
@@ -804,7 +814,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
804814
expected,
805815
msg,
806816
target: success_block,
807-
cleanup,
817+
cleanup: Some(cleanup),
808818
});
809819

810820
success_block
@@ -813,6 +823,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
813823

814824
/// Builds drops for pop_scope and exit_scope.
815825
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
826+
resume_block: BasicBlock,
816827
scope: &Scope<'tcx>,
817828
earlier_scopes: &[Scope<'tcx>],
818829
mut block: BasicBlock,
@@ -868,7 +879,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
868879
cfg.terminate(block, source_info, TerminatorKind::Drop {
869880
location: drop_data.location.clone(),
870881
target: next,
871-
unwind: on_diverge
882+
unwind: Some(on_diverge.unwrap_or(resume_block))
872883
});
873884
block = next;
874885
}

src/librustc_mir/transform/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
260260
deaggregator::Deaggregator,
261261
copy_prop::CopyPropagation,
262262
remove_noop_landing_pads::RemoveNoopLandingPads,
263+
simplify::SimplifyCfg::new("final"),
263264
simplify::SimplifyLocals,
264265

265266
generator::StateTransform,

src/librustc_mir/transform/simplify.rs

-34
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
124124
self.collapse_goto_chain(successor, &mut changed);
125125
}
126126

127-
changed |= self.simplify_unwind(&mut terminator);
128-
129127
let mut new_stmts = vec![];
130128
let mut inner_changed = true;
131129
while inner_changed {
@@ -238,38 +236,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
238236
true
239237
}
240238

241-
// turn an unwind branch to a resume block into a None
242-
fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
243-
let unwind = match terminator.kind {
244-
TerminatorKind::Drop { ref mut unwind, .. } |
245-
TerminatorKind::DropAndReplace { ref mut unwind, .. } |
246-
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
247-
TerminatorKind::Assert { cleanup: ref mut unwind, .. } =>
248-
unwind,
249-
_ => return false
250-
};
251-
252-
if let &mut Some(unwind_block) = unwind {
253-
let is_resume_block = match self.basic_blocks[unwind_block] {
254-
BasicBlockData {
255-
ref statements,
256-
terminator: Some(Terminator {
257-
kind: TerminatorKind::Resume, ..
258-
}), ..
259-
} if statements.is_empty() => true,
260-
_ => false
261-
};
262-
if is_resume_block {
263-
debug!("simplifying unwind to {:?} from {:?}",
264-
unwind_block, terminator.source_info);
265-
*unwind = None;
266-
}
267-
return is_resume_block;
268-
}
269-
270-
false
271-
}
272-
273239
fn strip_nops(&mut self) {
274240
for blk in self.basic_blocks.iter_mut() {
275241
blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {

src/test/mir-opt/basic_assignment.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ fn main() {
5050
// StorageLive(_5);
5151
// StorageLive(_6);
5252
// _6 = move _4;
53-
// replace(_5 <- move _6) -> [return: bb1, unwind: bb5];
53+
// replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
5454
// }
5555
// bb1: {
56-
// drop(_6) -> [return: bb6, unwind: bb4];
56+
// resume;
5757
// }
5858
// bb2: {
59-
// resume;
59+
// drop(_6) -> [return: bb6, unwind: bb4];
6060
// }
6161
// bb3: {
62-
// drop(_4) -> bb2;
62+
// drop(_4) -> bb1;
6363
// }
6464
// bb4: {
6565
// drop(_5) -> bb3;
@@ -74,7 +74,7 @@ fn main() {
7474
// }
7575
// bb7: {
7676
// StorageDead(_5);
77-
// drop(_4) -> bb8;
77+
// drop(_4) -> [return: bb8, unwind: bb1];
7878
// }
7979
// bb8: {
8080
// StorageDead(_4);

src/test/mir-opt/box_expr.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,20 @@ impl Drop for S {
4444
// StorageLive(_1);
4545
// StorageLive(_2);
4646
// _2 = Box(S);
47-
// (*_2) = const S::new() -> [return: bb1, unwind: bb3];
47+
// (*_2) = const S::new() -> [return: bb2, unwind: bb3];
4848
// }
4949
//
5050
// bb1: {
51-
// _1 = move _2;
52-
// drop(_2) -> bb4;
51+
// resume;
5352
// }
5453
//
5554
// bb2: {
56-
// resume;
55+
// _1 = move _2;
56+
// drop(_2) -> bb4;
5757
// }
5858
//
5959
// bb3: {
60-
// drop(_2) -> bb2;
60+
// drop(_2) -> bb1;
6161
// }
6262
//
6363
// bb4: {
@@ -72,7 +72,7 @@ impl Drop for S {
7272
// }
7373
//
7474
// bb6: {
75-
// drop(_1) -> bb2;
75+
// drop(_1) -> bb1;
7676
// }
7777
//
7878
// bb7: {

src/test/mir-opt/end_region_4.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ fn foo(i: i32) {
5151
// _3 = &'26_2rs _2;
5252
// StorageLive(_5);
5353
// _5 = (*_3);
54-
// _4 = const foo(move _5) -> [return: bb1, unwind: bb3];
54+
// _4 = const foo(move _5) -> [return: bb2, unwind: bb3];
5555
// }
5656
// bb1: {
57+
// resume;
58+
// }
59+
// bb2: {
5760
// StorageDead(_5);
5861
// StorageLive(_6);
5962
// _6 = &'26_4rs _2;
@@ -63,14 +66,11 @@ fn foo(i: i32) {
6366
// EndRegion('26_2rs);
6467
// StorageDead(_3);
6568
// StorageDead(_2);
66-
// drop(_1) -> bb4;
67-
// }
68-
// bb2: {
69-
// resume;
69+
// drop(_1) -> [return: bb4, unwind: bb1];
7070
// }
7171
// bb3: {
7272
// EndRegion('26_2rs);
73-
// drop(_1) -> bb2;
73+
// drop(_1) -> bb1;
7474
// }
7575
// bb4: {
7676
// StorageDead(_1);

src/test/mir-opt/end_region_5.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
4343
// _4 = &'14s _1;
4444
// _3 = [closure@NodeId(18)] { d: move _4 };
4545
// StorageDead(_4);
46-
// _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
46+
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
4747
// }
4848
// bb1: {
49+
// resume;
50+
// }
51+
// bb2: {
4952
// EndRegion('14s);
5053
// StorageDead(_3);
5154
// _0 = ();
52-
// drop(_1) -> bb4;
53-
// }
54-
// bb2: {
55-
// resume;
55+
// drop(_1) -> [return: bb4, unwind: bb1];
5656
// }
5757
// bb3: {
5858
// EndRegion('14s);
59-
// drop(_1) -> bb2;
59+
// drop(_1) -> bb1;
6060
// }
6161
// bb4: {
6262
// StorageDead(_1);

src/test/mir-opt/end_region_6.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
4343
// _4 = &'19s _1;
4444
// _3 = [closure@NodeId(22)] { d: move _4 };
4545
// StorageDead(_4);
46-
// _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
46+
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
4747
// }
4848
// bb1: {
49+
// resume;
50+
// }
51+
// bb2: {
4952
// EndRegion('19s);
5053
// StorageDead(_3);
5154
// _0 = ();
52-
// drop(_1) -> bb4;
53-
// }
54-
// bb2: {
55-
// resume;
55+
// drop(_1) -> [return: bb4, unwind: bb1];
5656
// }
5757
// bb3: {
5858
// EndRegion('19s);
59-
// drop(_1) -> bb2;
59+
// drop(_1) -> bb1;
6060
// }
6161
// bb4: {
6262
// StorageDead(_1);

0 commit comments

Comments
 (0)