Rollup merge of #148165 - nnethercote:less-mut-Analysis, r=cjgillot
Use `mut` less in dataflow analysis `&mut Analysis` is used a lot: - In results visitors, even though only one visitor needs mutability. - In all the `apply_*` methods, even though only one visitor needs mutability. I've lost track of the number of times I've thought "why are these `mut` again?" and had to look through the code to remind myself. It's really unexpected, and most `Analysis` instances are immutable, because the `state` values are what get mutated. This commit introduces `RefCell` in one analysis and one results visitor. This then lets another existing `RefCell` be removed, and a ton of `&mut Analysis` arguments become `&Analysis`. And then `Analysis` and `Results` can be recombined. r? `@cjgillot`
This commit is contained in:
commit
b5c92233fb
19 changed files with 228 additions and 259 deletions
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -55,7 +55,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -66,7 +66,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -77,7 +77,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
term: &'mir mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -92,7 +92,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -533,7 +533,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -542,7 +542,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -590,7 +590,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -599,7 +599,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{
|
|||
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -537,13 +537,11 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
mbcx.report_region_errors(nll_errors);
|
||||
}
|
||||
|
||||
let (mut flow_analysis, flow_entry_states) =
|
||||
get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||
let flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||
visit_results(
|
||||
body,
|
||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||
&mut flow_analysis,
|
||||
&flow_entry_states,
|
||||
&flow_results,
|
||||
&mut mbcx,
|
||||
);
|
||||
|
||||
|
|
@ -604,7 +602,7 @@ fn get_flow_results<'a, 'tcx>(
|
|||
move_data: &'a MoveData<'tcx>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
|
||||
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
|
||||
// We compute these three analyses individually, but them combine them into
|
||||
// a single results so that `mbcx` can visit them all together.
|
||||
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
|
||||
|
|
@ -629,14 +627,14 @@ fn get_flow_results<'a, 'tcx>(
|
|||
ever_inits: ever_inits.analysis,
|
||||
};
|
||||
|
||||
assert_eq!(borrows.results.len(), uninits.results.len());
|
||||
assert_eq!(borrows.results.len(), ever_inits.results.len());
|
||||
let results: Results<_> =
|
||||
itertools::izip!(borrows.results, uninits.results, ever_inits.results)
|
||||
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
|
||||
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
|
||||
let entry_states: EntryStates<_> =
|
||||
itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
|
||||
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||
.collect();
|
||||
|
||||
(analysis, results)
|
||||
Results { analysis, entry_states }
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||
|
|
@ -790,7 +788,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_analysis: &mut Borrowck<'a, 'tcx>,
|
||||
_analysis: &Borrowck<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
stmt: &Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -865,7 +863,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
|
|||
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_analysis: &mut Borrowck<'a, 'tcx>,
|
||||
_analysis: &Borrowck<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -985,7 +983,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
|
|||
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_analysis: &mut Borrowck<'a, 'tcx>,
|
||||
_analysis: &Borrowck<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ where
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -341,7 +341,7 @@ where
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -351,7 +351,7 @@ where
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
block: BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
//! Random access inspection of the results of a dataflow analysis.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::Deref;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
|
|
@ -10,30 +9,20 @@ use rustc_middle::mir::{self, BasicBlock, Location};
|
|||
|
||||
use super::{Analysis, Direction, Effect, EffectIndex, Results};
|
||||
|
||||
/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either
|
||||
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow`
|
||||
/// doesn't allow mutable borrowing.
|
||||
enum CowMut<'a, T> {
|
||||
BorrowedMut(&'a mut T),
|
||||
/// This is like `Cow`, but it lacks the `T: ToOwned` bound and doesn't support
|
||||
/// `to_owned`/`into_owned`.
|
||||
enum SimpleCow<'a, T> {
|
||||
Borrowed(&'a T),
|
||||
Owned(T),
|
||||
}
|
||||
|
||||
impl<T> Deref for CowMut<'_, T> {
|
||||
impl<T> Deref for SimpleCow<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
match self {
|
||||
CowMut::BorrowedMut(borrowed) => borrowed,
|
||||
CowMut::Owned(owned) => owned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for CowMut<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
CowMut::BorrowedMut(borrowed) => borrowed,
|
||||
CowMut::Owned(owned) => owned,
|
||||
SimpleCow::Borrowed(borrowed) => borrowed,
|
||||
SimpleCow::Owned(owned) => owned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,8 +42,7 @@ where
|
|||
A: Analysis<'tcx>,
|
||||
{
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
analysis: CowMut<'mir, A>,
|
||||
results: Cow<'mir, Results<A::Domain>>,
|
||||
results: SimpleCow<'mir, Results<'tcx, A>>,
|
||||
state: A::Domain,
|
||||
|
||||
pos: CursorPosition,
|
||||
|
|
@ -82,15 +70,10 @@ where
|
|||
self.body
|
||||
}
|
||||
|
||||
fn new(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
analysis: CowMut<'mir, A>,
|
||||
results: Cow<'mir, Results<A::Domain>>,
|
||||
) -> Self {
|
||||
let bottom_value = analysis.bottom_value(body);
|
||||
fn new(body: &'mir mir::Body<'tcx>, results: SimpleCow<'mir, Results<'tcx, A>>) -> Self {
|
||||
let bottom_value = results.analysis.bottom_value(body);
|
||||
ResultsCursor {
|
||||
body,
|
||||
analysis,
|
||||
results,
|
||||
|
||||
// Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that
|
||||
|
|
@ -106,21 +89,13 @@ where
|
|||
}
|
||||
|
||||
/// Returns a new cursor that takes ownership of and inspects analysis results.
|
||||
pub fn new_owning(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
analysis: A,
|
||||
results: Results<A::Domain>,
|
||||
) -> Self {
|
||||
Self::new(body, CowMut::Owned(analysis), Cow::Owned(results))
|
||||
pub fn new_owning(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
|
||||
Self::new(body, SimpleCow::Owned(results))
|
||||
}
|
||||
|
||||
/// Returns a new cursor that borrows and inspects analysis results.
|
||||
pub fn new_borrowing(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
analysis: &'mir mut A,
|
||||
results: &'mir Results<A::Domain>,
|
||||
) -> Self {
|
||||
Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results))
|
||||
pub fn new_borrowing(body: &'mir mir::Body<'tcx>, results: &'mir Results<'tcx, A>) -> Self {
|
||||
Self::new(body, SimpleCow::Borrowed(results))
|
||||
}
|
||||
|
||||
/// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
|
||||
|
|
@ -132,7 +107,7 @@ where
|
|||
|
||||
/// Returns the `Analysis` used to generate the underlying `Results`.
|
||||
pub fn analysis(&self) -> &A {
|
||||
&self.analysis
|
||||
&self.results.analysis
|
||||
}
|
||||
|
||||
/// Resets the cursor to hold the entry set for the given basic block.
|
||||
|
|
@ -144,7 +119,7 @@ where
|
|||
#[cfg(debug_assertions)]
|
||||
assert!(self.reachable_blocks.contains(block));
|
||||
|
||||
self.state.clone_from(&self.results[block]);
|
||||
self.state.clone_from(&self.results.entry_states[block]);
|
||||
self.pos = CursorPosition::block_entry(block);
|
||||
self.state_needs_reset = false;
|
||||
}
|
||||
|
|
@ -236,7 +211,7 @@ where
|
|||
let target_effect_index = effect.at_index(target.statement_index);
|
||||
|
||||
A::Direction::apply_effects_in_range(
|
||||
&mut *self.analysis,
|
||||
&self.results.analysis,
|
||||
&mut self.state,
|
||||
target.block,
|
||||
block_data,
|
||||
|
|
@ -251,8 +226,8 @@ where
|
|||
///
|
||||
/// 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.
|
||||
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
|
||||
f(&mut self.analysis, &mut self.state);
|
||||
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) {
|
||||
f(&self.results.analysis, &mut self.state);
|
||||
self.state_needs_reset = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub trait Direction {
|
|||
|
||||
/// Called by `iterate_to_fixpoint` during initial analysis computation.
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
|
|
@ -28,7 +28,7 @@ pub trait Direction {
|
|||
///
|
||||
/// `effects.start()` must precede or equal `effects.end()` in this direction.
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &mir::BasicBlockData<'tcx>,
|
||||
|
|
@ -40,10 +40,10 @@ pub trait Direction {
|
|||
/// all locations in a basic block (starting from `entry_state` and to
|
||||
/// visit them with `vis`.
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
analysis: &mut A,
|
||||
vis: &mut impl ResultsVisitor<'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>;
|
||||
|
|
@ -56,7 +56,7 @@ impl Direction for Backward {
|
|||
const IS_FORWARD: bool = false;
|
||||
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
|
|
@ -129,7 +129,7 @@ impl Direction for Backward {
|
|||
}
|
||||
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &mir::BasicBlockData<'tcx>,
|
||||
|
|
@ -206,10 +206,10 @@ impl Direction for Backward {
|
|||
}
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
analysis: &mut A,
|
||||
vis: &mut impl ResultsVisitor<'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
|
|
@ -242,7 +242,7 @@ impl Direction for Forward {
|
|||
const IS_FORWARD: bool = true;
|
||||
|
||||
fn apply_effects_in_block<'mir, 'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
body: &mir::Body<'tcx>,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
|
|
@ -312,7 +312,7 @@ impl Direction for Forward {
|
|||
}
|
||||
|
||||
fn apply_effects_in_range<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &mir::BasicBlockData<'tcx>,
|
||||
|
|
@ -386,10 +386,10 @@ impl Direction for Forward {
|
|||
}
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
analysis: &A,
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
analysis: &mut A,
|
||||
vis: &mut impl ResultsVisitor<'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
//! A helpful diagram for debugging dataflow problems.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
|
|
@ -33,8 +32,7 @@ use crate::errors::{
|
|||
pub(super) fn write_graphviz_results<'tcx, A>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
analysis: &mut A,
|
||||
results: &Results<A::Domain>,
|
||||
results: &Results<'tcx, A>,
|
||||
pass_name: Option<&'static str>,
|
||||
) -> std::io::Result<()>
|
||||
where
|
||||
|
|
@ -81,7 +79,7 @@ where
|
|||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
let graphviz = Formatter::new(body, analysis, results, style);
|
||||
let graphviz = Formatter::new(body, results, style);
|
||||
let mut render_opts =
|
||||
vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
|
||||
if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
|
||||
|
|
@ -206,12 +204,7 @@ where
|
|||
A: Analysis<'tcx>,
|
||||
{
|
||||
body: &'mir Body<'tcx>,
|
||||
// The `RefCell` is used because `<Formatter as Labeller>::node_label`
|
||||
// takes `&self`, but it needs to modify the analysis. This is also the
|
||||
// reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has
|
||||
// the operations that involve the mutation, i.e. within the `borrow_mut`.
|
||||
analysis: RefCell<&'mir mut A>,
|
||||
results: &'mir Results<A::Domain>,
|
||||
results: &'mir Results<'tcx, A>,
|
||||
style: OutputStyle,
|
||||
reachable: DenseBitSet<BasicBlock>,
|
||||
}
|
||||
|
|
@ -220,14 +213,9 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A>
|
|||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
fn new(
|
||||
body: &'mir Body<'tcx>,
|
||||
analysis: &'mir mut A,
|
||||
results: &'mir Results<A::Domain>,
|
||||
style: OutputStyle,
|
||||
) -> Self {
|
||||
fn new(body: &'mir Body<'tcx>, results: &'mir Results<'tcx, A>, style: OutputStyle) -> Self {
|
||||
let reachable = traversal::reachable_as_bitset(body);
|
||||
Formatter { body, analysis: analysis.into(), results, style, reachable }
|
||||
Formatter { body, results, style, reachable }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,12 +253,10 @@ where
|
|||
}
|
||||
|
||||
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
|
||||
let analysis = &mut **self.analysis.borrow_mut();
|
||||
|
||||
let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style);
|
||||
let diffs = StateDiffCollector::run(self.body, *block, self.results, self.style);
|
||||
|
||||
let mut fmt = BlockFormatter {
|
||||
cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results),
|
||||
cursor: ResultsCursor::new_borrowing(self.body, self.results),
|
||||
style: self.style,
|
||||
bg: Background::Light,
|
||||
};
|
||||
|
|
@ -698,8 +684,7 @@ impl<D> StateDiffCollector<D> {
|
|||
fn run<'tcx, A>(
|
||||
body: &Body<'tcx>,
|
||||
block: BasicBlock,
|
||||
analysis: &mut A,
|
||||
results: &Results<A::Domain>,
|
||||
results: &Results<'tcx, A>,
|
||||
style: OutputStyle,
|
||||
) -> Self
|
||||
where
|
||||
|
|
@ -707,12 +692,12 @@ impl<D> StateDiffCollector<D> {
|
|||
D: DebugWithContext<A>,
|
||||
{
|
||||
let mut collector = StateDiffCollector {
|
||||
prev_state: analysis.bottom_value(body),
|
||||
prev_state: results.analysis.bottom_value(body),
|
||||
after: vec![],
|
||||
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
|
||||
};
|
||||
|
||||
visit_results(body, std::iter::once(block), analysis, results, &mut collector);
|
||||
visit_results(body, std::iter::once(block), results, &mut collector);
|
||||
collector
|
||||
}
|
||||
}
|
||||
|
|
@ -736,7 +721,7 @@ where
|
|||
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -749,7 +734,7 @@ where
|
|||
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -760,7 +745,7 @@ where
|
|||
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -773,7 +758,7 @@ where
|
|||
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
analysis: &mut A,
|
||||
analysis: &A,
|
||||
state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
|
|||
|
|
@ -58,8 +58,7 @@ mod visitor;
|
|||
pub use self::cursor::ResultsCursor;
|
||||
pub use self::direction::{Backward, Direction, Forward};
|
||||
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
||||
pub(crate) use self::results::AnalysisAndResults;
|
||||
pub use self::results::Results;
|
||||
pub use self::results::{EntryStates, Results};
|
||||
pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results};
|
||||
|
||||
/// Analysis domains are all bitsets of various kinds. This trait holds
|
||||
|
|
@ -136,7 +135,7 @@ pub trait Analysis<'tcx> {
|
|||
/// analyses should not implement this without also implementing
|
||||
/// `apply_primary_statement_effect`.
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -145,7 +144,7 @@ pub trait Analysis<'tcx> {
|
|||
|
||||
/// Updates the current dataflow state with the effect of evaluating a statement.
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -159,7 +158,7 @@ pub trait Analysis<'tcx> {
|
|||
/// analyses should not implement this without also implementing
|
||||
/// `apply_primary_terminator_effect`.
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -173,7 +172,7 @@ pub trait Analysis<'tcx> {
|
|||
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
|
||||
/// initialized here.
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
_state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -189,7 +188,7 @@ pub trait Analysis<'tcx> {
|
|||
/// This is separate from `apply_primary_terminator_effect` to properly track state across
|
||||
/// unwind edges.
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -211,7 +210,7 @@ pub trait Analysis<'tcx> {
|
|||
/// engine doesn't need to clone the exit state for a block unless
|
||||
/// `get_switch_int_data` is actually called.
|
||||
fn get_switch_int_data(
|
||||
&mut self,
|
||||
&self,
|
||||
_block: mir::BasicBlock,
|
||||
_discr: &mir::Operand<'tcx>,
|
||||
) -> Option<Self::SwitchIntData> {
|
||||
|
|
@ -220,7 +219,7 @@ pub trait Analysis<'tcx> {
|
|||
|
||||
/// See comments on `get_switch_int_data`.
|
||||
fn apply_switch_int_edge_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_data: &mut Self::SwitchIntData,
|
||||
_state: &mut Self::Domain,
|
||||
_value: SwitchTargetValue,
|
||||
|
|
@ -245,19 +244,21 @@ pub trait Analysis<'tcx> {
|
|||
/// Without a `pass_name` to differentiates them, only the results for the latest run will be
|
||||
/// saved.
|
||||
fn iterate_to_fixpoint<'mir>(
|
||||
mut self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
pass_name: Option<&'static str>,
|
||||
) -> AnalysisAndResults<'tcx, Self>
|
||||
) -> Results<'tcx, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
Self::Domain: DebugWithContext<Self>,
|
||||
{
|
||||
let mut results = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
|
||||
self.initialize_start_block(body, &mut results[mir::START_BLOCK]);
|
||||
let mut entry_states =
|
||||
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
|
||||
self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
|
||||
|
||||
if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) {
|
||||
if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
|
||||
{
|
||||
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
|
||||
}
|
||||
|
||||
|
|
@ -281,17 +282,17 @@ pub trait Analysis<'tcx> {
|
|||
let mut state = self.bottom_value(body);
|
||||
while let Some(bb) = dirty_queue.pop() {
|
||||
// Set the state to the entry state of the block. This is equivalent to `state =
|
||||
// results[bb].clone()`, but it saves an allocation, thus improving compile times.
|
||||
state.clone_from(&results[bb]);
|
||||
// entry_states[bb].clone()`, but it saves an allocation, thus improving compile times.
|
||||
state.clone_from(&entry_states[bb]);
|
||||
|
||||
Self::Direction::apply_effects_in_block(
|
||||
&mut self,
|
||||
&self,
|
||||
body,
|
||||
&mut state,
|
||||
bb,
|
||||
&body[bb],
|
||||
|target: BasicBlock, state: &Self::Domain| {
|
||||
let set_changed = results[target].join(state);
|
||||
let set_changed = entry_states[target].join(state);
|
||||
if set_changed {
|
||||
dirty_queue.insert(target);
|
||||
}
|
||||
|
|
@ -299,14 +300,16 @@ pub trait Analysis<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let results = Results { analysis: self, entry_states };
|
||||
|
||||
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
|
||||
let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name);
|
||||
let res = write_graphviz_results(tcx, body, &results, pass_name);
|
||||
if let Err(e) = res {
|
||||
error!("Failed to write graphviz dataflow results: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
AnalysisAndResults { analysis: self, results }
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,26 +5,26 @@ use rustc_middle::mir::{BasicBlock, Body};
|
|||
|
||||
use super::{Analysis, ResultsCursor};
|
||||
|
||||
/// The results of a dataflow analysis that has converged to fixpoint. It only holds the domain
|
||||
/// values at the entry of each basic block. Domain values in other parts of the block are
|
||||
/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
|
||||
pub type Results<D> = IndexVec<BasicBlock, D>;
|
||||
pub type EntryStates<D> = IndexVec<BasicBlock, D>;
|
||||
|
||||
/// Utility type used in a few places where it's convenient to bundle an analysis with its results.
|
||||
pub struct AnalysisAndResults<'tcx, A>
|
||||
/// The results of a dataflow analysis that has converged to fixpoint. It holds the domain values
|
||||
/// (states) at the entry of each basic block. Domain values in other parts of the block are
|
||||
/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). The
|
||||
/// analysis is also present because it's often needed alongside the entry states.
|
||||
pub struct Results<'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
pub analysis: A,
|
||||
pub results: Results<A::Domain>,
|
||||
pub entry_states: EntryStates<A::Domain>,
|
||||
}
|
||||
|
||||
impl<'tcx, A> AnalysisAndResults<'tcx, A>
|
||||
impl<'tcx, A> Results<'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
/// Creates a `ResultsCursor` that takes ownership of `self`.
|
||||
pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
|
||||
ResultsCursor::new_owning(body, self.analysis, self.results)
|
||||
ResultsCursor::new_owning(body, self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,15 +71,15 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
|||
///
|
||||
/// | Location | Before | After |
|
||||
/// |------------------------|-------------------|--------|
|
||||
/// | (on_entry) | {102} ||
|
||||
/// | (on_entry) | {102} | |
|
||||
/// | statement 0 | +0 | +1 |
|
||||
/// | statement 1 | +2 | +3 |
|
||||
/// | `Call` terminator | +4 | +5 |
|
||||
/// | (on unwind) | {102,0,1,2,3,4,5} ||
|
||||
/// | (on unwind) | {102,0,1,2,3,4,5} | |
|
||||
///
|
||||
/// The `102` in the block's entry set is derived from the basic block index and ensures that the
|
||||
/// expected state is unique across all basic blocks. Remember, it is generated by
|
||||
/// `mock_results`, not from actually running `MockAnalysis` to fixpoint.
|
||||
/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
|
||||
struct MockAnalysis<'tcx, D> {
|
||||
body: &'tcx mir::Body<'tcx>,
|
||||
dir: PhantomData<D>,
|
||||
|
|
@ -96,7 +96,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
|
|||
ret
|
||||
}
|
||||
|
||||
fn mock_results(&self) -> IndexVec<BasicBlock, DenseBitSet<usize>> {
|
||||
fn mock_entry_states(&self) -> IndexVec<BasicBlock, DenseBitSet<usize>> {
|
||||
let empty = self.bottom_value(self.body);
|
||||
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
}
|
||||
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -185,7 +185,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -195,7 +195,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
}
|
||||
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -205,7 +205,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -255,7 +255,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
|
|||
let body = analysis.body;
|
||||
|
||||
let mut cursor =
|
||||
AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body);
|
||||
Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
|
||||
|
||||
cursor.allow_unreachable();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ use super::{Analysis, Direction, Results};
|
|||
pub fn visit_results<'mir, 'tcx, A>(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||
analysis: &mut A,
|
||||
results: &Results<A::Domain>,
|
||||
results: &Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
let mut state = analysis.bottom_value(body);
|
||||
let mut state = results.analysis.bottom_value(body);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
|
||||
|
|
@ -23,22 +22,21 @@ pub fn visit_results<'mir, 'tcx, A>(
|
|||
assert!(reachable_blocks.contains(block));
|
||||
|
||||
let block_data = &body[block];
|
||||
state.clone_from(&results[block]);
|
||||
A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis);
|
||||
state.clone_from(&results.entry_states[block]);
|
||||
A::Direction::visit_results_in_block(&results.analysis, &mut state, block, block_data, vis);
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `visit_results`, but only for reachable blocks.
|
||||
pub fn visit_reachable_results<'mir, 'tcx, A>(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
analysis: &mut A,
|
||||
results: &Results<A::Domain>,
|
||||
results: &Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'tcx, A>,
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
let blocks = traversal::reachable(body).map(|(bb, _)| bb);
|
||||
visit_results(body, blocks, analysis, results, vis)
|
||||
visit_results(body, blocks, results, vis)
|
||||
}
|
||||
|
||||
/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
|
||||
|
|
@ -53,7 +51,7 @@ where
|
|||
/// Called after the "early" effect of the given statement is applied to `state`.
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_analysis: &mut A,
|
||||
_analysis: &A,
|
||||
_state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -63,7 +61,7 @@ where
|
|||
/// Called after the "primary" effect of the given statement is applied to `state`.
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
_analysis: &mut A,
|
||||
_analysis: &A,
|
||||
_state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -73,7 +71,7 @@ where
|
|||
/// Called after the "early" effect of the given terminator is applied to `state`.
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_analysis: &mut A,
|
||||
_analysis: &A,
|
||||
_state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -85,7 +83,7 @@ where
|
|||
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_analysis: &mut A,
|
||||
_analysis: &A,
|
||||
_state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use crate::{Analysis, GenKill};
|
|||
/// 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
|
||||
/// immovable coroutines.
|
||||
#[derive(Clone)]
|
||||
pub struct MaybeBorrowedLocals;
|
||||
|
||||
impl MaybeBorrowedLocals {
|
||||
|
|
@ -34,7 +33,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -43,7 +42,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -400,7 +400,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -429,7 +429,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -448,7 +448,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_switch_int_data(
|
||||
&mut self,
|
||||
&self,
|
||||
block: mir::BasicBlock,
|
||||
discr: &mir::Operand<'tcx>,
|
||||
) -> Option<Self::SwitchIntData> {
|
||||
|
|
@ -460,7 +460,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_switch_int_edge_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
data: &mut Self::SwitchIntData,
|
||||
state: &mut Self::Domain,
|
||||
value: SwitchTargetValue,
|
||||
|
|
@ -513,7 +513,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -527,7 +527,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -545,7 +545,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -564,7 +564,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_switch_int_data(
|
||||
&mut self,
|
||||
&self,
|
||||
block: mir::BasicBlock,
|
||||
discr: &mir::Operand<'tcx>,
|
||||
) -> Option<Self::SwitchIntData> {
|
||||
|
|
@ -580,7 +580,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_switch_int_edge_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
data: &mut Self::SwitchIntData,
|
||||
state: &mut Self::Domain,
|
||||
value: SwitchTargetValue,
|
||||
|
|
@ -627,7 +627,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
#[instrument(skip(self, state), level = "debug")]
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -652,7 +652,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
#[instrument(skip(self, state, terminator), level = "debug")]
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -674,7 +674,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
block: mir::BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -50,7 +50,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -60,7 +60,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -278,7 +278,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -294,7 +294,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -304,7 +304,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
|
|
@ -53,7 +54,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
_: Location,
|
||||
|
|
@ -97,7 +98,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
_: Location,
|
||||
|
|
@ -115,12 +116,12 @@ type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowed
|
|||
/// Dataflow analysis that determines whether each local requires storage at a
|
||||
/// given location; i.e. whether its storage can go away without being observed.
|
||||
pub struct MaybeRequiresStorage<'mir, 'tcx> {
|
||||
borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>,
|
||||
borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
|
||||
pub fn new(borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>) -> Self {
|
||||
MaybeRequiresStorage { borrowed_locals }
|
||||
MaybeRequiresStorage { borrowed_locals: RefCell::new(borrowed_locals) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -176,7 +177,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_: &Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -187,7 +188,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -242,7 +243,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'t>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'t Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -283,7 +284,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -294,9 +295,10 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
|
||||
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
|
||||
/// Kill locals that are fully moved and have not been borrowed.
|
||||
fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
|
||||
let body = self.borrowed_locals.body();
|
||||
let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
|
||||
fn check_for_move(&self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
|
||||
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
|
||||
let body = borrowed_locals.body();
|
||||
let mut visitor = MoveVisitor { state, borrowed_locals: &mut borrowed_locals };
|
||||
visitor.visit_location(body, loc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ pub use self::drop_flag_effects::{
|
|||
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
||||
};
|
||||
pub use self::framework::{
|
||||
Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
|
||||
ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results,
|
||||
Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
||||
Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results,
|
||||
visit_results,
|
||||
};
|
||||
use self::move_paths::MoveData;
|
||||
|
||||
|
|
|
|||
|
|
@ -721,27 +721,13 @@ fn locals_live_across_suspend_points<'tcx>(
|
|||
|
||||
// Calculate the MIR locals that have been previously borrowed (even if they are still active).
|
||||
let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
|
||||
let mut borrowed_locals_analysis1 = borrowed_locals.analysis;
|
||||
let mut borrowed_locals_analysis2 = borrowed_locals_analysis1.clone(); // trivial
|
||||
let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(
|
||||
body,
|
||||
&mut borrowed_locals_analysis1,
|
||||
&borrowed_locals.results,
|
||||
);
|
||||
let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(
|
||||
body,
|
||||
&mut borrowed_locals_analysis2,
|
||||
&borrowed_locals.results,
|
||||
);
|
||||
let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(body, &borrowed_locals);
|
||||
let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(body, &borrowed_locals);
|
||||
|
||||
// Calculate the MIR locals that we need to keep storage around for.
|
||||
let mut requires_storage =
|
||||
let requires_storage =
|
||||
MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None);
|
||||
let mut requires_storage_cursor = ResultsCursor::new_borrowing(
|
||||
body,
|
||||
&mut requires_storage.analysis,
|
||||
&requires_storage.results,
|
||||
);
|
||||
let mut requires_storage_cursor = ResultsCursor::new_borrowing(body, &requires_storage);
|
||||
|
||||
// Calculate the liveness of MIR locals ignoring borrows.
|
||||
let mut liveness =
|
||||
|
|
@ -813,8 +799,7 @@ fn locals_live_across_suspend_points<'tcx>(
|
|||
body,
|
||||
&saved_locals,
|
||||
always_live_locals.clone(),
|
||||
&mut requires_storage.analysis,
|
||||
&requires_storage.results,
|
||||
&requires_storage,
|
||||
);
|
||||
|
||||
LivenessInfo {
|
||||
|
|
@ -879,8 +864,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
|
|||
body: &'mir Body<'tcx>,
|
||||
saved_locals: &'mir CoroutineSavedLocals,
|
||||
always_live_locals: DenseBitSet<Local>,
|
||||
analysis: &mut MaybeRequiresStorage<'mir, 'tcx>,
|
||||
results: &Results<DenseBitSet<Local>>,
|
||||
results: &Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
||||
) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
|
||||
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
||||
|
||||
|
|
@ -900,7 +884,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
|
|||
eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()),
|
||||
};
|
||||
|
||||
visit_reachable_results(body, analysis, results, &mut visitor);
|
||||
visit_reachable_results(body, results, &mut visitor);
|
||||
|
||||
let local_conflicts = visitor.local_conflicts;
|
||||
|
||||
|
|
@ -943,7 +927,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
|||
{
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_analysis: &mut MaybeRequiresStorage<'a, 'tcx>,
|
||||
_analysis: &MaybeRequiresStorage<'a, 'tcx>,
|
||||
state: &DenseBitSet<Local>,
|
||||
_statement: &Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -953,7 +937,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
|||
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_analysis: &mut MaybeRequiresStorage<'a, 'tcx>,
|
||||
_analysis: &MaybeRequiresStorage<'a, 'tcx>,
|
||||
state: &DenseBitSet<Local>,
|
||||
_terminator: &Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
//! Currently, this pass only propagates scalar values.
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Formatter;
|
||||
|
||||
use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx};
|
||||
|
|
@ -60,14 +61,12 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
|
|||
let map = Map::new(tcx, body, place_limit);
|
||||
|
||||
// Perform the actual dataflow analysis.
|
||||
let mut const_ = debug_span!("analyze")
|
||||
let const_ = debug_span!("analyze")
|
||||
.in_scope(|| ConstAnalysis::new(tcx, body, map).iterate_to_fixpoint(tcx, body, None));
|
||||
|
||||
// Collect results and patch the body afterwards.
|
||||
let mut visitor = Collector::new(tcx, &body.local_decls);
|
||||
debug_span!("collect").in_scope(|| {
|
||||
visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor)
|
||||
});
|
||||
debug_span!("collect").in_scope(|| visit_reachable_results(body, &const_, &mut visitor));
|
||||
let mut patch = visitor.patch;
|
||||
debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
|
||||
}
|
||||
|
|
@ -85,7 +84,7 @@ struct ConstAnalysis<'a, 'tcx> {
|
|||
map: Map<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &'a LocalDecls<'tcx>,
|
||||
ecx: InterpCx<'tcx, DummyMachine>,
|
||||
ecx: RefCell<InterpCx<'tcx, DummyMachine>>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +110,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &Statement<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -122,7 +121,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -135,7 +134,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
@ -153,7 +152,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
map,
|
||||
tcx,
|
||||
local_decls: &body.local_decls,
|
||||
ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
|
||||
ecx: RefCell::new(InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine)),
|
||||
typing_env,
|
||||
}
|
||||
}
|
||||
|
|
@ -410,6 +409,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(op) => self
|
||||
.ecx
|
||||
.borrow()
|
||||
.int_to_int_or_float(&op, layout)
|
||||
.discard_err()
|
||||
.map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
|
||||
|
|
@ -424,6 +424,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(op) => self
|
||||
.ecx
|
||||
.borrow()
|
||||
.float_to_float_or_int(&op, layout)
|
||||
.discard_err()
|
||||
.map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
|
||||
|
|
@ -454,6 +455,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(value) => self
|
||||
.ecx
|
||||
.borrow()
|
||||
.unary_op(*op, &value)
|
||||
.discard_err()
|
||||
.map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
|
||||
|
|
@ -468,6 +470,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
let val = match null_op {
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.ecx
|
||||
.borrow()
|
||||
.tcx
|
||||
.offset_of_subfield(self.typing_env, layout, fields.iter())
|
||||
.bytes(),
|
||||
|
|
@ -556,8 +559,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
Operand::Constant(box constant) => {
|
||||
if let Some(constant) =
|
||||
self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
|
||||
if let Some(constant) = self
|
||||
.ecx
|
||||
.borrow()
|
||||
.eval_mir_constant(&constant.const_, constant.span, None)
|
||||
.discard_err()
|
||||
{
|
||||
self.assign_constant(state, place, constant, &[]);
|
||||
}
|
||||
|
|
@ -587,7 +593,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
}
|
||||
operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() {
|
||||
operand = if let Some(operand) =
|
||||
self.ecx.borrow().project(&operand, proj_elem).discard_err()
|
||||
{
|
||||
operand
|
||||
} else {
|
||||
return;
|
||||
|
|
@ -598,17 +606,22 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
place,
|
||||
operand,
|
||||
&mut |elem, op| match elem {
|
||||
TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(),
|
||||
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
|
||||
TrackElem::Field(idx) => self.ecx.borrow().project_field(op, idx).discard_err(),
|
||||
TrackElem::Variant(idx) => {
|
||||
self.ecx.borrow().project_downcast(op, idx).discard_err()
|
||||
}
|
||||
TrackElem::Discriminant => {
|
||||
let variant = self.ecx.read_discriminant(op).discard_err()?;
|
||||
let discr_value =
|
||||
self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?;
|
||||
let variant = self.ecx.borrow().read_discriminant(op).discard_err()?;
|
||||
let discr_value = self
|
||||
.ecx
|
||||
.borrow()
|
||||
.discriminant_for_variant(op.layout.ty, variant)
|
||||
.discard_err()?;
|
||||
Some(discr_value.into())
|
||||
}
|
||||
TrackElem::DerefLen => {
|
||||
let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
|
||||
let len_usize = op.len(&self.ecx).discard_err()?;
|
||||
let op: OpTy<'_> = self.ecx.borrow().deref_pointer(op).discard_err()?.into();
|
||||
let len_usize = op.len(&self.ecx.borrow()).discard_err()?;
|
||||
let layout = self
|
||||
.tcx
|
||||
.layout_of(self.typing_env.as_query_input(self.tcx.types.usize))
|
||||
|
|
@ -617,7 +630,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
}
|
||||
},
|
||||
&mut |place, op| {
|
||||
if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err()
|
||||
if let Some(imm) = self.ecx.borrow().read_immediate_raw(op).discard_err()
|
||||
&& let Some(imm) = imm.right()
|
||||
{
|
||||
let elem = self.wrap_immediate(*imm);
|
||||
|
|
@ -641,7 +654,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
(FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
|
||||
// Both sides are known, do the actual computation.
|
||||
(FlatSet::Elem(left), FlatSet::Elem(right)) => {
|
||||
match self.ecx.binary_op(op, &left, &right).discard_err() {
|
||||
match self.ecx.borrow().binary_op(op, &left, &right).discard_err() {
|
||||
// Ideally this would return an Immediate, since it's sometimes
|
||||
// a pair and sometimes not. But as a hack we always return a pair
|
||||
// and just make the 2nd component `Bottom` when it does not exist.
|
||||
|
|
@ -714,8 +727,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
let enum_ty_layout = self.tcx.layout_of(self.typing_env.as_query_input(enum_ty)).ok()?;
|
||||
let discr_value =
|
||||
self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?;
|
||||
let discr_value = self
|
||||
.ecx
|
||||
.borrow()
|
||||
.discriminant_for_variant(enum_ty_layout.ty, variant_index)
|
||||
.discard_err()?;
|
||||
Some(discr_value.to_scalar())
|
||||
}
|
||||
|
||||
|
|
@ -946,7 +962,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
|
|||
#[instrument(level = "trace", skip(self, analysis, statement))]
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
analysis: &mut ConstAnalysis<'_, 'tcx>,
|
||||
analysis: &ConstAnalysis<'_, 'tcx>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -956,7 +972,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
|
|||
OperandCollector {
|
||||
state,
|
||||
visitor: self,
|
||||
ecx: &mut analysis.ecx,
|
||||
ecx: &mut analysis.ecx.borrow_mut(),
|
||||
map: &analysis.map,
|
||||
}
|
||||
.visit_rvalue(rvalue, location);
|
||||
|
|
@ -968,7 +984,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
|
|||
#[instrument(level = "trace", skip(self, analysis, statement))]
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
analysis: &mut ConstAnalysis<'_, 'tcx>,
|
||||
analysis: &ConstAnalysis<'_, 'tcx>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -978,9 +994,12 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
|
|||
// Don't overwrite the assignment if it already uses a constant (to keep the span).
|
||||
}
|
||||
StatementKind::Assign(box (place, _)) => {
|
||||
if let Some(value) =
|
||||
self.try_make_constant(&mut analysis.ecx, place, state, &analysis.map)
|
||||
{
|
||||
if let Some(value) = self.try_make_constant(
|
||||
&mut analysis.ecx.borrow_mut(),
|
||||
place,
|
||||
state,
|
||||
&analysis.map,
|
||||
) {
|
||||
self.patch.assignments.insert(location, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -990,13 +1009,18 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
|
|||
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
analysis: &mut ConstAnalysis<'_, 'tcx>,
|
||||
analysis: &ConstAnalysis<'_, 'tcx>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
terminator: &Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map }
|
||||
.visit_terminator(terminator, location);
|
||||
OperandCollector {
|
||||
state,
|
||||
visitor: self,
|
||||
ecx: &mut analysis.ecx.borrow_mut(),
|
||||
map: &analysis.map,
|
||||
}
|
||||
.visit_terminator(terminator, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::{Analysis, Results};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
pub(super) struct DestinationPropagation;
|
||||
|
|
@ -173,7 +173,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
|
|||
|
||||
let points = DenseLocationMap::new(body);
|
||||
let mut relevant = RelevantLocals::compute(&candidates, body.local_decls.len());
|
||||
let mut live = save_as_intervals(&points, body, &relevant, live.results);
|
||||
let mut live = save_as_intervals(&points, body, &relevant, live.entry_states);
|
||||
|
||||
dest_prop_mir_dump(tcx, body, &points, &live, &relevant);
|
||||
|
||||
|
|
@ -506,7 +506,7 @@ fn save_as_intervals<'tcx>(
|
|||
elements: &DenseLocationMap,
|
||||
body: &Body<'tcx>,
|
||||
relevant: &RelevantLocals,
|
||||
results: Results<DenseBitSet<Local>>,
|
||||
entry_states: EntryStates<DenseBitSet<Local>>,
|
||||
) -> SparseIntervalMatrix<RelevantLocal, TwoStepIndex> {
|
||||
let mut values = SparseIntervalMatrix::new(2 * elements.num_points());
|
||||
let mut state = MaybeLiveLocals.bottom_value(body);
|
||||
|
|
@ -529,7 +529,7 @@ fn save_as_intervals<'tcx>(
|
|||
continue;
|
||||
}
|
||||
|
||||
state.clone_from(&results[block]);
|
||||
state.clone_from(&entry_states[block]);
|
||||
|
||||
let block_data = &body.basic_blocks[block];
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
|
|
|
|||
|
|
@ -1160,7 +1160,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
trans: &mut Self::Domain,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -1169,7 +1169,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
&self,
|
||||
trans: &mut Self::Domain,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -1179,7 +1179,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
&self,
|
||||
_trans: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue