Skip to content

Commit fbdff56

Browse files
committed
Use DataflowResultsConsumer and remove dataflow::for_each_location
1 parent 6680d03 commit fbdff56

File tree

3 files changed

+94
-93
lines changed

3 files changed

+94
-93
lines changed

Diff for: src/librustc_mir/dataflow/at_location.rs

+5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ where
131131
curr_state.subtract(&self.stmt_kill);
132132
f(curr_state.iter());
133133
}
134+
135+
/// Returns a bitset of the elements present in the current state.
136+
pub fn as_dense(&self) -> &BitSet<BD::Idx> {
137+
&self.curr_state
138+
}
134139
}
135140

136141
impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>

Diff for: src/librustc_mir/dataflow/mod.rs

-56
Original file line numberDiff line numberDiff line change
@@ -380,62 +380,6 @@ pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location,
380380
gen_set.to_dense()
381381
}
382382

383-
/// Calls `f` with the dataflow state at every location in `mir`.
384-
/// Ignores blocks that terminate in `unreachable`.
385-
pub fn for_each_location<'tcx, T: BitDenotation<'tcx>>(
386-
mir: &Body<'tcx>,
387-
analysis: &T,
388-
result: &DataflowResults<'tcx, T>,
389-
mut f: impl FnMut(&HybridBitSet<T::Idx>, Location)
390-
) {
391-
for (block, bb_data) in mir.basic_blocks().iter_enumerated() {
392-
if bb_data.is_unreachable() {
393-
continue;
394-
}
395-
for_each_block_location(mir, block, bb_data, analysis, result, &mut f);
396-
}
397-
}
398-
399-
fn for_each_block_location<'tcx, T: BitDenotation<'tcx>>(
400-
mir: &Body<'tcx>,
401-
block: BasicBlock,
402-
bb_data: &BasicBlockData<'tcx>,
403-
analysis: &T,
404-
result: &DataflowResults<'tcx, T>,
405-
f: &mut impl FnMut(&HybridBitSet<T::Idx>, Location)
406-
) {
407-
let statements = &bb_data.statements;
408-
409-
let mut on_entry = result.sets().on_entry_set_for(block.index()).to_owned();
410-
let mut kill_set = on_entry.to_hybrid();
411-
let mut gen_set = kill_set.clone();
412-
413-
{
414-
let mut sets = BlockSets {
415-
on_entry: &mut on_entry,
416-
kill_set: &mut kill_set,
417-
gen_set: &mut gen_set,
418-
};
419-
// FIXME: This location is technically wrong, but there isn't a way to
420-
// denote the start of a block.
421-
f(sets.gen_set, Location { block, statement_index: 0 });
422-
423-
for statement_index in 0..statements.len() {
424-
let loc = Location { block, statement_index };
425-
analysis.before_statement_effect(&mut sets, loc);
426-
f(sets.gen_set, loc);
427-
analysis.statement_effect(&mut sets, loc);
428-
f(sets.gen_set, loc);
429-
}
430-
431-
let term_loc = Location { block, statement_index: mir[block].statements.len() };
432-
analysis.before_terminator_effect(&mut sets, term_loc);
433-
f(sets.gen_set, term_loc);
434-
analysis.terminator_effect(&mut sets, term_loc);
435-
f(sets.gen_set, term_loc);
436-
}
437-
}
438-
439383
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation<'tcx>
440384
{
441385
flow_state: DataflowState<'tcx, O>,

Diff for: src/librustc_mir/transform/generator.rs

+89-37
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ use std::mem;
6666
use crate::transform::{MirPass, MirSource};
6767
use crate::transform::simplify;
6868
use crate::transform::no_landing_pads::no_landing_pads;
69-
use crate::dataflow::{DataflowResults};
70-
use crate::dataflow::{do_dataflow, DebugFormatted, state_for_location, for_each_location};
69+
use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation};
70+
use crate::dataflow::{do_dataflow, DebugFormatted, state_for_location};
7171
use crate::dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
7272
use crate::util::dump_mir;
7373
use crate::util::liveness;
@@ -541,6 +541,25 @@ fn locals_live_across_suspend_points(
541541
}
542542
}
543543

544+
/// Renumbers the items present in `stored_locals` and applies the renumbering
545+
/// to 'input`.
546+
///
547+
/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
548+
/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
549+
fn renumber_bitset(input: &BitSet<Local>, stored_locals: &liveness::LiveVarSet)
550+
-> BitSet<GeneratorSavedLocal> {
551+
assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
552+
let mut out = BitSet::new_empty(stored_locals.count());
553+
for (idx, local) in stored_locals.iter().enumerate() {
554+
let saved_local = GeneratorSavedLocal::from(idx);
555+
if input.contains(local) {
556+
out.insert(saved_local);
557+
}
558+
}
559+
debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out);
560+
out
561+
}
562+
544563
/// For every saved local, looks for which locals are StorageLive at the same
545564
/// time. Generates a bitset for every local of all the other locals that may be
546565
/// StorageLive simultaneously with that local. This is used in the layout
@@ -550,7 +569,7 @@ fn compute_storage_conflicts(
550569
stored_locals: &liveness::LiveVarSet,
551570
ignored: &StorageIgnored,
552571
storage_live: DataflowResults<'tcx, MaybeStorageLive<'mir, 'tcx>>,
553-
storage_live_analysis: MaybeStorageLive<'mir, 'tcx>,
572+
_storage_live_analysis: MaybeStorageLive<'mir, 'tcx>,
554573
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
555574
assert_eq!(body.local_decls.len(), ignored.0.domain_size());
556575
assert_eq!(body.local_decls.len(), stored_locals.domain_size());
@@ -562,26 +581,18 @@ fn compute_storage_conflicts(
562581
let mut ineligible_locals = ignored.0.clone();
563582
ineligible_locals.intersect(&stored_locals);
564583

565-
// Of our remaining candidates, find out if any have overlapping storage
566-
// liveness. Those that do must be in the same variant to remain candidates.
567-
// FIXME(tmandry): Consider using sparse bitsets here once we have good
568-
// benchmarks for generators.
569-
let mut local_conflicts: BitMatrix<Local, Local> =
570-
BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len());
571-
572-
for_each_location(body, &storage_live_analysis, &storage_live, |state, loc| {
573-
let mut eligible_storage_live = state.clone().to_dense();
574-
eligible_storage_live.intersect(&stored_locals);
575-
576-
for local in eligible_storage_live.iter() {
577-
local_conflicts.union_row_with(&eligible_storage_live, local);
578-
}
579-
580-
if eligible_storage_live.count() > 1 {
581-
trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
582-
}
583-
});
584+
// Compute the storage conflicts for all eligible locals.
585+
let mut visitor = StorageConflictVisitor {
586+
body,
587+
stored_locals: &stored_locals,
588+
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len())
589+
};
590+
let mut state = FlowAtLocation::new(storage_live);
591+
visitor.analyze_results(&mut state);
592+
let local_conflicts = visitor.local_conflicts;
584593

594+
// Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
595+
//
585596
// NOTE: Today we store a full conflict bitset for every local. Technically
586597
// this is twice as many bits as we need, since the relation is symmetric.
587598
// However, in practice these bitsets are not usually large. The layout code
@@ -606,23 +617,64 @@ fn compute_storage_conflicts(
606617
storage_conflicts
607618
}
608619

609-
/// Renumbers the items present in `stored_locals` and applies the renumbering
610-
/// to 'input`.
611-
///
612-
/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
613-
/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
614-
fn renumber_bitset(input: &BitSet<Local>, stored_locals: &liveness::LiveVarSet)
615-
-> BitSet<GeneratorSavedLocal> {
616-
assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
617-
let mut out = BitSet::new_empty(stored_locals.count());
618-
for (idx, local) in stored_locals.iter().enumerate() {
619-
let saved_local = GeneratorSavedLocal::from(idx);
620-
if input.contains(local) {
621-
out.insert(saved_local);
620+
struct StorageConflictVisitor<'body, 'tcx: 'body, 's> {
621+
body: &'body Body<'tcx>,
622+
stored_locals: &'s liveness::LiveVarSet,
623+
// FIXME(tmandry): Consider using sparse bitsets here once we have good
624+
// benchmarks for generators.
625+
local_conflicts: BitMatrix<Local, Local>,
626+
}
627+
628+
impl<'body, 'tcx: 'body, 's> DataflowResultsConsumer<'body, 'tcx>
629+
for StorageConflictVisitor<'body, 'tcx, 's> {
630+
type FlowState = FlowAtLocation<'tcx, MaybeStorageLive<'body, 'tcx>>;
631+
632+
fn body(&self) -> &'body Body<'tcx> {
633+
self.body
634+
}
635+
636+
fn visit_block_entry(&mut self,
637+
block: BasicBlock,
638+
flow_state: &Self::FlowState) {
639+
// statement_index is only used for logging, so this is fine.
640+
self.apply_state(flow_state, Location { block, statement_index: 0 });
641+
}
642+
643+
fn visit_statement_entry(&mut self,
644+
loc: Location,
645+
_stmt: &Statement<'tcx>,
646+
flow_state: &Self::FlowState) {
647+
self.apply_state(flow_state, loc);
648+
}
649+
650+
fn visit_terminator_entry(&mut self,
651+
loc: Location,
652+
_term: &Terminator<'tcx>,
653+
flow_state: &Self::FlowState) {
654+
self.apply_state(flow_state, loc);
655+
}
656+
}
657+
658+
impl<'body, 'tcx: 'body, 's> StorageConflictVisitor<'body, 'tcx, 's> {
659+
fn apply_state(&mut self,
660+
flow_state: &FlowAtLocation<'tcx, MaybeStorageLive<'body, 'tcx>>,
661+
loc: Location) {
662+
// Ignore unreachable blocks.
663+
if self.body.basic_blocks()[loc.block].is_unreachable() {
664+
return;
665+
}
666+
667+
let mut eligible_storage_live = flow_state.as_dense().clone();
668+
eligible_storage_live.intersect(&self.stored_locals);
669+
670+
for local in eligible_storage_live.iter() {
671+
self.local_conflicts.union_row_with(&eligible_storage_live, local);
672+
}
673+
674+
if eligible_storage_live.count() > 1 {
675+
trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
622676
}
623677
}
624-
debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out);
625-
out
626678
}
627679

628680
fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

0 commit comments

Comments
 (0)