Skip to content

Commit d8ed2e7

Browse files
committed
Use RequiresStorage to determine which locals can overlap
1 parent aee1357 commit d8ed2e7

File tree

3 files changed

+33
-20
lines changed

3 files changed

+33
-20
lines changed

src/librustc_mir/dataflow/impls/storage_liveness.rs

-4
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
7272

7373
/// Dataflow analysis that determines whether each local requires storage at a
7474
/// given location; i.e. whether its storage can go away without being observed.
75-
///
76-
/// In the case of a movable generator, borrowed_locals can be `None` and we
77-
/// will not consider borrows in this pass. This relies on the fact that we only
78-
/// use this pass at yield points for these generators.
7975
pub struct RequiresStorage<'mir, 'tcx, 'b> {
8076
body: &'mir Body<'tcx>,
8177
borrowed_locals:

src/librustc_mir/transform/generator.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
6262
use rustc_data_structures::bit_set::{BitSet, BitMatrix};
6363
use std::borrow::Cow;
6464
use std::iter;
65+
use std::marker::PhantomData;
6566
use std::mem;
6667
use crate::transform::{MirPass, MirSource};
6768
use crate::transform::simplify;
@@ -539,8 +540,8 @@ fn locals_live_across_suspend_points(
539540
body,
540541
&live_locals,
541542
&ignored,
542-
storage_live,
543-
storage_live_analysis);
543+
requires_storage,
544+
requires_storage_analysis);
544545

545546
LivenessInfo {
546547
live_locals,
@@ -577,8 +578,8 @@ fn compute_storage_conflicts(
577578
body: &'mir Body<'tcx>,
578579
stored_locals: &liveness::LiveVarSet,
579580
ignored: &StorageIgnored,
580-
storage_live: DataflowResults<'tcx, MaybeStorageLive<'mir, 'tcx>>,
581-
_storage_live_analysis: MaybeStorageLive<'mir, 'tcx>,
581+
requires_storage: DataflowResults<'tcx, RequiresStorage<'mir, 'tcx, '_>>,
582+
_requires_storage_analysis: RequiresStorage<'mir, 'tcx, '_>,
582583
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
583584
assert_eq!(body.local_decls.len(), ignored.0.domain_size());
584585
assert_eq!(body.local_decls.len(), stored_locals.domain_size());
@@ -594,9 +595,10 @@ fn compute_storage_conflicts(
594595
let mut visitor = StorageConflictVisitor {
595596
body,
596597
stored_locals: &stored_locals,
597-
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len())
598+
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
599+
_phantom: PhantomData::default(),
598600
};
599-
let mut state = FlowAtLocation::new(storage_live);
601+
let mut state = FlowAtLocation::new(requires_storage);
600602
visitor.analyze_results(&mut state);
601603
let local_conflicts = visitor.local_conflicts;
602604

@@ -626,18 +628,19 @@ fn compute_storage_conflicts(
626628
storage_conflicts
627629
}
628630

629-
struct StorageConflictVisitor<'body, 'tcx, 's> {
631+
struct StorageConflictVisitor<'body: 'b, 'tcx, 's, 'b> {
630632
body: &'body Body<'tcx>,
631633
stored_locals: &'s liveness::LiveVarSet,
632634
// FIXME(tmandry): Consider using sparse bitsets here once we have good
633635
// benchmarks for generators.
634636
local_conflicts: BitMatrix<Local, Local>,
637+
_phantom: PhantomData<&'b ()>,
635638
}
636639

637-
impl<'body, 'tcx, 's> DataflowResultsConsumer<'body, 'tcx>
638-
for StorageConflictVisitor<'body, 'tcx, 's>
640+
impl<'body, 'tcx, 's, 'b> DataflowResultsConsumer<'body, 'tcx>
641+
for StorageConflictVisitor<'body, 'tcx, 's, 'b>
639642
{
640-
type FlowState = FlowAtLocation<'tcx, MaybeStorageLive<'body, 'tcx>>;
643+
type FlowState = FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx, 'b>>;
641644

642645
fn body(&self) -> &'body Body<'tcx> {
643646
self.body
@@ -665,9 +668,9 @@ impl<'body, 'tcx, 's> DataflowResultsConsumer<'body, 'tcx>
665668
}
666669
}
667670

668-
impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> {
671+
impl<'body, 'tcx, 's, 'b> StorageConflictVisitor<'body, 'tcx, 's, 'b> {
669672
fn apply_state(&mut self,
670-
flow_state: &FlowAtLocation<'tcx, MaybeStorageLive<'body, 'tcx>>,
673+
flow_state: &FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx, 'b>>,
671674
loc: Location) {
672675
// Ignore unreachable blocks.
673676
match self.body.basic_blocks()[loc.block].terminator().kind {

src/test/run-pass/generator/size-moved-locals.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl Drop for Foo {
2121
fn drop(&mut self) {}
2222
}
2323

24-
fn simple() -> impl Generator<Yield = (), Return = ()> {
24+
fn move_before_yield() -> impl Generator<Yield = (), Return = ()> {
2525
static || {
2626
let first = Foo([0; FOO_SIZE]);
2727
let _second = first;
@@ -32,7 +32,7 @@ fn simple() -> impl Generator<Yield = (), Return = ()> {
3232

3333
fn noop() {}
3434

35-
fn complex() -> impl Generator<Yield = (), Return = ()> {
35+
fn move_before_yield_with_noop() -> impl Generator<Yield = (), Return = ()> {
3636
static || {
3737
let first = Foo([0; FOO_SIZE]);
3838
noop();
@@ -42,7 +42,21 @@ fn complex() -> impl Generator<Yield = (), Return = ()> {
4242
}
4343
}
4444

45+
// Today we don't have NRVO (we allocate space for both `first` and `second`,)
46+
// but we can overlap `first` with `_third`.
47+
fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
48+
static || {
49+
let first = Foo([0; FOO_SIZE]);
50+
yield;
51+
let second = first;
52+
yield;
53+
let _third = second;
54+
yield;
55+
}
56+
}
57+
4558
fn main() {
46-
assert_eq!(1028, std::mem::size_of_val(&simple()));
47-
assert_eq!(1032, std::mem::size_of_val(&complex()));
59+
assert_eq!(1028, std::mem::size_of_val(&move_before_yield()));
60+
assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop()));
61+
assert_eq!(2056, std::mem::size_of_val(&overlap_move_points()));
4862
}

0 commit comments

Comments
 (0)