Skip to content

Commit

Permalink
funnel all unwind paths through a single Resume block
Browse files Browse the repository at this point in the history
This simplifies analysis and borrow-checking because liveness at the
resume point can always be simply propagated.

Later on, the "dead" Resumes are removed.
  • Loading branch information
arielb1 committed Dec 3, 2017
1 parent 485476c commit 9dc3967
Show file tree
Hide file tree
Showing 25 changed files with 261 additions and 261 deletions.
2 changes: 1 addition & 1 deletion src/librustc_mir/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
this.cfg.terminate(block, source_info, TerminatorKind::Call {
func: fun,
args,
cleanup,
cleanup: Some(cleanup),
destination: if diverges {
None
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}),
args: vec![val, expect],
destination: Some((eq_result.clone(), eq_block)),
cleanup,
cleanup: Some(cleanup),
});

// check the result
Expand Down
65 changes: 38 additions & 27 deletions src/librustc_mir/build/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
assert_eq!(scope.region_scope, region_scope.0);

self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
let resume_block = self.resume_block();
unpack!(block = build_scope_drops(&mut self.cfg,
resume_block,
&scope,
&self.scopes,
block,
Expand Down Expand Up @@ -422,6 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}

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

unpack!(block = build_scope_drops(&mut self.cfg,
resume_block,
scope,
rest,
block,
Expand Down Expand Up @@ -468,6 +472,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let src_info = self.scopes[0].source_info(self.fn_span);
let mut block = self.cfg.start_new_block();
let result = block;
let resume_block = self.resume_block();
let mut rest = &mut self.scopes[..];

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

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

fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option<BasicBlock> {
if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
return None;
fn resume_block(&mut self) -> BasicBlock {
if let Some(target) = self.cached_resume_block {
target
} else {
let resumeblk = self.cfg.start_new_cleanup_block();
self.cfg.terminate(resumeblk,
SourceInfo {
scope: ARGUMENT_VISIBILITY_SCOPE,
span: self.fn_span
},
TerminatorKind::Resume);
self.cached_resume_block = Some(resumeblk);
resumeblk
}
assert!(!self.scopes.is_empty()); // or `any` above would be false
}

fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
// To start, create the resume terminator.
let mut target = self.resume_block();

let Builder { ref mut cfg, ref mut scopes,
ref mut cached_resume_block, .. } = *self;
let Builder { ref mut cfg, ref mut scopes, .. } = *self;

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

// To start, create the resume terminator.
let mut target = if let Some(target) = *cached_resume_block {
target
} else {
let resumeblk = cfg.start_new_cleanup_block();
cfg.terminate(resumeblk,
scopes[0].source_info(self.fn_span),
TerminatorKind::Resume);
*cached_resume_block = Some(resumeblk);
resumeblk
};

for scope in scopes.iter_mut() {
target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
scope, target, generator_drop);
if scopes.iter().any(|scope| scope.needs_cleanup) {
for scope in scopes.iter_mut() {
target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
scope, target, generator_drop);
}
}
Some(target)

target
}

/// Utility function for *non*-scope code to build their own drops
Expand All @@ -760,7 +770,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
TerminatorKind::Drop {
location,
target: next_target,
unwind: diverge_target,
unwind: Some(diverge_target),
});
next_target.unit()
}
Expand All @@ -779,7 +789,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
location,
value,
target: next_target,
unwind: diverge_target,
unwind: Some(diverge_target),
});
next_target.unit()
}
Expand All @@ -804,7 +814,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
expected,
msg,
target: success_block,
cleanup,
cleanup: Some(cleanup),
});

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

/// Builds drops for pop_scope and exit_scope.
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
resume_block: BasicBlock,
scope: &Scope<'tcx>,
earlier_scopes: &[Scope<'tcx>],
mut block: BasicBlock,
Expand Down Expand Up @@ -868,7 +879,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
cfg.terminate(block, source_info, TerminatorKind::Drop {
location: drop_data.location.clone(),
target: next,
unwind: on_diverge
unwind: Some(on_diverge.unwrap_or(resume_block))
});
block = next;
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
deaggregator::Deaggregator,
copy_prop::CopyPropagation,
remove_noop_landing_pads::RemoveNoopLandingPads,
simplify::SimplifyCfg::new("final"),
simplify::SimplifyLocals,

generator::StateTransform,
Expand Down
34 changes: 0 additions & 34 deletions src/librustc_mir/transform/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
self.collapse_goto_chain(successor, &mut changed);
}

changed |= self.simplify_unwind(&mut terminator);

let mut new_stmts = vec![];
let mut inner_changed = true;
while inner_changed {
Expand Down Expand Up @@ -238,38 +236,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
true
}

// turn an unwind branch to a resume block into a None
fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
let unwind = match terminator.kind {
TerminatorKind::Drop { ref mut unwind, .. } |
TerminatorKind::DropAndReplace { ref mut unwind, .. } |
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
TerminatorKind::Assert { cleanup: ref mut unwind, .. } =>
unwind,
_ => return false
};

if let &mut Some(unwind_block) = unwind {
let is_resume_block = match self.basic_blocks[unwind_block] {
BasicBlockData {
ref statements,
terminator: Some(Terminator {
kind: TerminatorKind::Resume, ..
}), ..
} if statements.is_empty() => true,
_ => false
};
if is_resume_block {
debug!("simplifying unwind to {:?} from {:?}",
unwind_block, terminator.source_info);
*unwind = None;
}
return is_resume_block;
}

false
}

fn strip_nops(&mut self) {
for blk in self.basic_blocks.iter_mut() {
blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
Expand Down
10 changes: 5 additions & 5 deletions src/test/mir-opt/basic_assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ fn main() {
// StorageLive(_5);
// StorageLive(_6);
// _6 = move _4;
// replace(_5 <- move _6) -> [return: bb1, unwind: bb5];
// replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
// }
// bb1: {
// drop(_6) -> [return: bb6, unwind: bb4];
// resume;
// }
// bb2: {
// resume;
// drop(_6) -> [return: bb6, unwind: bb4];
// }
// bb3: {
// drop(_4) -> bb2;
// drop(_4) -> bb1;
// }
// bb4: {
// drop(_5) -> bb3;
Expand All @@ -74,7 +74,7 @@ fn main() {
// }
// bb7: {
// StorageDead(_5);
// drop(_4) -> bb8;
// drop(_4) -> [return: bb8, unwind: bb1];
// }
// bb8: {
// StorageDead(_4);
Expand Down
12 changes: 6 additions & 6 deletions src/test/mir-opt/box_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ impl Drop for S {
// StorageLive(_1);
// StorageLive(_2);
// _2 = Box(S);
// (*_2) = const S::new() -> [return: bb1, unwind: bb3];
// (*_2) = const S::new() -> [return: bb2, unwind: bb3];
// }
//
// bb1: {
// _1 = move _2;
// drop(_2) -> bb4;
// resume;
// }
//
// bb2: {
// resume;
// _1 = move _2;
// drop(_2) -> bb4;
// }
//
// bb3: {
// drop(_2) -> bb2;
// drop(_2) -> bb1;
// }
//
// bb4: {
Expand All @@ -72,7 +72,7 @@ impl Drop for S {
// }
//
// bb6: {
// drop(_1) -> bb2;
// drop(_1) -> bb1;
// }
//
// bb7: {
Expand Down
12 changes: 6 additions & 6 deletions src/test/mir-opt/end_region_4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ fn foo(i: i32) {
// _3 = &'26_2rs _2;
// StorageLive(_5);
// _5 = (*_3);
// _4 = const foo(move _5) -> [return: bb1, unwind: bb3];
// _4 = const foo(move _5) -> [return: bb2, unwind: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// StorageDead(_5);
// StorageLive(_6);
// _6 = &'26_4rs _2;
Expand All @@ -63,14 +66,11 @@ fn foo(i: i32) {
// EndRegion('26_2rs);
// StorageDead(_3);
// StorageDead(_2);
// drop(_1) -> bb4;
// }
// bb2: {
// resume;
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('26_2rs);
// drop(_1) -> bb2;
// drop(_1) -> bb1;
// }
// bb4: {
// StorageDead(_1);
Expand Down
12 changes: 6 additions & 6 deletions src/test/mir-opt/end_region_5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// _4 = &'14s _1;
// _3 = [closure@NodeId(18)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// EndRegion('14s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> bb4;
// }
// bb2: {
// resume;
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('14s);
// drop(_1) -> bb2;
// drop(_1) -> bb1;
// }
// bb4: {
// StorageDead(_1);
Expand Down
12 changes: 6 additions & 6 deletions src/test/mir-opt/end_region_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// _4 = &'19s _1;
// _3 = [closure@NodeId(22)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb1, unwind: bb3];
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// EndRegion('19s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> bb4;
// }
// bb2: {
// resume;
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('19s);
// drop(_1) -> bb2;
// drop(_1) -> bb1;
// }
// bb4: {
// StorageDead(_1);
Expand Down
Loading

0 comments on commit 9dc3967

Please sign in to comment.