Skip to content

Commit 4f0b256

Browse files
committed
Use caches for scope exits more aggressively
1 parent 05420b5 commit 4f0b256

File tree

1 file changed

+113
-82
lines changed

1 file changed

+113
-82
lines changed

src/librustc_mir/build/scope.rs

+113-82
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
323323
let parent_hir_id =
324324
tcx.hir.definitions().node_to_hir_id(
325325
self.source_scope_local_data[source_scope].lint_root
326-
);
326+
);
327327
let current_hir_id =
328328
tcx.hir.definitions().node_to_hir_id(node_id);
329329
sets.lint_level_set(parent_hir_id) ==
@@ -333,7 +333,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
333333
if !same_lint_scopes {
334334
self.source_scope =
335335
self.new_source_scope(region_scope.1.span, lint_level,
336-
None);
336+
None);
337337
}
338338
}
339339
self.push_scope(region_scope);
@@ -455,35 +455,58 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
455455
if may_panic {
456456
self.diverge_cleanup();
457457
}
458-
let mut target_blocks = (target, self.resume_block());
459458

460-
for scope in &mut self.scopes[(len - scope_count)..] {
459+
let resume_block = self.resume_block();
460+
461+
// Start from the last cached block
462+
let (mut target_blocks, first_uncached) = self.scopes[(len - scope_count)..].iter()
463+
.enumerate()
464+
.rev()
465+
.find_map(|(idx, scope)| {
466+
scope.cached_exits.get(&(target, region_scope.0)).map(|cached_target| {
467+
(
468+
(
469+
*cached_target,
470+
scope.cached_unwind.get(true).unwrap_or_else(|| {
471+
debug_assert!(!may_panic, "cached block not present?");
472+
resume_block
473+
}),
474+
),
475+
idx + 1,
476+
)
477+
})
478+
})
479+
.unwrap_or_else(|| {
480+
let unwind_block = self.scopes[len - scope_count - 1].cached_unwind
481+
.get(true)
482+
.unwrap_or_else(|| {
483+
debug_assert!(!may_panic, "cached block not present?");
484+
resume_block
485+
});
486+
((target, unwind_block), 0)
487+
});
488+
489+
for scope in &mut self.scopes[(len - scope_count + first_uncached)..] {
461490
if scope.drops.is_empty() {
462491
continue;
463492
}
464-
if let Some(&cached) = scope.cached_exits.get(&(target, region_scope.0)) {
465-
target_blocks = (cached, scope.cached_unwind.get(false).unwrap_or_else(|| {
466-
debug_assert!(!may_panic, "cached block not present?");
467-
target_blocks.1
468-
}));
469-
} else {
470-
let current_target = self.cfg.start_new_block();
471-
self.cfg.terminate(
472-
current_target,
473-
scope.source_info(span),
474-
TerminatorKind::Goto { target: target_blocks.0 },
475-
);
476-
target_blocks = build_scope_drops(
477-
&mut self.cfg,
478-
current_target,
479-
target_blocks.1,
480-
&scope.drops,
481-
scope,
482-
self.arg_count,
483-
false,
484-
);
485-
scope.cached_exits.insert((target, region_scope.0), target_blocks.0);
486-
};
493+
494+
let current_target = self.cfg.start_new_block();
495+
self.cfg.terminate(
496+
current_target,
497+
scope.source_info(span),
498+
TerminatorKind::Goto { target: target_blocks.0 },
499+
);
500+
target_blocks = build_scope_drops(
501+
&mut self.cfg,
502+
current_target,
503+
target_blocks.1,
504+
&scope.drops,
505+
scope,
506+
self.arg_count,
507+
false,
508+
);
509+
scope.cached_exits.insert((target, region_scope.0), target_blocks.0);
487510
}
488511
self.cfg.terminate(
489512
block,
@@ -497,56 +520,66 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
497520
/// This path terminates in GeneratorDrop. Returns the start of the path.
498521
/// None indicates there’s no cleanup to do at this point.
499522
pub fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
500-
// Fill in the cache
523+
// Fill in the cache for unwinds
501524
self.diverge_cleanup_gen(true);
502525

503526
let src_info = self.scopes[0].source_info(self.fn_span);
504-
let mut target_blocks = None;
505-
let resume_block = self.resume_block();
506527

507-
for scope in &mut self.scopes {
528+
// Start from the last cached block
529+
let (mut target_blocks, first_uncached) = self.scopes.iter()
530+
.enumerate()
531+
.rev()
532+
.find_map(|(idx, scope)| {
533+
scope.cached_generator_drop.map(|cached_target| {
534+
(
535+
(
536+
cached_target,
537+
scope.cached_unwind.get(true).unwrap_or_else(|| {
538+
span_bug!(src_info.span, "cached block not present?")
539+
}),
540+
),
541+
idx + 1,
542+
)
543+
})
544+
})
545+
.unwrap_or_else(|| {
546+
let generator_drop_block = self.cfg.start_new_block();
547+
self.cfg.terminate(generator_drop_block, src_info, TerminatorKind::GeneratorDrop);
548+
((generator_drop_block, self.resume_block()), 0)
549+
});
550+
551+
for scope in &mut self.scopes[first_uncached..] {
508552
if !scope.needs_cleanup {
509553
continue;
510554
}
511-
if let Some(cached) = scope.cached_generator_drop {
512-
target_blocks = Some((cached, scope.cached_unwind.get(true).unwrap_or_else(|| {
513-
span_bug!(src_info.span, "cached block not present?")
514-
})));
515-
} else {
516-
let current_target = self.cfg.start_new_block();
517-
let unwind_target = if let Some((target, unwind_target)) = target_blocks {
518-
self.cfg.terminate(
519-
current_target,
520-
src_info,
521-
TerminatorKind::Goto { target },
522-
);
523-
unwind_target
524-
} else {
525-
self.cfg.terminate(current_target, src_info, TerminatorKind::GeneratorDrop);
526-
resume_block
527-
};
528-
let next_target_blocks = build_scope_drops(
529-
&mut self.cfg,
530-
current_target,
531-
unwind_target,
532-
&scope.drops,
533-
scope,
534-
self.arg_count,
535-
true,
536-
);
537-
scope.cached_generator_drop = Some(next_target_blocks.0);
538-
target_blocks = Some(next_target_blocks);
539-
};
555+
556+
let current_target = self.cfg.start_new_block();
557+
self.cfg.terminate(
558+
current_target,
559+
src_info,
560+
TerminatorKind::Goto { target: target_blocks.0 },
561+
);
562+
563+
target_blocks = build_scope_drops(
564+
&mut self.cfg,
565+
current_target,
566+
target_blocks.1,
567+
&scope.drops,
568+
scope,
569+
self.arg_count,
570+
true,
571+
);
572+
scope.cached_generator_drop = Some(target_blocks.0);
540573
}
541574

542-
target_blocks.map(|(target, _)| target)
575+
Some(target_blocks.0)
543576
}
544577

545578
/// Creates a new source scope, nested in the current one.
546579
pub fn new_source_scope(&mut self,
547-
span: Span,
548-
lint_level: LintLevel,
549-
safety: Option<Safety>) -> SourceScope {
580+
span: Span,
581+
lint_level: LintLevel,
582+
safety: Option<Safety>) -> SourceScope {
550583
let parent = self.source_scope;
551584
debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
552585
span, lint_level, safety,
@@ -805,11 +838,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
805838
}
806839

807840
fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
808-
// To start, create the resume terminator.
809-
let mut target = self.resume_block();
810-
811-
let Builder { ref mut cfg, ref mut scopes, .. } = *self;
812-
813841
// Build up the drops in **reverse** order. The end result will
814842
// look like:
815843
//
@@ -821,8 +849,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
821849
// store caches. If everything is cached, we'll just walk right
822850
// to left reading the cached results but never created anything.
823851

824-
for scope in scopes.iter_mut() {
825-
target = build_diverge_scope(cfg, scope.region_scope_span,
852+
// Find the last cached block
853+
let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter()
854+
.rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) {
855+
(self.scopes[cached_index].cached_unwind.get(generator_drop).unwrap(), cached_index + 1)
856+
} else {
857+
(self.resume_block(), 0)
858+
};
859+
860+
for scope in self.scopes[first_uncached..].iter_mut() {
861+
target = build_diverge_scope(&mut self.cfg, scope.region_scope_span,
826862
scope, target, generator_drop);
827863
}
828864

@@ -999,11 +1035,11 @@ fn push_storage_deads<'tcx>(
9991035
}
10001036

10011037
fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
1002-
span: Span,
1003-
scope: &mut Scope<'tcx>,
1004-
mut target: BasicBlock,
1005-
generator_drop: bool)
1006-
-> BasicBlock
1038+
span: Span,
1039+
scope: &mut Scope<'tcx>,
1040+
mut target: BasicBlock,
1041+
generator_drop: bool)
1042+
-> BasicBlock
10071043
{
10081044
// Build up the drops in **reverse** order. The end result will
10091045
// look like:
@@ -1015,11 +1051,6 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
10151051
// remainder. If everything is cached, we'll just walk right to
10161052
// left reading the cached results but never create anything.
10171053

1018-
let scope_cached_block = scope.cached_unwind.ref_mut(generator_drop);
1019-
if let Some(scope_cached_block) = *scope_cached_block {
1020-
return scope_cached_block;
1021-
}
1022-
10231054
let source_scope = scope.source_scope;
10241055
let source_info = |span| SourceInfo {
10251056
span,
@@ -1058,7 +1089,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
10581089
};
10591090
}
10601091

1061-
*scope_cached_block = Some(target);
1092+
*scope.cached_unwind.ref_mut(generator_drop) = Some(target);
10621093

10631094
debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
10641095

0 commit comments

Comments
 (0)