Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
464c02e
integrate scopes into MIR
nikomatsakis Mar 9, 2016
323d7f4
record a scope for each `VarDecl`
nikomatsakis Mar 9, 2016
e752d4c
track the innermost scope for every stmt
nikomatsakis Mar 9, 2016
3a16f57
extend Terminator into a struct so it can have additional fields
nikomatsakis Mar 10, 2016
9d00dee
add span/scope-id to terminator
nikomatsakis Mar 18, 2016
caac0b9
reformat mir text pretty printer
nikomatsakis Mar 19, 2016
d32bde3
augment MIR pretty printer to print scopes
nikomatsakis Mar 22, 2016
0d93989
adjust pretty printer to print scopes / auxiliary
nikomatsakis Mar 22, 2016
a61c175
allow dumping intermediate IR with -Z dump-mir
nikomatsakis Mar 22, 2016
f976e22
fix bug in `simplify_cfg` with inf. loops
nikomatsakis Mar 22, 2016
cb04e49
rewrite drop code
nikomatsakis Mar 23, 2016
f66fd89
replace DUMMY_SP on resume with span from fn
nikomatsakis Mar 23, 2016
14a5657
Rename `MirPlusPlus` to `MirAndScopeAuxiliary`
nikomatsakis Mar 23, 2016
a2bab6f
Address nit: use doc-comments for fields of VarDecl
nikomatsakis Mar 23, 2016
c1a53a6
Address nit: doc-comments on fields
nikomatsakis Mar 23, 2016
b3d2059
Address nit: block.unit()
nikomatsakis Mar 23, 2016
70d0123
Address nit: Remove `ScopedDataVec` newtype
nikomatsakis Mar 23, 2016
c36707a
Add `ScopeAuxiliaryVec`, return MIR+aux via tuple
nikomatsakis Mar 23, 2016
2b96cfb
add comments on remaining fields
nikomatsakis Mar 23, 2016
1c0fa34
Update borrowck to use `repr::*` instead of a mix
nikomatsakis Mar 23, 2016
a276e75
introduce "call-site-scope" as the outermost scope
nikomatsakis Mar 23, 2016
0769865
rewrite scope drop to be iterative
nikomatsakis Mar 24, 2016
ed7c30b
rework MIR visitor
nikomatsakis Mar 24, 2016
091a007
pacify the merciless tidy
nikomatsakis Mar 24, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ pub struct Builder<'a, 'tcx: 'a> {
var_indices: FnvHashMap<ast::NodeId, u32>,
temp_decls: Vec<TempDecl<'tcx>>,
unit_temp: Option<Lvalue<'tcx>>,

// cached block with a RESUME terminator; we create this at the
// first panic
cached_resume_block: Option<BasicBlock>,
}

struct CFG<'tcx> {
Expand Down Expand Up @@ -175,6 +179,7 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
var_decls: vec![],
var_indices: FnvHashMap(),
unit_temp: None,
cached_resume_block: None,
};

assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
Expand Down
66 changes: 34 additions & 32 deletions src/librustc_mir/build/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,21 +456,41 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// 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> {
if self.scopes.is_empty() {
if self.scopes.iter().all(|scope| scope.drops.is_empty() && scope.free.is_none()) {
return None;
}
assert!(!self.scopes.is_empty()); // or `all` above would be true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this assertion really necessary or, perhaps, it is misplaced and should go above the if?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nagisa it's more a comment than an assertion, I guess. Although I think that, in practice, the list of scopes cannot be empty here, so it could in principle go above the if


let unit_temp = self.get_unit_temp();
let Builder { ref mut hir, ref mut cfg, ref mut scopes, .. } = *self;

// Given an array of scopes, we generate these from the outermost scope to the innermost
// one. Thus for array [S0, S1, S2] with corresponding cleanup blocks [B0, B1, B2], we will
// generate B0 <- B1 <- B2 in left-to-right order. Control flow of the generated blocks
// always ends up at a block with the Resume terminator.
if scopes.iter().any(|scope| !scope.drops.is_empty() || scope.free.is_some()) {
Some(build_diverge_scope(hir.tcx(), self.fn_span, cfg, &unit_temp, scopes))
let Builder { ref mut hir, ref mut cfg, ref mut scopes,
ref mut cached_resume_block, .. } = *self;

// Build up the drops in **reverse** order. The end result will
// look like:
//
// scopes[n] -> scopes[n-1] -> ... -> scopes[0]
//
// However, we build this in **reverse order**. That is, we
// process scopes[0], then scopes[1], etc, pointing each one at
// the result generates from the one before. Along the way, we
// 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 {
None
let resumeblk = cfg.start_new_cleanup_block();
cfg.terminate(resumeblk, scopes[0].id, self.fn_span, TerminatorKind::Resume);
*cached_resume_block = Some(resumeblk);
resumeblk
};

for scope in scopes {
target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, scope, target);
}

Some(target)
}

/// Utility function for *non*-scope code to build their own drops
Expand Down Expand Up @@ -640,43 +660,25 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
}

fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
fn_span: Span,
cfg: &mut CFG<'tcx>,
unit_temp: &Lvalue<'tcx>,
scopes: &mut [Scope<'tcx>])
scope: &mut Scope<'tcx>,
mut target: BasicBlock)
-> BasicBlock
{
assert!(scopes.len() >= 1);

// Build up the drops in **reverse** order. The end result will
// look like:
//
// [drops[n]] -...-> [drops[0]] -> [Free] -> [scopes[..n-1]]
// [drops[n]] -...-> [drops[0]] -> [Free] -> [target]
// | |
// +------------------------------------+
// code for scopes[n]
// code for scope
//
// The code in this function reads from right to left. At each
// point, we check for cached blocks representing the
// remainder. If everything is cached, we'll just walk right to
// left reading the cached results but never created anything.

// To start, translate scopes[1..].
let (scope, earlier_scopes) = scopes.split_last_mut().unwrap();
let mut target = if let Some(cached_block) = scope.cached_block {
cached_block
} else if earlier_scopes.is_empty() {
// Diverging from the root scope creates a RESUME terminator.
// FIXME what span to use here?
let resumeblk = cfg.start_new_cleanup_block();
cfg.terminate(resumeblk, scope.id, fn_span, TerminatorKind::Resume);
resumeblk
} else {
// Diverging from any other scope chains up to the previous scope.
build_diverge_scope(tcx, fn_span, cfg, unit_temp, earlier_scopes)
};
scope.cached_block = Some(target);

// Next, build up any free.
if let Some(ref mut free_data) = scope.free {
target = if let Some(cached_block) = free_data.cached_block {
Expand Down