Take MIR dataflow analyses by mutable reference.

This commit is contained in:
Jason Newcomb 2023-02-20 17:28:03 -05:00
parent fdd030127c
commit eaddc37075
19 changed files with 491 additions and 288 deletions

View file

@ -10,8 +10,12 @@ use rustc_middle::mir::visit::{MutVisitor, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
use rustc_mir_dataflow::value_analysis::{
Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
};
use rustc_mir_dataflow::{
lattice::FlatSet, Analysis, Results, ResultsVisitor, SwitchIntEdgeEffects,
};
use rustc_span::DUMMY_SP;
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
@ -52,11 +56,11 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
// Perform the actual dataflow analysis.
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());
// 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!("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>,
map: &'map Map,
/// 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
@ -400,9 +403,9 @@ struct CollectAndPatch<'tcx, 'map> {
assignments: FxHashMap<Location, ScalarTy<'tcx>>,
}
impl<'tcx, 'map> CollectAndPatch<'tcx, 'map> {
fn new(tcx: TyCtxt<'tcx>, map: &'map Map) -> Self {
Self { tcx, map, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
impl<'tcx> CollectAndPatch<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Self {
Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
}
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>>>;
fn visit_statement_before_primary_effect(
&mut self,
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
state: &Self::FlowState,
statement: &'mir Statement<'tcx>,
location: Location,
) {
match &statement.kind {
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(
&mut self,
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
state: &Self::FlowState,
statement: &'mir Statement<'tcx>,
location: Location,
@ -441,30 +450,34 @@ impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(_)))) => {
// 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) {
FlatSet::Top => (),
FlatSet::Elem(value) => {
self.assignments.insert(location, value);
StatementKind::Assign(box (place, _)) => {
match state.get(place.as_ref(), &results.analysis.0.map) {
FlatSet::Top => (),
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(
&mut self,
results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
state: &Self::FlowState,
terminator: &'mir Terminator<'tcx>,
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> {
self.tcx
}
@ -496,14 +509,15 @@ impl<'tcx, 'map> MutVisitor<'tcx> for CollectAndPatch<'tcx, 'map> {
struct OperandCollector<'tcx, 'map, 'a> {
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> {
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
match operand {
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::Elem(value) => {
self.visitor.before_effect.insert((location, *place), value);

View file

@ -597,16 +597,15 @@ fn locals_live_across_suspend_points<'tcx>(
let borrowed_locals_results =
MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
let mut borrowed_locals_cursor =
rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body_ref);
// Calculate the MIR locals that we actually need to keep storage around
// for.
let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
.into_engine(tcx, body_ref)
.iterate_to_fixpoint();
let mut requires_storage_cursor =
rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
let mut requires_storage_results =
MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
.into_engine(tcx, body_ref)
.iterate_to_fixpoint();
let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body_ref);
// Calculate the liveness of MIR locals ignoring borrows.
let mut liveness = MaybeLiveLocals
@ -747,7 +746,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
body: &'mir Body<'tcx>,
saved_locals: &GeneratorSavedLocals,
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> {
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
@ -802,13 +801,14 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
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, '_>
{
type FlowState = BitSet<Local>;
fn visit_statement_before_primary_effect(
&mut self,
_results: &R,
state: &Self::FlowState,
_statement: &'mir Statement<'tcx>,
loc: Location,
@ -818,6 +818,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
fn visit_terminator_before_primary_effect(
&mut self,
_results: &R,
state: &Self::FlowState,
_terminator: &'mir Terminator<'tcx>,
loc: Location,