Use new liveness analysis during generator transform

This commit is contained in:
Dylan MacKenzie 2020-04-10 11:13:31 -07:00
parent 4c34ec6848
commit 91003401c8

View File

@ -50,12 +50,13 @@
//! Otherwise it drops all the values in scope at the last suspension point.
use crate::dataflow::{self, Analysis};
use crate::dataflow::{MaybeBorrowedLocals, MaybeRequiresStorage, MaybeStorageLive};
use crate::dataflow::{
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
};
use crate::transform::no_landing_pads::no_landing_pads;
use crate::transform::simplify;
use crate::transform::{MirPass, MirSource};
use crate::util::dump_mir;
use crate::util::liveness;
use crate::util::storage;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
@ -195,7 +196,7 @@ struct SuspensionPoint<'tcx> {
/// Which block to jump to if the generator is dropped in this state.
drop: Option<BasicBlock>,
/// Set of locals that have live storage while at this suspension point.
storage_liveness: liveness::LiveVarSet,
storage_liveness: BitSet<Local>,
}
struct TransformVisitor<'tcx> {
@ -211,7 +212,7 @@ struct TransformVisitor<'tcx> {
remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
// A map from a suspension point in a block to the locals which have live storage at that point
storage_liveness: IndexVec<BasicBlock, Option<liveness::LiveVarSet>>,
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
// A list of suspension points, generated during the transform
suspension_points: Vec<SuspensionPoint<'tcx>>,
@ -418,7 +419,7 @@ struct LivenessInfo {
/// GeneratorSavedLocal is indexed in terms of the elements in this set;
/// i.e. GeneratorSavedLocal::new(1) corresponds to the second local
/// included in this set.
live_locals: liveness::LiveVarSet,
live_locals: BitSet<Local>,
/// The set of saved locals live at each suspension point.
live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
@ -430,7 +431,7 @@ struct LivenessInfo {
/// For every suspending block, the locals which are storage-live across
/// that suspension point.
storage_liveness: IndexVec<BasicBlock, Option<liveness::LiveVarSet>>,
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
}
fn locals_live_across_suspend_points(
@ -467,18 +468,22 @@ fn locals_live_across_suspend_points(
dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
// Calculate the liveness of MIR locals ignoring borrows.
let mut liveness = liveness::liveness_of_locals(body);
liveness::dump_mir(tcx, "generator_liveness", source, body_ref, &liveness);
let mut liveness = MaybeLiveLocals
.into_engine(tcx, body_ref, def_id)
.iterate_to_fixpoint()
.into_results_cursor(body_ref);
let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
let mut live_locals_at_suspension_points = Vec::new();
let mut live_locals_at_any_suspension_point =
liveness::LiveVarSet::new_empty(body.local_decls.len());
let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
for (block, data) in body.basic_blocks().iter_enumerated() {
if let TerminatorKind::Yield { .. } = data.terminator().kind {
let loc = Location { block, statement_index: data.statements.len() };
liveness.seek_to_block_end(block);
let mut live_locals = liveness.get().clone();
if !movable {
// The `liveness` variable contains the liveness of MIR locals ignoring borrows.
// This is correct for movable generators since borrows cannot live across
@ -491,7 +496,7 @@ fn locals_live_across_suspend_points(
// forever. Note that the final liveness is still bounded by the storage liveness
// of the local, which happens using the `intersect` operation below.
borrowed_locals_cursor.seek_before_primary_effect(loc);
liveness.outs[block].union(borrowed_locals_cursor.get());
live_locals.union(borrowed_locals_cursor.get());
}
// Store the storage liveness for later use so we can restore the state
@ -499,14 +504,11 @@ fn locals_live_across_suspend_points(
storage_live.seek_before_primary_effect(loc);
storage_liveness_map[block] = Some(storage_live.get().clone());
requires_storage_cursor.seek_before_primary_effect(loc);
let storage_required = requires_storage_cursor.get().clone();
// Locals live are live at this point only if they are used across
// suspension points (the `liveness` variable)
// and their storage is required (the `storage_required` variable)
let mut live_locals = storage_required;
live_locals.intersect(&liveness.outs[block]);
requires_storage_cursor.seek_before_primary_effect(loc);
live_locals.intersect(requires_storage_cursor.get());
// The generator argument is ignored.
live_locals.remove(SELF_ARG);
@ -551,7 +553,7 @@ fn locals_live_across_suspend_points(
/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
fn renumber_bitset(
input: &BitSet<Local>,
stored_locals: &liveness::LiveVarSet,
stored_locals: &BitSet<Local>,
) -> BitSet<GeneratorSavedLocal> {
assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
let mut out = BitSet::new_empty(stored_locals.count());
@ -571,7 +573,7 @@ fn renumber_bitset(
/// computation; see `GeneratorLayout` for more.
fn compute_storage_conflicts(
body: &'mir Body<'tcx>,
stored_locals: &liveness::LiveVarSet,
stored_locals: &BitSet<Local>,
always_live_locals: storage::AlwaysLiveLocals,
requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
@ -626,7 +628,7 @@ fn compute_storage_conflicts(
struct StorageConflictVisitor<'mir, 'tcx, 's> {
body: &'mir Body<'tcx>,
stored_locals: &'s liveness::LiveVarSet,
stored_locals: &'s BitSet<Local>,
// FIXME(tmandry): Consider using sparse bitsets here once we have good
// benchmarks for generators.
local_conflicts: BitMatrix<Local, Local>,
@ -635,7 +637,7 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
type FlowState = BitSet<Local>;
fn visit_statement(
fn visit_statement_before_primary_effect(
&mut self,
state: &Self::FlowState,
_statement: &'mir Statement<'tcx>,
@ -644,7 +646,7 @@ impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx,
self.apply_state(state, loc);
}
fn visit_terminator(
fn visit_terminator_before_primary_effect(
&mut self,
state: &Self::FlowState,
_terminator: &'mir Terminator<'tcx>,
@ -685,7 +687,7 @@ fn compute_layout<'tcx>(
) -> (
FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
GeneratorLayout<'tcx>,
IndexVec<BasicBlock, Option<liveness::LiveVarSet>>,
IndexVec<BasicBlock, Option<BitSet<Local>>>,
) {
// Use a liveness analysis to compute locals which are live across a suspension point
let LivenessInfo {