Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 18 additions & 35 deletions compiler/rustc_mir_dataflow/src/impls/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ use crate::{Analysis, Backward, GenKill};
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
pub struct MaybeLiveLocals;

impl MaybeLiveLocals {
pub fn transfer_function<I>(state: &mut I) -> TransferFunction<'_, I> {
TransferFunction(state)
}
}

impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
type Domain = DenseBitSet<Local>;
type Direction = Backward;
Expand All @@ -50,7 +44,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
statement: &mir::Statement<'tcx>,
location: Location,
) {
TransferFunction(state).visit_statement(statement, location);
LivenessTransferFunction(state).visit_statement(statement, location);
}

fn apply_primary_terminator_effect(
Expand All @@ -59,7 +53,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
terminator: &mir::Terminator<'tcx>,
location: Location,
) {
TransferFunction(state).visit_terminator(terminator, location);
LivenessTransferFunction(state).visit_terminator(terminator, location);
}

fn apply_call_return_effect(
Expand All @@ -84,9 +78,9 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
}
}

pub struct TransferFunction<'a, I>(pub &'a mut I);
pub struct LivenessTransferFunction<'a, I>(pub &'a mut I);

impl<'tcx, I> Visitor<'tcx> for TransferFunction<'_, I>
impl<'tcx, I> Visitor<'tcx> for LivenessTransferFunction<'_, I>
where
I: GenKill<Local>,
{
Expand Down Expand Up @@ -136,7 +130,6 @@ impl<'tcx> Visitor<'tcx> for YieldResumeEffect<'_> {
}
}

#[derive(Eq, PartialEq, Clone)]
pub enum DefUse {
/// Full write to the local.
Def,
Expand Down Expand Up @@ -208,7 +201,8 @@ impl DefUse {
}
}

/// Like `MaybeLiveLocals`, but does not mark locals as live if they are used in a dead assignment.
/// Like `MaybeLiveLocals` (and layered on top of `MaybeLiveLocals`), but does not mark locals as
/// live if they are used in a dead assignment.
///
/// This is basically written for dead store elimination and nothing else.
///
Expand All @@ -219,7 +213,7 @@ pub struct MaybeTransitiveLiveLocals<'a> {
}

impl<'a> MaybeTransitiveLiveLocals<'a> {
/// The `always_alive` set is the set of locals to which all stores should unconditionally be
/// The `always_live` set is the set of locals to which all stores should unconditionally be
/// considered live.
///
/// This should include at least all locals that are ever borrowed.
Expand All @@ -233,7 +227,7 @@ impl<'a> MaybeTransitiveLiveLocals<'a> {
pub fn can_be_removed_if_dead<'tcx>(
stmt_kind: &StatementKind<'tcx>,
always_live: &DenseBitSet<Local>,
debuginfo_locals: &'a DenseBitSet<Local>,
debuginfo_locals: &DenseBitSet<Local>,
) -> Option<Place<'tcx>> {
// Compute the place that we are storing to, if any
let destination = match stmt_kind {
Expand Down Expand Up @@ -274,12 +268,11 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
const NAME: &'static str = "transitive liveness";

fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = not live
DenseBitSet::new_empty(body.local_decls.len())
MaybeLiveLocals.bottom_value(body)
}

fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// No variables are live until we observe a use
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
MaybeLiveLocals.initialize_start_block(body, state)
}

fn apply_primary_statement_effect(
Expand All @@ -288,14 +281,16 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
statement: &mir::Statement<'tcx>,
location: Location,
) {
// This is the one part of `MaybeTransitiveLiveLocals` that differs from `MaybeLiveLocals`.
if let Some(destination) =
Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals)
Self::can_be_removed_if_dead(&statement.kind, self.always_live, self.debuginfo_locals)
&& !state.contains(destination.local)
{
// This store is dead
return;
}
TransferFunction(state).visit_statement(statement, location);

MaybeLiveLocals.apply_primary_statement_effect(state, statement, location);
}

fn apply_primary_terminator_effect(
Expand All @@ -304,27 +299,15 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
terminator: &mir::Terminator<'tcx>,
location: Location,
) {
TransferFunction(state).visit_terminator(terminator, location);
MaybeLiveLocals.apply_primary_terminator_effect(state, terminator, location)
}

fn apply_call_return_effect(
&self,
state: &mut Self::Domain,
_block: mir::BasicBlock,
block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(state).visit_place(
&resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START,
)
} else {
return_places.for_each(|place| {
if let Some(local) = place.as_local() {
state.remove(local);
}
});
}
MaybeLiveLocals.apply_call_return_effect(state, block, return_places);
}
}
3 changes: 1 addition & 2 deletions compiler/rustc_mir_dataflow/src/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ pub use self::initialized::{
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
};
pub use self::liveness::{
DefUse, MaybeLiveLocals, MaybeTransitiveLiveLocals,
TransferFunction as LivenessTransferFunction,
DefUse, LivenessTransferFunction, MaybeLiveLocals, MaybeTransitiveLiveLocals,
};
pub use self::storage_liveness::{
MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive, always_storage_live_locals,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_transform/src/dest_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ use rustc_index::{IndexVec, newtype_index};
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, VisitPlacesWith, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
use rustc_mir_dataflow::impls::{DefUse, LivenessTransferFunction, MaybeLiveLocals};
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_mir_dataflow::{Analysis, EntryStates, GenKill};
use tracing::{debug, trace};
Expand Down Expand Up @@ -619,7 +619,7 @@ fn save_as_intervals<'tcx>(

state.current = state.current + 1;
debug_assert_eq!(state.current, two_step_loc(loc, Effect::Before));
MaybeLiveLocals::transfer_function(&mut state).visit_terminator(term, loc);
LivenessTransferFunction(&mut state).visit_terminator(term, loc);

for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index };
Expand Down Expand Up @@ -659,7 +659,7 @@ fn save_as_intervals<'tcx>(
// the all the writes we manually marked as live in the second half of the statement.
state.current = TwoStepIndex::from_u32(state.current.as_u32() + 1);
debug_assert_eq!(state.current, two_step_loc(loc, Effect::Before));
MaybeLiveLocals::transfer_function(&mut state).visit_statement(stmt, loc);
LivenessTransferFunction(&mut state).visit_statement(stmt, loc);
}

// Cleanup the current block for the next one.
Expand Down
Loading