Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More rustc_mir_dataflow cleanups #118638

Merged
merged 4 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 70 additions & 83 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,101 +11,88 @@ use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::ResultsVisitable;
use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results};
use std::fmt;

use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};

/// A tuple with named fields that can hold either the results or the transient state of the
/// dataflow analyses used by the borrow checker.
#[derive(Debug)]
pub struct BorrowckAnalyses<B, U, E> {
pub borrows: B,
pub uninits: U,
pub ever_inits: E,
}

/// The results of the dataflow analyses used by the borrow checker.
pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
Results<'tcx, Borrows<'mir, 'tcx>>,
Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
>;
pub struct BorrowckResults<'mir, 'tcx> {
pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>,
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
}

/// The transient state of the dataflow analyses used by the borrow checker.
pub type BorrowckFlowState<'mir, 'tcx> =
<BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;

macro_rules! impl_visitable {
( $(
$T:ident { $( $field:ident : $A:ident ),* $(,)? }
)* ) => { $(
impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
where
$( $A: Analysis<'tcx, Direction = D>, )*
{
type Direction = D;
type FlowState = $T<$( $A::Domain ),*>;
#[derive(Debug)]
pub struct BorrowckFlowState<'mir, 'tcx> {
pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
}

fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
$T {
$( $field: self.$field.analysis.bottom_value(body) ),*
}
}
impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> {
// All three analyses are forward, but we have to use just one here.
type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
type FlowState = BorrowckFlowState<'mir, 'tcx>;

fn reset_to_block_entry(
&self,
state: &mut Self::FlowState,
block: BasicBlock,
) {
$( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
}
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
BorrowckFlowState {
borrows: self.borrows.analysis.bottom_value(body),
uninits: self.uninits.analysis.bottom_value(body),
ever_inits: self.ever_inits.analysis.bottom_value(body),
}
}

fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_before_statement_effect(&mut state.$field, stmt, loc); )*
}
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
state.borrows.clone_from(&self.borrows.entry_set_for_block(block));
state.uninits.clone_from(&self.uninits.entry_set_for_block(block));
state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block));
}

fn reconstruct_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_statement_effect(&mut state.$field, stmt, loc); )*
}
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
}

fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_before_terminator_effect(&mut state.$field, term, loc); )*
}
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
}

fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_terminator_effect(&mut state.$field, term, loc); )*
}
}
)* }
}
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
}

impl_visitable! {
BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
}
}

rustc_index::newtype_index! {
Expand Down Expand Up @@ -598,7 +585,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {

fn before_terminator_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
Expand All @@ -625,7 +612,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {

fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir_dataflow/src/framework/direction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl Direction for Backward {
{
results.reset_to_block_entry(state, block);

vis.visit_block_end(results, state, block_data, block);
vis.visit_block_end(state);

// Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
Expand All @@ -214,7 +214,7 @@ impl Direction for Backward {
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}

vis.visit_block_start(results, state, block_data, block);
vis.visit_block_start(state);
}

fn join_state_into_successors_of<'tcx, A>(
Expand Down Expand Up @@ -449,7 +449,7 @@ impl Direction for Forward {
{
results.reset_to_block_entry(state, block);

vis.visit_block_start(results, state, block_data, block);
vis.visit_block_start(state);

for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index };
Expand All @@ -466,7 +466,7 @@ impl Direction for Forward {
results.reconstruct_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);

vis.visit_block_end(results, state, block_data, block);
vis.visit_block_end(state);
}

fn join_state_into_successors_of<'tcx, A>(
Expand Down
16 changes: 2 additions & 14 deletions compiler/rustc_mir_dataflow/src/framework/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,25 +545,13 @@ where
{
type FlowState = A::Domain;

fn visit_block_start(
&mut self,
_results: &mut Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
fn visit_block_start(&mut self, state: &Self::FlowState) {
if A::Direction::IS_FORWARD {
self.prev_state.clone_from(state);
}
}

fn visit_block_end(
&mut self,
_results: &mut Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
fn visit_block_end(&mut self, state: &Self::FlowState) {
if A::Direction::IS_BACKWARD {
self.prev_state.clone_from(state);
}
Expand Down
21 changes: 12 additions & 9 deletions compiler/rustc_mir_dataflow/src/framework/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,26 +248,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {

/// A gen/kill dataflow problem.
///
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer
/// functions for each statement in this way, the transfer function for an entire basic block can
/// be computed efficiently.
/// Each method in this trait has a corresponding one in `Analysis`. However, the first two methods
/// here only allow modification of the dataflow state via "gen" and "kill" operations. By defining
/// transfer functions for each statement in this way, the transfer function for an entire basic
/// block can be computed efficiently. The remaining methods match up with `Analysis` exactly.
///
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`.
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis` via a blanket
/// impl below.
pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
type Idx: Idx;

fn domain_size(&self, body: &mir::Body<'tcx>) -> usize;

/// See `Analysis::apply_statement_effect`.
/// See `Analysis::apply_statement_effect`. Note how the second arg differs.
fn statement_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
statement: &mir::Statement<'tcx>,
location: Location,
);

/// See `Analysis::apply_before_statement_effect`.
/// See `Analysis::apply_before_statement_effect`. Note how the second arg
/// differs.
fn before_statement_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
Expand All @@ -287,7 +289,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_before_terminator_effect`.
fn before_terminator_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
Expand All @@ -298,7 +300,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_call_return_effect`.
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
);
Expand All @@ -313,6 +315,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
}
}

// Blanket impl: any impl of `GenKillAnalysis` automatically impls `Analysis`.
impl<'tcx, A> Analysis<'tcx> for A
where
A: GenKillAnalysis<'tcx>,
Expand Down
22 changes: 4 additions & 18 deletions compiler/rustc_mir_dataflow/src/framework/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ pub fn visit_results<'mir, 'tcx, F, R>(
pub trait ResultsVisitor<'mir, 'tcx, R> {
type FlowState;

fn visit_block_start(
&mut self,
_results: &mut R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
}
fn visit_block_start(&mut self, _state: &Self::FlowState) {}

/// Called with the `before_statement_effect` of the given statement applied to `state` but not
/// its `statement_effect`.
Expand Down Expand Up @@ -86,20 +79,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
) {
}

fn visit_block_end(
&mut self,
_results: &mut R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
}
fn visit_block_end(&mut self, _state: &Self::FlowState) {}
}

/// Things that can be visited by a `ResultsVisitor`.
///
/// This trait exists so that we can visit the results of multiple dataflow analyses simultaneously.
/// DO NOT IMPLEMENT MANUALLY. Instead, use the `impl_visitable` macro below.
/// This trait exists so that we can visit the results of one or more dataflow analyses
/// simultaneously.
pub trait ResultsVisitable<'tcx> {
type Direction: Direction;
type FlowState;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {

fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir_dataflow/src/impls/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {

fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down Expand Up @@ -499,7 +499,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {

fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down Expand Up @@ -617,7 +617,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {

fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down Expand Up @@ -712,7 +712,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {

fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
Expand Down
Loading
Loading