mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Use new liveness analysis during generator transform
This commit is contained in:
parent
4c34ec6848
commit
91003401c8
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user