Take MIR dataflow analyses by mutable reference.
This commit is contained in:
parent
fdd030127c
commit
eaddc37075
19 changed files with 491 additions and 288 deletions
|
@ -59,7 +59,7 @@ macro_rules! impl_visitable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
fn reconstruct_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -69,7 +69,7 @@ macro_rules! impl_visitable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
fn reconstruct_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -79,7 +79,7 @@ macro_rules! impl_visitable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
fn reconstruct_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
term: &mir::Terminator<'tcx>,
|
term: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -89,7 +89,7 @@ macro_rules! impl_visitable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
fn reconstruct_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
term: &mir::Terminator<'tcx>,
|
term: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -341,7 +341,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
type Idx = BorrowIndex;
|
type Idx = BorrowIndex;
|
||||||
|
|
||||||
fn before_statement_effect(
|
fn before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -350,7 +350,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -398,7 +398,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_terminator_effect(
|
fn before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -407,7 +407,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -424,7 +424,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
|
|
@ -372,7 +372,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
// Compute and report region errors, if any.
|
// Compute and report region errors, if any.
|
||||||
mbcx.report_region_errors(nll_errors);
|
mbcx.report_region_errors(nll_errors);
|
||||||
|
|
||||||
let results = BorrowckResults {
|
let mut results = BorrowckResults {
|
||||||
ever_inits: flow_ever_inits,
|
ever_inits: flow_ever_inits,
|
||||||
uninits: flow_uninits,
|
uninits: flow_uninits,
|
||||||
borrows: flow_borrows,
|
borrows: flow_borrows,
|
||||||
|
@ -383,7 +383,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
rustc_mir_dataflow::visit_results(
|
rustc_mir_dataflow::visit_results(
|
||||||
body,
|
body,
|
||||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||||
&results,
|
&mut results,
|
||||||
&mut mbcx,
|
&mut mbcx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -618,11 +618,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
// 2. loans made in overlapping scopes do not conflict
|
// 2. loans made in overlapping scopes do not conflict
|
||||||
// 3. assignments do not affect things loaned out as immutable
|
// 3. assignments do not affect things loaned out as immutable
|
||||||
// 4. moves do not affect things loaned out in any way
|
// 4. moves do not affect things loaned out in any way
|
||||||
impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
|
impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
type FlowState = Flows<'cx, 'tcx>;
|
type FlowState = Flows<'cx, 'tcx>;
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
flow_state: &Flows<'cx, 'tcx>,
|
flow_state: &Flows<'cx, 'tcx>,
|
||||||
stmt: &'cx Statement<'tcx>,
|
stmt: &'cx Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -692,6 +693,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
flow_state: &Flows<'cx, 'tcx>,
|
flow_state: &Flows<'cx, 'tcx>,
|
||||||
term: &'cx Terminator<'tcx>,
|
term: &'cx Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -800,6 +802,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
|
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
flow_state: &Flows<'cx, 'tcx>,
|
flow_state: &Flows<'cx, 'tcx>,
|
||||||
term: &'cx Terminator<'tcx>,
|
term: &'cx Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
|
|
@ -337,7 +337,7 @@ where
|
||||||
Q: Qualif,
|
Q: Qualif,
|
||||||
{
|
{
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -346,7 +346,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -355,7 +355,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
|
|
@ -1,18 +1,60 @@
|
||||||
//! Random access inspection of the results of a dataflow analysis.
|
//! Random access inspection of the results of a dataflow analysis.
|
||||||
|
|
||||||
use crate::framework::BitSetExt;
|
use crate::{framework::BitSetExt, CloneAnalysis};
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
|
|
||||||
use super::{Analysis, Direction, Effect, EffectIndex, Results};
|
use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results, ResultsCloned};
|
||||||
|
|
||||||
|
// `AnalysisResults` is needed as an impl such as the following has an unconstrained type
|
||||||
|
// parameter:
|
||||||
|
// ```
|
||||||
|
// impl<'tcx, A, E, R> ResultsCursor<'_, 'tcx, A, R>
|
||||||
|
// where
|
||||||
|
// A: Analysis<'tcx>,
|
||||||
|
// E: Borrow<EntrySets<'tcx, A>>,
|
||||||
|
// R: Results<'tcx, A, E>,
|
||||||
|
// {}
|
||||||
|
// ```
|
||||||
|
|
||||||
|
/// A type representing the analysis results consumed by a `ResultsCursor`.
|
||||||
|
pub trait AnalysisResults<'tcx, A>: BorrowMut<Results<'tcx, A, Self::EntrySets>>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx>,
|
||||||
|
{
|
||||||
|
/// The type containing the entry sets for this `Results` type.
|
||||||
|
///
|
||||||
|
/// Should be either `EntrySets<'tcx, A>` or `&EntrySets<'tcx, A>`.
|
||||||
|
type EntrySets: Borrow<EntrySets<'tcx, A>>;
|
||||||
|
}
|
||||||
|
impl<'tcx, A, E> AnalysisResults<'tcx, A> for Results<'tcx, A, E>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx>,
|
||||||
|
E: Borrow<EntrySets<'tcx, A>>,
|
||||||
|
{
|
||||||
|
type EntrySets = E;
|
||||||
|
}
|
||||||
|
impl<'a, 'tcx, A, E> AnalysisResults<'tcx, A> for &'a mut Results<'tcx, A, E>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx>,
|
||||||
|
E: Borrow<EntrySets<'tcx, A>>,
|
||||||
|
{
|
||||||
|
type EntrySets = E;
|
||||||
|
}
|
||||||
|
|
||||||
/// A `ResultsCursor` that borrows the underlying `Results`.
|
/// A `ResultsCursor` that borrows the underlying `Results`.
|
||||||
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
|
pub type ResultsRefCursor<'res, 'mir, 'tcx, A> =
|
||||||
|
ResultsCursor<'mir, 'tcx, A, &'res mut Results<'tcx, A>>;
|
||||||
|
|
||||||
|
/// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This
|
||||||
|
/// allows multiple cursors over the same `Results`.
|
||||||
|
pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> =
|
||||||
|
ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>;
|
||||||
|
|
||||||
/// Allows random access inspection of the results of a dataflow analysis.
|
/// Allows random access inspection of the results of a dataflow analysis.
|
||||||
///
|
///
|
||||||
|
@ -45,7 +87,38 @@ where
|
||||||
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
|
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
R: Borrow<Results<'tcx, A>>,
|
{
|
||||||
|
/// Returns the dataflow state at the current location.
|
||||||
|
pub fn get(&self) -> &A::Domain {
|
||||||
|
&self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the body this analysis was run on.
|
||||||
|
pub fn body(&self) -> &'mir mir::Body<'tcx> {
|
||||||
|
self.body
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwraps this cursor, returning the underlying `Results`.
|
||||||
|
pub fn into_results(self) -> R {
|
||||||
|
self.results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'res, 'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx> + CloneAnalysis,
|
||||||
|
{
|
||||||
|
/// Creates a new cursor over the same `Results`. Note that the cursor's position is *not*
|
||||||
|
/// copied.
|
||||||
|
pub fn new_cursor(&self) -> Self {
|
||||||
|
Self::new(self.body, self.results.reclone_analysis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx>,
|
||||||
|
R: AnalysisResults<'tcx, A>,
|
||||||
{
|
{
|
||||||
/// Returns a new cursor that can inspect `results`.
|
/// Returns a new cursor that can inspect `results`.
|
||||||
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
|
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
|
||||||
|
@ -74,8 +147,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying `Results`.
|
/// Returns the underlying `Results`.
|
||||||
pub fn results(&self) -> &Results<'tcx, A> {
|
pub fn results(&mut self) -> &Results<'tcx, A, R::EntrySets> {
|
||||||
&self.results.borrow()
|
self.results.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the underlying `Results`.
|
||||||
|
pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> {
|
||||||
|
self.results.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `Analysis` used to generate the underlying `Results`.
|
/// Returns the `Analysis` used to generate the underlying `Results`.
|
||||||
|
@ -83,9 +161,14 @@ where
|
||||||
&self.results.borrow().analysis
|
&self.results.borrow().analysis
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the dataflow state at the current location.
|
/// Returns the `Analysis` used to generate the underlying `Results`.
|
||||||
pub fn get(&self) -> &A::Domain {
|
pub fn mut_analysis(&mut self) -> &mut A {
|
||||||
&self.state
|
&mut self.results.borrow_mut().analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns both the dataflow state at the current location and the `Analysis`.
|
||||||
|
pub fn get_with_analysis(&mut self) -> (&A::Domain, &mut A) {
|
||||||
|
(&self.state, &mut self.results.borrow_mut().analysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the cursor to hold the entry set for the given basic block.
|
/// Resets the cursor to hold the entry set for the given basic block.
|
||||||
|
@ -97,7 +180,7 @@ where
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert!(self.reachable_blocks.contains(block));
|
assert!(self.reachable_blocks.contains(block));
|
||||||
|
|
||||||
self.state.clone_from(&self.results.borrow().entry_set_for_block(block));
|
self.state.clone_from(self.results.borrow().entry_set_for_block(block));
|
||||||
self.pos = CursorPosition::block_entry(block);
|
self.pos = CursorPosition::block_entry(block);
|
||||||
self.state_needs_reset = false;
|
self.state_needs_reset = false;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +269,7 @@ where
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let analysis = &self.results.borrow().analysis;
|
let analysis = &mut self.results.borrow_mut().analysis;
|
||||||
let target_effect_index = effect.at_index(target.statement_index);
|
let target_effect_index = effect.at_index(target.statement_index);
|
||||||
|
|
||||||
A::Direction::apply_effects_in_range(
|
A::Direction::apply_effects_in_range(
|
||||||
|
@ -205,8 +288,8 @@ where
|
||||||
///
|
///
|
||||||
/// This can be used, e.g., to apply the call return effect directly to the cursor without
|
/// This can be used, e.g., to apply the call return effect directly to the cursor without
|
||||||
/// creating an extra copy of the dataflow state.
|
/// creating an extra copy of the dataflow state.
|
||||||
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) {
|
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
|
||||||
f(&self.results.borrow().analysis, &mut self.state);
|
f(&mut self.results.borrow_mut().analysis, &mut self.state);
|
||||||
self.state_needs_reset = true;
|
self.state_needs_reset = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +298,6 @@ impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
|
||||||
where
|
where
|
||||||
A: crate::GenKillAnalysis<'tcx>,
|
A: crate::GenKillAnalysis<'tcx>,
|
||||||
A::Domain: BitSetExt<A::Idx>,
|
A::Domain: BitSetExt<A::Idx>,
|
||||||
R: Borrow<Results<'tcx, A>>,
|
|
||||||
{
|
{
|
||||||
pub fn contains(&self, elem: A::Idx) -> bool {
|
pub fn contains(&self, elem: A::Idx) -> bool {
|
||||||
self.get().contains(elem)
|
self.get().contains(elem)
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub trait Direction {
|
||||||
///
|
///
|
||||||
/// `effects.start()` must precede or equal `effects.end()` in this direction.
|
/// `effects.start()` must precede or equal `effects.end()` in this direction.
|
||||||
fn apply_effects_in_range<'tcx, A>(
|
fn apply_effects_in_range<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -25,7 +25,7 @@ pub trait Direction {
|
||||||
A: Analysis<'tcx>;
|
A: Analysis<'tcx>;
|
||||||
|
|
||||||
fn apply_effects_in_block<'tcx, A>(
|
fn apply_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -33,7 +33,7 @@ pub trait Direction {
|
||||||
A: Analysis<'tcx>;
|
A: Analysis<'tcx>;
|
||||||
|
|
||||||
fn gen_kill_effects_in_block<'tcx, A>(
|
fn gen_kill_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
trans: &mut GenKillSet<A::Idx>,
|
trans: &mut GenKillSet<A::Idx>,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -44,13 +44,13 @@ pub trait Direction {
|
||||||
state: &mut F,
|
state: &mut F,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &R,
|
results: &mut R,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, FlowState = F>;
|
R: ResultsVisitable<'tcx, FlowState = F>;
|
||||||
|
|
||||||
fn join_state_into_successors_of<'tcx, A>(
|
fn join_state_into_successors_of<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &mir::Body<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
exit_state: &mut A::Domain,
|
exit_state: &mut A::Domain,
|
||||||
|
@ -67,7 +67,7 @@ impl Direction for Backward {
|
||||||
const IS_FORWARD: bool = false;
|
const IS_FORWARD: bool = false;
|
||||||
|
|
||||||
fn apply_effects_in_block<'tcx, A>(
|
fn apply_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -87,7 +87,7 @@ impl Direction for Backward {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_kill_effects_in_block<'tcx, A>(
|
fn gen_kill_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
trans: &mut GenKillSet<A::Idx>,
|
trans: &mut GenKillSet<A::Idx>,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -107,7 +107,7 @@ impl Direction for Backward {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_effects_in_range<'tcx, A>(
|
fn apply_effects_in_range<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -187,36 +187,36 @@ impl Direction for Backward {
|
||||||
state: &mut F,
|
state: &mut F,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &R,
|
results: &mut R,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, FlowState = F>,
|
R: ResultsVisitable<'tcx, FlowState = F>,
|
||||||
{
|
{
|
||||||
results.reset_to_block_entry(state, block);
|
results.reset_to_block_entry(state, block);
|
||||||
|
|
||||||
vis.visit_block_end(&state, block_data, block);
|
vis.visit_block_end(results, &state, block_data, block);
|
||||||
|
|
||||||
// Terminator
|
// Terminator
|
||||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||||
let term = block_data.terminator();
|
let term = block_data.terminator();
|
||||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
results.reconstruct_before_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_before_primary_effect(state, term, loc);
|
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||||
results.reconstruct_terminator_effect(state, term, loc);
|
results.reconstruct_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_after_primary_effect(state, term, loc);
|
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||||
|
|
||||||
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
||||||
let loc = Location { block, statement_index };
|
let loc = Location { block, statement_index };
|
||||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
results.reconstruct_before_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_before_primary_effect(state, stmt, loc);
|
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||||
results.reconstruct_statement_effect(state, stmt, loc);
|
results.reconstruct_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_after_primary_effect(state, stmt, loc);
|
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
vis.visit_block_start(state, block_data, block);
|
vis.visit_block_start(results, state, block_data, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_state_into_successors_of<'tcx, A>(
|
fn join_state_into_successors_of<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxt<'tcx>,
|
||||||
body: &mir::Body<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
exit_state: &mut A::Domain,
|
exit_state: &mut A::Domain,
|
||||||
|
@ -319,7 +319,7 @@ impl Direction for Forward {
|
||||||
const IS_FORWARD: bool = true;
|
const IS_FORWARD: bool = true;
|
||||||
|
|
||||||
fn apply_effects_in_block<'tcx, A>(
|
fn apply_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -339,7 +339,7 @@ impl Direction for Forward {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_kill_effects_in_block<'tcx, A>(
|
fn gen_kill_effects_in_block<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
trans: &mut GenKillSet<A::Idx>,
|
trans: &mut GenKillSet<A::Idx>,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -359,7 +359,7 @@ impl Direction for Forward {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_effects_in_range<'tcx, A>(
|
fn apply_effects_in_range<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &mir::BasicBlockData<'tcx>,
|
block_data: &mir::BasicBlockData<'tcx>,
|
||||||
|
@ -435,35 +435,35 @@ impl Direction for Forward {
|
||||||
state: &mut F,
|
state: &mut F,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &R,
|
results: &mut R,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, FlowState = F>,
|
R: ResultsVisitable<'tcx, FlowState = F>,
|
||||||
{
|
{
|
||||||
results.reset_to_block_entry(state, block);
|
results.reset_to_block_entry(state, block);
|
||||||
|
|
||||||
vis.visit_block_start(state, block_data, block);
|
vis.visit_block_start(results, state, block_data, block);
|
||||||
|
|
||||||
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
||||||
let loc = Location { block, statement_index };
|
let loc = Location { block, statement_index };
|
||||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
results.reconstruct_before_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_before_primary_effect(state, stmt, loc);
|
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||||
results.reconstruct_statement_effect(state, stmt, loc);
|
results.reconstruct_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_after_primary_effect(state, stmt, loc);
|
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||||
let term = block_data.terminator();
|
let term = block_data.terminator();
|
||||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
results.reconstruct_before_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_before_primary_effect(state, term, loc);
|
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||||
results.reconstruct_terminator_effect(state, term, loc);
|
results.reconstruct_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_after_primary_effect(state, term, loc);
|
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||||
|
|
||||||
vis.visit_block_end(state, block_data, block);
|
vis.visit_block_end(results, state, block_data, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_state_into_successors_of<'tcx, A>(
|
fn join_state_into_successors_of<'tcx, A>(
|
||||||
analysis: &A,
|
analysis: &mut A,
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxt<'tcx>,
|
||||||
_body: &mir::Body<'tcx>,
|
_body: &mir::Body<'tcx>,
|
||||||
exit_state: &mut A::Domain,
|
exit_state: &mut A::Domain,
|
||||||
|
|
|
@ -5,7 +5,9 @@ use crate::errors::{
|
||||||
};
|
};
|
||||||
use crate::framework::BitSetExt;
|
use crate::framework::BitSetExt;
|
||||||
|
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
@ -22,54 +24,108 @@ use rustc_span::symbol::{sym, Symbol};
|
||||||
use super::fmt::DebugWithContext;
|
use super::fmt::DebugWithContext;
|
||||||
use super::graphviz;
|
use super::graphviz;
|
||||||
use super::{
|
use super::{
|
||||||
visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
|
visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
|
||||||
ResultsCursor, ResultsVisitor,
|
GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
|
||||||
|
ResultsVisitor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
|
||||||
|
|
||||||
/// A dataflow analysis that has converged to fixpoint.
|
/// A dataflow analysis that has converged to fixpoint.
|
||||||
pub struct Results<'tcx, A>
|
pub struct Results<'tcx, A, E = EntrySets<'tcx, A>>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
pub analysis: A,
|
pub analysis: A,
|
||||||
pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
|
pub(super) entry_sets: E,
|
||||||
|
pub(super) _marker: PhantomData<&'tcx ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A> Results<'tcx, A>
|
/// `Results` type with a cloned `Analysis` and borrowed entry sets.
|
||||||
|
pub type ResultsCloned<'res, 'tcx, A> = Results<'tcx, A, &'res EntrySets<'tcx, A>>;
|
||||||
|
|
||||||
|
impl<'tcx, A, E> Results<'tcx, A, E>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
|
E: Borrow<EntrySets<'tcx, A>>,
|
||||||
{
|
{
|
||||||
/// Creates a `ResultsCursor` that can inspect these `Results`.
|
/// Creates a `ResultsCursor` that can inspect these `Results`.
|
||||||
pub fn into_results_cursor<'mir>(
|
pub fn into_results_cursor<'mir>(
|
||||||
self,
|
self,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
) -> ResultsCursor<'mir, 'tcx, A> {
|
) -> ResultsCursor<'mir, 'tcx, A, Self> {
|
||||||
ResultsCursor::new(body, self)
|
ResultsCursor::new(body, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the dataflow state for the given block.
|
/// Gets the dataflow state for the given block.
|
||||||
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
|
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
|
||||||
&self.entry_sets[block]
|
&self.entry_sets.borrow()[block]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visit_with<'mir>(
|
pub fn visit_with<'mir>(
|
||||||
&self,
|
&mut self,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
|
||||||
) {
|
) {
|
||||||
visit_results(body, blocks, self, vis)
|
visit_results(body, blocks, self, vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visit_reachable_with<'mir>(
|
pub fn visit_reachable_with<'mir>(
|
||||||
&self,
|
&mut self,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
|
||||||
) {
|
) {
|
||||||
let blocks = mir::traversal::reachable(body);
|
let blocks = mir::traversal::reachable(body);
|
||||||
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'tcx, A> Results<'tcx, A>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx>,
|
||||||
|
{
|
||||||
|
/// Creates a `ResultsCursor` that can inspect these `Results`.
|
||||||
|
pub fn as_results_cursor<'a, 'mir>(
|
||||||
|
&'a mut self,
|
||||||
|
body: &'mir mir::Body<'tcx>,
|
||||||
|
) -> ResultsRefCursor<'a, 'mir, 'tcx, A> {
|
||||||
|
ResultsCursor::new(body, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx, A> Results<'tcx, A>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx> + CloneAnalysis,
|
||||||
|
{
|
||||||
|
/// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
|
||||||
|
pub fn clone_analysis(&self) -> ResultsCloned<'_, 'tcx, A> {
|
||||||
|
Results {
|
||||||
|
analysis: self.analysis.clone_analysis(),
|
||||||
|
entry_sets: &self.entry_sets,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `ResultsCursor` that can inspect these `Results`.
|
||||||
|
pub fn cloned_results_cursor<'mir>(
|
||||||
|
&self,
|
||||||
|
body: &'mir mir::Body<'tcx>,
|
||||||
|
) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> {
|
||||||
|
self.clone_analysis().into_results_cursor(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'res, 'tcx, A> Results<'tcx, A, &'res EntrySets<'tcx, A>>
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx> + CloneAnalysis,
|
||||||
|
{
|
||||||
|
/// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
|
||||||
|
pub fn reclone_analysis(&self) -> Self {
|
||||||
|
Results {
|
||||||
|
analysis: self.analysis.clone_analysis(),
|
||||||
|
entry_sets: self.entry_sets,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A solver for dataflow problems.
|
/// A solver for dataflow problems.
|
||||||
pub struct Engine<'a, 'tcx, A>
|
pub struct Engine<'a, 'tcx, A>
|
||||||
|
@ -98,7 +154,7 @@ where
|
||||||
T: Idx,
|
T: Idx,
|
||||||
{
|
{
|
||||||
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
|
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
|
||||||
pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
|
pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, mut analysis: A) -> Self {
|
||||||
// If there are no back-edges in the control-flow graph, we only ever need to apply the
|
// If there are no back-edges in the control-flow graph, we only ever need to apply the
|
||||||
// transfer function for each block exactly once (assuming that we process blocks in RPO).
|
// transfer function for each block exactly once (assuming that we process blocks in RPO).
|
||||||
//
|
//
|
||||||
|
@ -114,7 +170,7 @@ where
|
||||||
|
|
||||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||||
let trans = &mut trans_for_block[block];
|
let trans = &mut trans_for_block[block];
|
||||||
A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
|
A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
|
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
|
||||||
|
@ -171,7 +227,13 @@ where
|
||||||
A::Domain: DebugWithContext<A>,
|
A::Domain: DebugWithContext<A>,
|
||||||
{
|
{
|
||||||
let Engine {
|
let Engine {
|
||||||
analysis, body, mut entry_sets, tcx, apply_trans_for_block, pass_name, ..
|
mut analysis,
|
||||||
|
body,
|
||||||
|
mut entry_sets,
|
||||||
|
tcx,
|
||||||
|
apply_trans_for_block,
|
||||||
|
pass_name,
|
||||||
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
|
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
|
||||||
|
@ -203,11 +265,13 @@ where
|
||||||
// Apply the block transfer function, using the cached one if it exists.
|
// Apply the block transfer function, using the cached one if it exists.
|
||||||
match &apply_trans_for_block {
|
match &apply_trans_for_block {
|
||||||
Some(apply) => apply(bb, &mut state),
|
Some(apply) => apply(bb, &mut state),
|
||||||
None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
|
None => {
|
||||||
|
A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
A::Direction::join_state_into_successors_of(
|
A::Direction::join_state_into_successors_of(
|
||||||
&analysis,
|
&mut analysis,
|
||||||
tcx,
|
tcx,
|
||||||
body,
|
body,
|
||||||
&mut state,
|
&mut state,
|
||||||
|
@ -221,9 +285,9 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = Results { analysis, entry_sets };
|
let mut results = Results { analysis, entry_sets, _marker: PhantomData };
|
||||||
|
|
||||||
let res = write_graphviz_results(tcx, &body, &results, pass_name);
|
let res = write_graphviz_results(tcx, body, &mut results, pass_name);
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
error!("Failed to write graphviz dataflow results: {}", e);
|
error!("Failed to write graphviz dataflow results: {}", e);
|
||||||
}
|
}
|
||||||
|
@ -239,7 +303,7 @@ where
|
||||||
fn write_graphviz_results<'tcx, A>(
|
fn write_graphviz_results<'tcx, A>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &mir::Body<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
results: &Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
pass_name: Option<&'static str>,
|
pass_name: Option<&'static str>,
|
||||||
) -> std::io::Result<()>
|
) -> std::io::Result<()>
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! A helpful diagram for debugging dataflow problems.
|
//! A helpful diagram for debugging dataflow problems.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use std::{io, ops, str};
|
use std::{io, ops, str};
|
||||||
|
|
||||||
|
@ -28,23 +29,27 @@ impl OutputStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Formatter<'a, 'tcx, A>
|
pub struct Formatter<'res, 'mir, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
body: &'a Body<'tcx>,
|
body: &'mir Body<'tcx>,
|
||||||
results: &'a Results<'tcx, A>,
|
results: RefCell<&'res mut Results<'tcx, A>>,
|
||||||
style: OutputStyle,
|
style: OutputStyle,
|
||||||
reachable: BitSet<BasicBlock>,
|
reachable: BitSet<BasicBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, A> Formatter<'a, 'tcx, A>
|
impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
|
pub fn new(
|
||||||
|
body: &'mir Body<'tcx>,
|
||||||
|
results: &'res mut Results<'tcx, A>,
|
||||||
|
style: OutputStyle,
|
||||||
|
) -> Self {
|
||||||
let reachable = mir::traversal::reachable_as_bitset(body);
|
let reachable = mir::traversal::reachable_as_bitset(body);
|
||||||
Formatter { body, results, style, reachable }
|
Formatter { body, results: results.into(), style, reachable }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +69,7 @@ fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
|
impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, '_, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
A::Domain: DebugWithContext<A>,
|
A::Domain: DebugWithContext<A>,
|
||||||
|
@ -83,13 +88,14 @@ where
|
||||||
|
|
||||||
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
|
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
|
||||||
let mut label = Vec::new();
|
let mut label = Vec::new();
|
||||||
|
let mut results = self.results.borrow_mut();
|
||||||
let mut fmt = BlockFormatter {
|
let mut fmt = BlockFormatter {
|
||||||
results: ResultsRefCursor::new(self.body, self.results),
|
results: results.as_results_cursor(self.body),
|
||||||
style: self.style,
|
style: self.style,
|
||||||
bg: Background::Light,
|
bg: Background::Light,
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt.write_node_label(&mut label, self.body, *block).unwrap();
|
fmt.write_node_label(&mut label, *block).unwrap();
|
||||||
dot::LabelText::html(String::from_utf8(label).unwrap())
|
dot::LabelText::html(String::from_utf8(label).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +109,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
|
impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
|
@ -137,16 +143,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockFormatter<'a, 'tcx, A>
|
struct BlockFormatter<'res, 'mir, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
results: ResultsRefCursor<'a, 'a, 'tcx, A>,
|
results: ResultsRefCursor<'res, 'mir, 'tcx, A>,
|
||||||
bg: Background,
|
bg: Background,
|
||||||
style: OutputStyle,
|
style: OutputStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, A> BlockFormatter<'a, 'tcx, A>
|
impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
A::Domain: DebugWithContext<A>,
|
A::Domain: DebugWithContext<A>,
|
||||||
|
@ -159,12 +165,7 @@ where
|
||||||
bg
|
bg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_node_label(
|
fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> {
|
||||||
&mut self,
|
|
||||||
w: &mut impl io::Write,
|
|
||||||
body: &'a Body<'tcx>,
|
|
||||||
block: BasicBlock,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
// Sample output:
|
// Sample output:
|
||||||
// +-+-----------------------------------------------+
|
// +-+-----------------------------------------------+
|
||||||
// A | bb4 |
|
// A | bb4 |
|
||||||
|
@ -215,11 +216,11 @@ where
|
||||||
self.write_row_with_full_state(w, "", "(on start)")?;
|
self.write_row_with_full_state(w, "", "(on start)")?;
|
||||||
|
|
||||||
// D + E: Statement and terminator transfer functions
|
// D + E: Statement and terminator transfer functions
|
||||||
self.write_statements_and_terminator(w, body, block)?;
|
self.write_statements_and_terminator(w, block)?;
|
||||||
|
|
||||||
// F: State at end of block
|
// F: State at end of block
|
||||||
|
|
||||||
let terminator = body[block].terminator();
|
let terminator = self.results.body()[block].terminator();
|
||||||
|
|
||||||
// Write the full dataflow state immediately after the terminator if it differs from the
|
// Write the full dataflow state immediately after the terminator if it differs from the
|
||||||
// state at block entry.
|
// state at block entry.
|
||||||
|
@ -389,10 +390,14 @@ where
|
||||||
fn write_statements_and_terminator(
|
fn write_statements_and_terminator(
|
||||||
&mut self,
|
&mut self,
|
||||||
w: &mut impl io::Write,
|
w: &mut impl io::Write,
|
||||||
body: &'a Body<'tcx>,
|
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style);
|
let diffs = StateDiffCollector::run(
|
||||||
|
self.results.body(),
|
||||||
|
block,
|
||||||
|
self.results.mut_results(),
|
||||||
|
self.style,
|
||||||
|
);
|
||||||
|
|
||||||
let mut diffs_before = diffs.before.map(|v| v.into_iter());
|
let mut diffs_before = diffs.before.map(|v| v.into_iter());
|
||||||
let mut diffs_after = diffs.after.into_iter();
|
let mut diffs_after = diffs.after.into_iter();
|
||||||
|
@ -401,7 +406,7 @@ where
|
||||||
if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
|
if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, statement) in body[block].statements.iter().enumerate() {
|
for (i, statement) in self.results.body()[block].statements.iter().enumerate() {
|
||||||
let statement_str = format!("{statement:?}");
|
let statement_str = format!("{statement:?}");
|
||||||
let index_str = format!("{i}");
|
let index_str = format!("{i}");
|
||||||
|
|
||||||
|
@ -423,7 +428,7 @@ where
|
||||||
assert!(diffs_after.is_empty());
|
assert!(diffs_after.is_empty());
|
||||||
assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
|
assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
|
||||||
|
|
||||||
let terminator = body[block].terminator();
|
let terminator = self.results.body()[block].terminator();
|
||||||
let mut terminator_str = String::new();
|
let mut terminator_str = String::new();
|
||||||
terminator.kind.fmt_head(&mut terminator_str).unwrap();
|
terminator.kind.fmt_head(&mut terminator_str).unwrap();
|
||||||
|
|
||||||
|
@ -492,29 +497,24 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StateDiffCollector<'a, 'tcx, A>
|
struct StateDiffCollector<D> {
|
||||||
where
|
prev_state: D,
|
||||||
A: Analysis<'tcx>,
|
|
||||||
{
|
|
||||||
analysis: &'a A,
|
|
||||||
prev_state: A::Domain,
|
|
||||||
before: Option<Vec<String>>,
|
before: Option<Vec<String>>,
|
||||||
after: Vec<String>,
|
after: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, A> StateDiffCollector<'a, 'tcx, A>
|
impl<D> StateDiffCollector<D> {
|
||||||
where
|
fn run<'tcx, A>(
|
||||||
A: Analysis<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
A::Domain: DebugWithContext<A>,
|
|
||||||
{
|
|
||||||
fn run(
|
|
||||||
body: &'a mir::Body<'tcx>,
|
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
results: &'a Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
style: OutputStyle,
|
style: OutputStyle,
|
||||||
) -> Self {
|
) -> Self
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx, Domain = D>,
|
||||||
|
D: DebugWithContext<A>,
|
||||||
|
{
|
||||||
let mut collector = StateDiffCollector {
|
let mut collector = StateDiffCollector {
|
||||||
analysis: &results.analysis,
|
|
||||||
prev_state: results.analysis.bottom_value(body),
|
prev_state: results.analysis.bottom_value(body),
|
||||||
after: vec![],
|
after: vec![],
|
||||||
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
|
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
|
||||||
|
@ -525,7 +525,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
|
impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
A::Domain: DebugWithContext<A>,
|
A::Domain: DebugWithContext<A>,
|
||||||
|
@ -534,6 +534,7 @@ where
|
||||||
|
|
||||||
fn visit_block_start(
|
fn visit_block_start(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_block_data: &mir::BasicBlockData<'tcx>,
|
_block_data: &mir::BasicBlockData<'tcx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
|
@ -545,6 +546,7 @@ where
|
||||||
|
|
||||||
fn visit_block_end(
|
fn visit_block_end(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_block_data: &mir::BasicBlockData<'tcx>,
|
_block_data: &mir::BasicBlockData<'tcx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
|
@ -556,45 +558,49 @@ where
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
if let Some(before) = self.before.as_mut() {
|
if let Some(before) = self.before.as_mut() {
|
||||||
before.push(diff_pretty(state, &self.prev_state, self.analysis));
|
before.push(diff_pretty(state, &self.prev_state, &results.analysis));
|
||||||
self.prev_state.clone_from(state)
|
self.prev_state.clone_from(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
|
self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
|
||||||
self.prev_state.clone_from(state)
|
self.prev_state.clone_from(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
if let Some(before) = self.before.as_mut() {
|
if let Some(before) = self.before.as_mut() {
|
||||||
before.push(diff_pretty(state, &self.prev_state, self.analysis));
|
before.push(diff_pretty(state, &self.prev_state, &results.analysis));
|
||||||
self.prev_state.clone_from(state)
|
self.prev_state.clone_from(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, A>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
|
self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
|
||||||
self.prev_state.clone_from(state)
|
self.prev_state.clone_from(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,9 @@ pub mod graphviz;
|
||||||
pub mod lattice;
|
pub mod lattice;
|
||||||
mod visitor;
|
mod visitor;
|
||||||
|
|
||||||
pub use self::cursor::{ResultsCursor, ResultsRefCursor};
|
pub use self::cursor::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
|
||||||
pub use self::direction::{Backward, Direction, Forward};
|
pub use self::direction::{Backward, Direction, Forward};
|
||||||
pub use self::engine::{Engine, Results};
|
pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
|
||||||
pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
|
pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
|
||||||
pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
|
pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ pub trait AnalysisDomain<'tcx> {
|
||||||
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// Updates the current dataflow state with the effect of evaluating a statement.
|
/// Updates the current dataflow state with the effect of evaluating a statement.
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -159,7 +159,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
|
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
|
||||||
/// analyses should not implement this without also implementing `apply_statement_effect`.
|
/// analyses should not implement this without also implementing `apply_statement_effect`.
|
||||||
fn apply_before_statement_effect(
|
fn apply_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_state: &mut Self::Domain,
|
_state: &mut Self::Domain,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -173,7 +173,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
|
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
|
||||||
/// initialized here.
|
/// initialized here.
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -186,7 +186,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
|
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
|
||||||
/// analyses should not implement this without also implementing `apply_terminator_effect`.
|
/// analyses should not implement this without also implementing `apply_terminator_effect`.
|
||||||
fn apply_before_terminator_effect(
|
fn apply_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_state: &mut Self::Domain,
|
_state: &mut Self::Domain,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -201,7 +201,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// This is separate from `apply_terminator_effect` to properly track state across unwind
|
/// This is separate from `apply_terminator_effect` to properly track state across unwind
|
||||||
/// edges.
|
/// edges.
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -214,7 +214,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
///
|
///
|
||||||
/// By default, no effects happen.
|
/// By default, no effects happen.
|
||||||
fn apply_yield_resume_effect(
|
fn apply_yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_state: &mut Self::Domain,
|
_state: &mut Self::Domain,
|
||||||
_resume_block: BasicBlock,
|
_resume_block: BasicBlock,
|
||||||
_resume_place: mir::Place<'tcx>,
|
_resume_place: mir::Place<'tcx>,
|
||||||
|
@ -235,7 +235,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
/// engine doesn't need to clone the exit state for a block unless
|
/// engine doesn't need to clone the exit state for a block unless
|
||||||
/// `SwitchIntEdgeEffects::apply` is actually called.
|
/// `SwitchIntEdgeEffects::apply` is actually called.
|
||||||
fn apply_switch_int_edge_effects(
|
fn apply_switch_int_edge_effects(
|
||||||
&self,
|
&mut self,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
_discr: &mir::Operand<'tcx>,
|
_discr: &mir::Operand<'tcx>,
|
||||||
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||||
|
@ -269,6 +269,21 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines an `Analysis` which can be cloned for use in multiple `ResultsCursor`s or
|
||||||
|
/// `ResultsVisitor`s. Note this need not be a full clone, only enough of one to be used with a new
|
||||||
|
/// `ResultsCursor` or `ResultsVisitor`
|
||||||
|
pub trait CloneAnalysis {
|
||||||
|
fn clone_analysis(&self) -> Self;
|
||||||
|
}
|
||||||
|
impl<'tcx, A> CloneAnalysis for A
|
||||||
|
where
|
||||||
|
A: Analysis<'tcx> + Copy,
|
||||||
|
{
|
||||||
|
fn clone_analysis(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A gen/kill dataflow problem.
|
/// A gen/kill dataflow problem.
|
||||||
///
|
///
|
||||||
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
|
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
|
||||||
|
@ -282,7 +297,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_statement_effect`.
|
/// See `Analysis::apply_statement_effect`.
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -290,7 +305,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_before_statement_effect`.
|
/// See `Analysis::apply_before_statement_effect`.
|
||||||
fn before_statement_effect(
|
fn before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -299,7 +314,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_terminator_effect`.
|
/// See `Analysis::apply_terminator_effect`.
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -307,7 +322,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_before_terminator_effect`.
|
/// See `Analysis::apply_before_terminator_effect`.
|
||||||
fn before_terminator_effect(
|
fn before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -318,7 +333,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_call_return_effect`.
|
/// See `Analysis::apply_call_return_effect`.
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -326,7 +341,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_yield_resume_effect`.
|
/// See `Analysis::apply_yield_resume_effect`.
|
||||||
fn yield_resume_effect(
|
fn yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_resume_block: BasicBlock,
|
_resume_block: BasicBlock,
|
||||||
_resume_place: mir::Place<'tcx>,
|
_resume_place: mir::Place<'tcx>,
|
||||||
|
@ -335,7 +350,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
|
||||||
|
|
||||||
/// See `Analysis::apply_switch_int_edge_effects`.
|
/// See `Analysis::apply_switch_int_edge_effects`.
|
||||||
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
||||||
&self,
|
&mut self,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
_discr: &mir::Operand<'tcx>,
|
_discr: &mir::Operand<'tcx>,
|
||||||
_edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
_edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
||||||
|
@ -349,7 +364,7 @@ where
|
||||||
A::Domain: GenKill<A::Idx> + BitSetExt<A::Idx>,
|
A::Domain: GenKill<A::Idx> + BitSetExt<A::Idx>,
|
||||||
{
|
{
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -358,7 +373,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_before_statement_effect(
|
fn apply_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -367,7 +382,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -376,7 +391,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_before_terminator_effect(
|
fn apply_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -387,7 +402,7 @@ where
|
||||||
/* Edge-specific effects */
|
/* Edge-specific effects */
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -396,7 +411,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_yield_resume_effect(
|
fn apply_yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut A::Domain,
|
state: &mut A::Domain,
|
||||||
resume_block: BasicBlock,
|
resume_block: BasicBlock,
|
||||||
resume_place: mir::Place<'tcx>,
|
resume_place: mir::Place<'tcx>,
|
||||||
|
@ -405,7 +420,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_switch_int_edge_effects(
|
fn apply_switch_int_edge_effects(
|
||||||
&self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
discr: &mir::Operand<'tcx>,
|
discr: &mir::Operand<'tcx>,
|
||||||
edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
|
edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
|
||||||
|
|
|
@ -179,7 +179,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
|
|
||||||
impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -189,7 +189,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_before_statement_effect(
|
fn apply_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -199,7 +199,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -209,7 +209,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_before_terminator_effect(
|
fn apply_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -219,7 +219,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_state: &mut Self::Domain,
|
_state: &mut Self::Domain,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -266,7 +266,8 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
|
||||||
let body = analysis.body;
|
let body = analysis.body;
|
||||||
|
|
||||||
let mut cursor =
|
let mut cursor =
|
||||||
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
|
Results { entry_sets: analysis.mock_entry_sets(), analysis, _marker: PhantomData }
|
||||||
|
.into_results_cursor(body);
|
||||||
|
|
||||||
cursor.allow_unreachable();
|
cursor.allow_unreachable();
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
|
|
||||||
use super::{Analysis, Direction, Results};
|
use super::{Analysis, Direction, EntrySets, Results};
|
||||||
|
|
||||||
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
|
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
|
||||||
/// dataflow state at that location.
|
/// dataflow state at that location.
|
||||||
pub fn visit_results<'mir, 'tcx, F, V>(
|
pub fn visit_results<'mir, 'tcx, F, R>(
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||||
results: &V,
|
results: &mut R,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
|
||||||
) where
|
) where
|
||||||
V: ResultsVisitable<'tcx, FlowState = F>,
|
R: ResultsVisitable<'tcx, FlowState = F>,
|
||||||
{
|
{
|
||||||
let mut state = results.new_flow_state(body);
|
let mut state = results.new_flow_state(body);
|
||||||
|
|
||||||
|
@ -22,15 +24,18 @@ pub fn visit_results<'mir, 'tcx, F, V>(
|
||||||
assert!(reachable_blocks.contains(block));
|
assert!(reachable_blocks.contains(block));
|
||||||
|
|
||||||
let block_data = &body[block];
|
let block_data = &body[block];
|
||||||
V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ResultsVisitor<'mir, 'tcx> {
|
/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
|
||||||
|
/// visited.
|
||||||
|
pub trait ResultsVisitor<'mir, 'tcx, R> {
|
||||||
type FlowState;
|
type FlowState;
|
||||||
|
|
||||||
fn visit_block_start(
|
fn visit_block_start(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_block_data: &'mir mir::BasicBlockData<'tcx>,
|
_block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
|
@ -41,6 +46,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
|
||||||
/// its `statement_effect`.
|
/// its `statement_effect`.
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -51,6 +57,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
|
||||||
/// statement applied to `state`.
|
/// statement applied to `state`.
|
||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -61,6 +68,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
|
||||||
/// its `terminator_effect`.
|
/// its `terminator_effect`.
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -73,6 +81,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
|
||||||
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -81,6 +90,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
|
||||||
|
|
||||||
fn visit_block_end(
|
fn visit_block_end(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
_state: &Self::FlowState,
|
_state: &Self::FlowState,
|
||||||
_block_data: &'mir mir::BasicBlockData<'tcx>,
|
_block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
|
@ -105,37 +115,38 @@ pub trait ResultsVisitable<'tcx> {
|
||||||
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
|
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
fn reconstruct_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
fn reconstruct_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
fn reconstruct_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
fn reconstruct_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
|
impl<'tcx, A, E> ResultsVisitable<'tcx> for Results<'tcx, A, E>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
|
E: Borrow<EntrySets<'tcx, A>>,
|
||||||
{
|
{
|
||||||
type FlowState = A::Domain;
|
type FlowState = A::Domain;
|
||||||
|
|
||||||
|
@ -146,11 +157,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
|
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
|
||||||
state.clone_from(&self.entry_set_for_block(block));
|
state.clone_from(self.entry_set_for_block(block));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
fn reconstruct_before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -159,7 +170,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
fn reconstruct_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -168,7 +179,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
fn reconstruct_before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
term: &mir::Terminator<'tcx>,
|
term: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -177,7 +188,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
fn reconstruct_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::FlowState,
|
state: &mut Self::FlowState,
|
||||||
term: &mir::Terminator<'tcx>,
|
term: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_middle::mir::*;
|
||||||
/// At present, this is used as a very limited form of alias analysis. For example,
|
/// At present, this is used as a very limited form of alias analysis. For example,
|
||||||
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
|
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
|
||||||
/// immovable generators.
|
/// immovable generators.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct MaybeBorrowedLocals;
|
pub struct MaybeBorrowedLocals;
|
||||||
|
|
||||||
impl MaybeBorrowedLocals {
|
impl MaybeBorrowedLocals {
|
||||||
|
@ -36,7 +37,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
|
||||||
type Idx = Local;
|
type Idx = Local;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -45,7 +46,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -54,7 +55,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi
|
||||||
/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
|
/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
|
||||||
/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
|
/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
|
||||||
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
|
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct MaybeLiveLocals;
|
pub struct MaybeLiveLocals;
|
||||||
|
|
||||||
impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
|
impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
|
||||||
|
@ -43,7 +44,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
|
||||||
type Idx = Local;
|
type Idx = Local;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -52,7 +53,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -61,7 +62,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -74,7 +75,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yield_resume_effect(
|
fn yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_resume_block: mir::BasicBlock,
|
_resume_block: mir::BasicBlock,
|
||||||
resume_place: mir::Place<'tcx>,
|
resume_place: mir::Place<'tcx>,
|
||||||
|
@ -216,6 +217,7 @@ impl DefUse {
|
||||||
/// This is basically written for dead store elimination and nothing else.
|
/// This is basically written for dead store elimination and nothing else.
|
||||||
///
|
///
|
||||||
/// All of the caveats of `MaybeLiveLocals` apply.
|
/// All of the caveats of `MaybeLiveLocals` apply.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct MaybeTransitiveLiveLocals<'a> {
|
pub struct MaybeTransitiveLiveLocals<'a> {
|
||||||
always_live: &'a BitSet<Local>,
|
always_live: &'a BitSet<Local>,
|
||||||
}
|
}
|
||||||
|
@ -248,7 +250,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
||||||
|
|
||||||
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut Self::Domain,
|
trans: &mut Self::Domain,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -283,7 +285,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut Self::Domain,
|
trans: &mut Self::Domain,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -292,7 +294,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut Self::Domain,
|
trans: &mut Self::Domain,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -305,7 +307,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_yield_resume_effect(
|
fn apply_yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut Self::Domain,
|
trans: &mut Self::Domain,
|
||||||
_resume_block: mir::BasicBlock,
|
_resume_block: mir::BasicBlock,
|
||||||
resume_place: mir::Place<'tcx>,
|
resume_place: mir::Place<'tcx>,
|
||||||
|
|
|
@ -306,7 +306,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
||||||
type Idx = MovePathIndex;
|
type Idx = MovePathIndex;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
statement: &mir::Statement<'tcx>,
|
statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -329,7 +329,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -351,7 +351,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -372,7 +372,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
||||||
&self,
|
&mut self,
|
||||||
block: mir::BasicBlock,
|
block: mir::BasicBlock,
|
||||||
discr: &mir::Operand<'tcx>,
|
discr: &mir::Operand<'tcx>,
|
||||||
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
||||||
|
@ -442,7 +442,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||||
type Idx = MovePathIndex;
|
type Idx = MovePathIndex;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -456,7 +456,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -467,7 +467,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -488,7 +488,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
|
||||||
&self,
|
&mut self,
|
||||||
block: mir::BasicBlock,
|
block: mir::BasicBlock,
|
||||||
discr: &mir::Operand<'tcx>,
|
discr: &mir::Operand<'tcx>,
|
||||||
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
|
||||||
|
@ -562,7 +562,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
|
||||||
type Idx = MovePathIndex;
|
type Idx = MovePathIndex;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -573,7 +573,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -584,7 +584,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: mir::BasicBlock,
|
_block: mir::BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -627,7 +627,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||||
|
|
||||||
#[instrument(skip(self, trans), level = "debug")]
|
#[instrument(skip(self, trans), level = "debug")]
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -651,7 +651,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||||
|
|
||||||
#[instrument(skip(self, trans, _terminator), level = "debug")]
|
#[instrument(skip(self, trans, _terminator), level = "debug")]
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -672,7 +672,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
block: mir::BasicBlock,
|
block: mir::BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
|
|
||||||
use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
|
use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor};
|
||||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MaybeStorageLive<'a> {
|
pub struct MaybeStorageLive<'a> {
|
||||||
|
@ -17,6 +16,12 @@ impl<'a> MaybeStorageLive<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::CloneAnalysis for MaybeStorageLive<'_> {
|
||||||
|
fn clone_analysis(&self) -> Self {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
|
impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
|
||||||
type Domain = BitSet<Local>;
|
type Domain = BitSet<Local>;
|
||||||
|
|
||||||
|
@ -43,7 +48,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
|
||||||
type Idx = Local;
|
type Idx = Local;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
_: Location,
|
_: Location,
|
||||||
|
@ -56,7 +61,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_: &mir::Terminator<'tcx>,
|
_: &mir::Terminator<'tcx>,
|
||||||
_: Location,
|
_: Location,
|
||||||
|
@ -65,7 +70,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -110,7 +115,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
|
||||||
type Idx = Local;
|
type Idx = Local;
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
_: Location,
|
_: Location,
|
||||||
|
@ -123,7 +128,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_: &mir::Terminator<'tcx>,
|
_: &mir::Terminator<'tcx>,
|
||||||
_: Location,
|
_: Location,
|
||||||
|
@ -132,7 +137,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
_trans: &mut impl GenKill<Self::Idx>,
|
_trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -141,28 +146,28 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
|
type BorrowedLocalsResults<'res, 'mir, 'tcx> =
|
||||||
|
ResultsClonedCursor<'res, 'mir, 'tcx, MaybeBorrowedLocals>;
|
||||||
|
|
||||||
/// Dataflow analysis that determines whether each local requires storage at a
|
/// Dataflow analysis that determines whether each local requires storage at a
|
||||||
/// given location; i.e. whether its storage can go away without being observed.
|
/// given location; i.e. whether its storage can go away without being observed.
|
||||||
pub struct MaybeRequiresStorage<'mir, 'tcx> {
|
pub struct MaybeRequiresStorage<'res, 'mir, 'tcx> {
|
||||||
body: &'mir Body<'tcx>,
|
borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>,
|
||||||
borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
|
impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> {
|
||||||
pub fn new(
|
pub fn new(borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>) -> Self {
|
||||||
body: &'mir Body<'tcx>,
|
MaybeRequiresStorage { borrowed_locals }
|
||||||
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
|
|
||||||
) -> Self {
|
|
||||||
MaybeRequiresStorage {
|
|
||||||
body,
|
|
||||||
borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
|
impl crate::CloneAnalysis for MaybeRequiresStorage<'_, '_, '_> {
|
||||||
|
fn clone_analysis(&self) -> Self {
|
||||||
|
Self { borrowed_locals: self.borrowed_locals.new_cursor() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
||||||
type Domain = BitSet<Local>;
|
type Domain = BitSet<Local>;
|
||||||
|
|
||||||
const NAME: &'static str = "requires_storage";
|
const NAME: &'static str = "requires_storage";
|
||||||
|
@ -181,17 +186,17 @@ impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
|
impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
||||||
type Idx = Local;
|
type Idx = Local;
|
||||||
|
|
||||||
fn before_statement_effect(
|
fn before_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
stmt: &mir::Statement<'tcx>,
|
stmt: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
// If a place is borrowed in a statement, it needs storage for that statement.
|
// If a place is borrowed in a statement, it needs storage for that statement.
|
||||||
self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
|
self.borrowed_locals.mut_analysis().statement_effect(trans, stmt, loc);
|
||||||
|
|
||||||
match &stmt.kind {
|
match &stmt.kind {
|
||||||
StatementKind::StorageDead(l) => trans.kill(*l),
|
StatementKind::StorageDead(l) => trans.kill(*l),
|
||||||
|
@ -218,7 +223,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement_effect(
|
fn statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_: &mir::Statement<'tcx>,
|
_: &mir::Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -229,13 +234,13 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_terminator_effect(
|
fn before_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
||||||
self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
|
self.borrowed_locals.mut_analysis().terminator_effect(trans, terminator, loc);
|
||||||
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { destination, .. } => {
|
TerminatorKind::Call { destination, .. } => {
|
||||||
|
@ -282,7 +287,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(
|
fn terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -321,7 +326,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_return_effect(
|
fn call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -330,7 +335,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yield_resume_effect(
|
fn yield_resume_effect(
|
||||||
&self,
|
&mut self,
|
||||||
trans: &mut impl GenKill<Self::Idx>,
|
trans: &mut impl GenKill<Self::Idx>,
|
||||||
_resume_block: BasicBlock,
|
_resume_block: BasicBlock,
|
||||||
resume_place: mir::Place<'tcx>,
|
resume_place: mir::Place<'tcx>,
|
||||||
|
@ -339,28 +344,28 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
|
impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> {
|
||||||
/// Kill locals that are fully moved and have not been borrowed.
|
/// Kill locals that are fully moved and have not been borrowed.
|
||||||
fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
|
fn check_for_move(&mut self, trans: &mut impl GenKill<Local>, loc: Location) {
|
||||||
let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
|
let body = self.borrowed_locals.body();
|
||||||
visitor.visit_location(&self.body, loc);
|
let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals };
|
||||||
|
visitor.visit_location(body, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MoveVisitor<'a, 'mir, 'tcx, T> {
|
struct MoveVisitor<'a, 'res, 'mir, 'tcx, T> {
|
||||||
borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
|
borrowed_locals: &'a mut BorrowedLocalsResults<'res, 'mir, 'tcx>,
|
||||||
trans: &'a mut T,
|
trans: &'a mut T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
|
impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx, T>
|
||||||
where
|
where
|
||||||
T: GenKill<Local>,
|
T: GenKill<Local>,
|
||||||
{
|
{
|
||||||
fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
|
fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
|
||||||
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
|
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
|
||||||
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
|
self.borrowed_locals.seek_before_primary_effect(loc);
|
||||||
borrowed_locals.seek_before_primary_effect(loc);
|
if !self.borrowed_locals.contains(local) {
|
||||||
if !borrowed_locals.contains(local) {
|
|
||||||
self.trans.kill(local);
|
self.trans.kill(local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,9 @@ pub use self::drop_flag_effects::{
|
||||||
};
|
};
|
||||||
pub use self::framework::{
|
pub use self::framework::{
|
||||||
fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
|
fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
|
||||||
Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
|
CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
|
||||||
ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
|
ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitable,
|
||||||
|
ResultsVisitor, SwitchIntEdgeEffects,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::move_paths::MoveData;
|
use self::move_paths::MoveData;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::impls::{
|
||||||
use crate::move_paths::{HasMoveData, MoveData};
|
use crate::move_paths::{HasMoveData, MoveData};
|
||||||
use crate::move_paths::{LookupResult, MovePathIndex};
|
use crate::move_paths::{LookupResult, MovePathIndex};
|
||||||
use crate::MoveDataParamEnv;
|
use crate::MoveDataParamEnv;
|
||||||
use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
|
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
|
||||||
|
|
||||||
pub struct SanityCheck;
|
pub struct SanityCheck;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||||
.into_engine(tcx, body)
|
.into_engine(tcx, body)
|
||||||
.iterate_to_fixpoint();
|
.iterate_to_fixpoint();
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, body, &flow_inits);
|
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||||
|
@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||||
.into_engine(tcx, body)
|
.into_engine(tcx, body)
|
||||||
.iterate_to_fixpoint();
|
.iterate_to_fixpoint();
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, body, &flow_uninits);
|
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||||
|
@ -58,13 +58,13 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||||
.into_engine(tcx, body)
|
.into_engine(tcx, body)
|
||||||
.iterate_to_fixpoint();
|
.iterate_to_fixpoint();
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, body, &flow_def_inits);
|
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
||||||
|
|
||||||
sanity_check_via_rustc_peek(tcx, body, &flow_liveness);
|
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
||||||
|
@ -91,17 +91,14 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||||
/// errors are not intended to be used for unit tests.)
|
/// errors are not intended to be used for unit tests.)
|
||||||
pub fn sanity_check_via_rustc_peek<'tcx, A>(
|
pub fn sanity_check_via_rustc_peek<'tcx, A>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
mut cursor: ResultsCursor<'_, 'tcx, A>,
|
||||||
results: &Results<'tcx, A>,
|
|
||||||
) where
|
) where
|
||||||
A: RustcPeekAt<'tcx>,
|
A: RustcPeekAt<'tcx>,
|
||||||
{
|
{
|
||||||
let def_id = body.source.def_id();
|
let def_id = cursor.body().source.def_id();
|
||||||
debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
|
debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
|
||||||
|
|
||||||
let mut cursor = ResultsCursor::new(body, results);
|
let peek_calls = cursor.body().basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
|
||||||
|
|
||||||
let peek_calls = body.basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
|
|
||||||
PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
|
PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,8 +129,8 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
|
||||||
) => {
|
) => {
|
||||||
let loc = Location { block: bb, statement_index };
|
let loc = Location { block: bb, statement_index };
|
||||||
cursor.seek_before_primary_effect(loc);
|
cursor.seek_before_primary_effect(loc);
|
||||||
let state = cursor.get();
|
let (state, analysis) = cursor.get_with_analysis();
|
||||||
results.analysis.peek_at(tcx, *place, state, call);
|
analysis.peek_at(tcx, *place, state, call);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -343,7 +343,7 @@ where
|
||||||
T: ValueAnalysis<'tcx>,
|
T: ValueAnalysis<'tcx>,
|
||||||
{
|
{
|
||||||
fn apply_statement_effect(
|
fn apply_statement_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
statement: &Statement<'tcx>,
|
statement: &Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -354,7 +354,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_terminator_effect(
|
fn apply_terminator_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
terminator: &Terminator<'tcx>,
|
terminator: &Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
|
@ -365,7 +365,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Self::Domain,
|
state: &mut Self::Domain,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
return_places: crate::CallReturnPlaces<'_, 'tcx>,
|
return_places: crate::CallReturnPlaces<'_, 'tcx>,
|
||||||
|
@ -376,7 +376,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_switch_int_edge_effects(
|
fn apply_switch_int_edge_effects(
|
||||||
&self,
|
&mut self,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
discr: &Operand<'tcx>,
|
discr: &Operand<'tcx>,
|
||||||
apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||||
|
|
|
@ -10,8 +10,12 @@ use rustc_middle::mir::visit::{MutVisitor, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::layout::TyAndLayout;
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
|
use rustc_mir_dataflow::value_analysis::{
|
||||||
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
|
Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
|
||||||
|
};
|
||||||
|
use rustc_mir_dataflow::{
|
||||||
|
lattice::FlatSet, Analysis, Results, ResultsVisitor, SwitchIntEdgeEffects,
|
||||||
|
};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
|
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
|
||||||
|
|
||||||
|
@ -52,11 +56,11 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
|
||||||
|
|
||||||
// Perform the actual dataflow analysis.
|
// Perform the actual dataflow analysis.
|
||||||
let analysis = ConstAnalysis::new(tcx, body, map);
|
let analysis = ConstAnalysis::new(tcx, body, map);
|
||||||
let results = debug_span!("analyze")
|
let mut results = debug_span!("analyze")
|
||||||
.in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
|
.in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
|
||||||
|
|
||||||
// Collect results and patch the body afterwards.
|
// Collect results and patch the body afterwards.
|
||||||
let mut visitor = CollectAndPatch::new(tcx, &results.analysis.0.map);
|
let mut visitor = CollectAndPatch::new(tcx);
|
||||||
debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
|
debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
|
||||||
debug_span!("patch").in_scope(|| visitor.visit_body(body));
|
debug_span!("patch").in_scope(|| visitor.visit_body(body));
|
||||||
}
|
}
|
||||||
|
@ -387,9 +391,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollectAndPatch<'tcx, 'map> {
|
struct CollectAndPatch<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
map: &'map Map,
|
|
||||||
|
|
||||||
/// For a given MIR location, this stores the values of the operands used by that location. In
|
/// For a given MIR location, this stores the values of the operands used by that location. In
|
||||||
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
|
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
|
||||||
|
@ -400,9 +403,9 @@ struct CollectAndPatch<'tcx, 'map> {
|
||||||
assignments: FxHashMap<Location, ScalarTy<'tcx>>,
|
assignments: FxHashMap<Location, ScalarTy<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 'map> CollectAndPatch<'tcx, 'map> {
|
impl<'tcx> CollectAndPatch<'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>, map: &'map Map) -> Self {
|
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
Self { tcx, map, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
|
Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> {
|
fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> {
|
||||||
|
@ -414,18 +417,23 @@ impl<'tcx, 'map> CollectAndPatch<'tcx, 'map> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map> {
|
impl<'mir, 'tcx>
|
||||||
|
ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
|
||||||
|
for CollectAndPatch<'tcx>
|
||||||
|
{
|
||||||
type FlowState = State<FlatSet<ScalarTy<'tcx>>>;
|
type FlowState = State<FlatSet<ScalarTy<'tcx>>>;
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
statement: &'mir Statement<'tcx>,
|
statement: &'mir Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(box (_, rvalue)) => {
|
StatementKind::Assign(box (_, rvalue)) => {
|
||||||
OperandCollector { state, visitor: self }.visit_rvalue(rvalue, location);
|
OperandCollector { state, visitor: self, map: &results.analysis.0.map }
|
||||||
|
.visit_rvalue(rvalue, location);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -433,6 +441,7 @@ impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map
|
||||||
|
|
||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
statement: &'mir Statement<'tcx>,
|
statement: &'mir Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -441,30 +450,34 @@ impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map
|
||||||
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(_)))) => {
|
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(_)))) => {
|
||||||
// Don't overwrite the assignment if it already uses a constant (to keep the span).
|
// Don't overwrite the assignment if it already uses a constant (to keep the span).
|
||||||
}
|
}
|
||||||
StatementKind::Assign(box (place, _)) => match state.get(place.as_ref(), self.map) {
|
StatementKind::Assign(box (place, _)) => {
|
||||||
FlatSet::Top => (),
|
match state.get(place.as_ref(), &results.analysis.0.map) {
|
||||||
FlatSet::Elem(value) => {
|
FlatSet::Top => (),
|
||||||
self.assignments.insert(location, value);
|
FlatSet::Elem(value) => {
|
||||||
|
self.assignments.insert(location, value);
|
||||||
|
}
|
||||||
|
FlatSet::Bottom => {
|
||||||
|
// This assignment is either unreachable, or an uninitialized value is assigned.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FlatSet::Bottom => {
|
}
|
||||||
// This assignment is either unreachable, or an uninitialized value is assigned.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
terminator: &'mir Terminator<'tcx>,
|
terminator: &'mir Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
OperandCollector { state, visitor: self }.visit_terminator(terminator, location);
|
OperandCollector { state, visitor: self, map: &results.analysis.0.map }
|
||||||
|
.visit_terminator(terminator, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 'map> MutVisitor<'tcx> for CollectAndPatch<'tcx, 'map> {
|
impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
@ -496,14 +509,15 @@ impl<'tcx, 'map> MutVisitor<'tcx> for CollectAndPatch<'tcx, 'map> {
|
||||||
|
|
||||||
struct OperandCollector<'tcx, 'map, 'a> {
|
struct OperandCollector<'tcx, 'map, 'a> {
|
||||||
state: &'a State<FlatSet<ScalarTy<'tcx>>>,
|
state: &'a State<FlatSet<ScalarTy<'tcx>>>,
|
||||||
visitor: &'a mut CollectAndPatch<'tcx, 'map>,
|
visitor: &'a mut CollectAndPatch<'tcx>,
|
||||||
|
map: &'map Map,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
|
impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
|
||||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Copy(place) | Operand::Move(place) => {
|
Operand::Copy(place) | Operand::Move(place) => {
|
||||||
match self.state.get(place.as_ref(), self.visitor.map) {
|
match self.state.get(place.as_ref(), self.map) {
|
||||||
FlatSet::Top => (),
|
FlatSet::Top => (),
|
||||||
FlatSet::Elem(value) => {
|
FlatSet::Elem(value) => {
|
||||||
self.visitor.before_effect.insert((location, *place), value);
|
self.visitor.before_effect.insert((location, *place), value);
|
||||||
|
|
|
@ -597,16 +597,15 @@ fn locals_live_across_suspend_points<'tcx>(
|
||||||
let borrowed_locals_results =
|
let borrowed_locals_results =
|
||||||
MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
|
MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
|
||||||
|
|
||||||
let mut borrowed_locals_cursor =
|
let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body_ref);
|
||||||
rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
|
|
||||||
|
|
||||||
// Calculate the MIR locals that we actually need to keep storage around
|
// Calculate the MIR locals that we actually need to keep storage around
|
||||||
// for.
|
// for.
|
||||||
let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
|
let mut requires_storage_results =
|
||||||
.into_engine(tcx, body_ref)
|
MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
|
||||||
.iterate_to_fixpoint();
|
.into_engine(tcx, body_ref)
|
||||||
let mut requires_storage_cursor =
|
.iterate_to_fixpoint();
|
||||||
rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
|
let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body_ref);
|
||||||
|
|
||||||
// Calculate the liveness of MIR locals ignoring borrows.
|
// Calculate the liveness of MIR locals ignoring borrows.
|
||||||
let mut liveness = MaybeLiveLocals
|
let mut liveness = MaybeLiveLocals
|
||||||
|
@ -747,7 +746,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
|
||||||
body: &'mir Body<'tcx>,
|
body: &'mir Body<'tcx>,
|
||||||
saved_locals: &GeneratorSavedLocals,
|
saved_locals: &GeneratorSavedLocals,
|
||||||
always_live_locals: BitSet<Local>,
|
always_live_locals: BitSet<Local>,
|
||||||
requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'_, 'mir, 'tcx>>,
|
||||||
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
|
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
|
||||||
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
||||||
|
|
||||||
|
@ -802,13 +801,14 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
|
||||||
local_conflicts: BitMatrix<Local, Local>,
|
local_conflicts: BitMatrix<Local, Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
|
impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
|
||||||
for StorageConflictVisitor<'mir, 'tcx, '_>
|
for StorageConflictVisitor<'mir, 'tcx, '_>
|
||||||
{
|
{
|
||||||
type FlowState = BitSet<Local>;
|
type FlowState = BitSet<Local>;
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_statement: &'mir Statement<'tcx>,
|
_statement: &'mir Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -818,6 +818,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
|
||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_results: &R,
|
||||||
state: &Self::FlowState,
|
state: &Self::FlowState,
|
||||||
_terminator: &'mir Terminator<'tcx>,
|
_terminator: &'mir Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue