summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_dataflow/src/framework
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_mir_dataflow/src/framework
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_dataflow/src/framework')
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs173
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs41
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/fmt.rs32
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs94
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs111
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs7
7 files changed, 251 insertions, 213 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 804b44a6b..8a9e37c5a 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -1,11 +1,10 @@
-use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets, UnwindAction};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::{
+ self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, UnwindAction,
+};
use std::ops::RangeInclusive;
use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{
- Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget,
-};
+use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
pub trait Direction {
const IS_FORWARD: bool;
@@ -24,15 +23,17 @@ pub trait Direction {
) where
A: Analysis<'tcx>;
- fn apply_effects_in_block<'tcx, A>(
+ fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
- block_data: &mir::BasicBlockData<'tcx>,
- ) where
+ block_data: &'mir mir::BasicBlockData<'tcx>,
+ statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
+ ) -> TerminatorEdges<'mir, 'tcx>
+ where
A: Analysis<'tcx>;
- fn gen_kill_effects_in_block<'tcx, A>(
+ fn gen_kill_statement_effects_in_block<'tcx, A>(
analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -51,10 +52,10 @@ pub trait Direction {
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
- tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
- block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
+ block: BasicBlock,
+ edges: TerminatorEdges<'_, 'tcx>,
propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>;
@@ -66,27 +67,33 @@ pub struct Backward;
impl Direction for Backward {
const IS_FORWARD: bool = false;
- fn apply_effects_in_block<'tcx, A>(
+ fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
- block_data: &mir::BasicBlockData<'tcx>,
- ) where
+ block_data: &'mir mir::BasicBlockData<'tcx>,
+ statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
+ ) -> TerminatorEdges<'mir, 'tcx>
+ where
A: Analysis<'tcx>,
{
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
- analysis.apply_terminator_effect(state, terminator, location);
-
- for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
- let location = Location { block, statement_index };
- analysis.apply_before_statement_effect(state, statement, location);
- analysis.apply_statement_effect(state, statement, location);
+ let edges = analysis.apply_terminator_effect(state, terminator, location);
+ if let Some(statement_effect) = statement_effect {
+ statement_effect(block, state)
+ } else {
+ for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
+ let location = Location { block, statement_index };
+ analysis.apply_before_statement_effect(state, statement, location);
+ analysis.apply_statement_effect(state, statement, location);
+ }
}
+ edges
}
- fn gen_kill_effects_in_block<'tcx, A>(
+ fn gen_kill_statement_effects_in_block<'tcx, A>(
analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -94,11 +101,6 @@ impl Direction for Backward {
) where
A: GenKillAnalysis<'tcx>,
{
- let terminator = block_data.terminator();
- let location = Location { block, statement_index: block_data.statements.len() };
- analysis.before_terminator_effect(trans, terminator, location);
- analysis.terminator_effect(trans, terminator, location);
-
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index };
analysis.before_statement_effect(trans, statement, location);
@@ -217,10 +219,10 @@ impl Direction for Backward {
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
- _tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
- (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
+ bb: BasicBlock,
+ _edges: TerminatorEdges<'_, 'tcx>,
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
@@ -254,7 +256,11 @@ impl Direction for Backward {
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => {
let mut tmp = exit_state.clone();
- analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg);
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ resume,
+ CallReturnPlaces::Yield(resume_arg),
+ );
propagate(pred, &tmp);
}
@@ -318,27 +324,33 @@ pub struct Forward;
impl Direction for Forward {
const IS_FORWARD: bool = true;
- fn apply_effects_in_block<'tcx, A>(
+ fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
- block_data: &mir::BasicBlockData<'tcx>,
- ) where
+ block_data: &'mir mir::BasicBlockData<'tcx>,
+ statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>,
+ ) -> TerminatorEdges<'mir, 'tcx>
+ where
A: Analysis<'tcx>,
{
- for (statement_index, statement) in block_data.statements.iter().enumerate() {
- let location = Location { block, statement_index };
- analysis.apply_before_statement_effect(state, statement, location);
- analysis.apply_statement_effect(state, statement, location);
+ if let Some(statement_effect) = statement_effect {
+ statement_effect(block, state)
+ } else {
+ for (statement_index, statement) in block_data.statements.iter().enumerate() {
+ let location = Location { block, statement_index };
+ analysis.apply_before_statement_effect(state, statement, location);
+ analysis.apply_statement_effect(state, statement, location);
+ }
}
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
- analysis.apply_terminator_effect(state, terminator, location);
+ analysis.apply_terminator_effect(state, terminator, location)
}
- fn gen_kill_effects_in_block<'tcx, A>(
+ fn gen_kill_statement_effects_in_block<'tcx, A>(
analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -351,11 +363,6 @@ impl Direction for Forward {
analysis.before_statement_effect(trans, statement, location);
analysis.statement_effect(trans, statement, location);
}
-
- let terminator = block_data.terminator();
- let location = Location { block, statement_index: block_data.statements.len() };
- analysis.before_terminator_effect(trans, terminator, location);
- analysis.terminator_effect(trans, terminator, location);
}
fn apply_effects_in_range<'tcx, A>(
@@ -464,86 +471,32 @@ impl Direction for Forward {
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
- _tcx: TyCtxt<'tcx>,
_body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
- (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
+ bb: BasicBlock,
+ edges: TerminatorEdges<'_, 'tcx>,
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
{
- use mir::TerminatorKind::*;
- match bb_data.terminator().kind {
- Return | Resume | Terminate | GeneratorDrop | Unreachable => {}
-
- Goto { target } => propagate(target, exit_state),
-
- Assert { target, unwind, expected: _, msg: _, cond: _ }
- | Drop { target, unwind, place: _, replace: _ }
- | FalseUnwind { real_target: target, unwind } => {
- if let UnwindAction::Cleanup(unwind) = unwind {
- propagate(unwind, exit_state);
- }
-
+ match edges {
+ TerminatorEdges::None => {}
+ TerminatorEdges::Single(target) => propagate(target, exit_state),
+ TerminatorEdges::Double(target, unwind) => {
propagate(target, exit_state);
+ propagate(unwind, exit_state);
}
-
- FalseEdge { real_target, imaginary_target } => {
- propagate(real_target, exit_state);
- propagate(imaginary_target, exit_state);
- }
-
- Yield { resume: target, drop, resume_arg, value: _ } => {
- if let Some(drop) = drop {
- propagate(drop, exit_state);
- }
-
- analysis.apply_yield_resume_effect(exit_state, target, resume_arg);
- propagate(target, exit_state);
- }
-
- Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => {
- if let UnwindAction::Cleanup(unwind) = unwind {
- propagate(unwind, exit_state);
- }
-
- if let Some(target) = target {
- // N.B.: This must be done *last*, otherwise the unwind path will see the call
- // return effect.
- analysis.apply_call_return_effect(
- exit_state,
- bb,
- CallReturnPlaces::Call(destination),
- );
- propagate(target, exit_state);
- }
- }
-
- InlineAsm {
- template: _,
- ref operands,
- options: _,
- line_spans: _,
- destination,
- unwind,
- } => {
+ TerminatorEdges::AssignOnReturn { return_, unwind, place } => {
+ // This must be done *first*, otherwise the unwind path will see the assignments.
if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state);
}
-
- if let Some(target) = destination {
- // N.B.: This must be done *last*, otherwise the unwind path will see the call
- // return effect.
- analysis.apply_call_return_effect(
- exit_state,
- bb,
- CallReturnPlaces::InlineAsm(operands),
- );
- propagate(target, exit_state);
+ if let Some(return_) = return_ {
+ analysis.apply_call_return_effect(exit_state, bb, place);
+ propagate(return_, exit_state);
}
}
-
- SwitchInt { ref targets, ref discr } => {
+ TerminatorEdges::SwitchInt { targets, discr } => {
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
exit_state,
targets,
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index c755d7588..a29962d77 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -144,7 +144,7 @@ where
// gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade
// performance in practice. I've tried a few ways to avoid this, but they have downsides. See
// the message for the commit that added this FIXME for more information.
- apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
+ apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
}
impl<'a, 'tcx, A, D, T> Engine<'a, 'tcx, A>
@@ -165,12 +165,17 @@ where
// Otherwise, compute and store the cumulative transfer function for each block.
- let identity = GenKillSet::identity(analysis.bottom_value(body).domain_size());
+ let identity = GenKillSet::identity(analysis.domain_size(body));
let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks);
for (block, block_data) in body.basic_blocks.iter_enumerated() {
let trans = &mut trans_for_block[block];
- A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data);
+ A::Direction::gen_kill_statement_effects_in_block(
+ &mut analysis,
+ trans,
+ block,
+ block_data,
+ );
}
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
@@ -199,17 +204,18 @@ where
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
analysis: A,
- apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
+ apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
) -> Self {
- let bottom_value = analysis.bottom_value(body);
- let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), &body.basic_blocks);
+ let mut entry_sets =
+ IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
- if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != bottom_value {
+ if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body)
+ {
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
}
- Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_trans_for_block }
+ Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_statement_trans_for_block }
}
/// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
@@ -231,7 +237,7 @@ where
body,
mut entry_sets,
tcx,
- apply_trans_for_block,
+ apply_statement_trans_for_block,
pass_name,
..
} = self;
@@ -263,19 +269,20 @@ where
state.clone_from(&entry_sets[bb]);
// Apply the block transfer function, using the cached one if it exists.
- match &apply_trans_for_block {
- Some(apply) => apply(bb, &mut state),
- None => {
- A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data)
- }
- }
+ let edges = A::Direction::apply_effects_in_block(
+ &mut analysis,
+ &mut state,
+ bb,
+ bb_data,
+ apply_statement_trans_for_block.as_deref(),
+ );
A::Direction::join_state_into_successors_of(
&mut analysis,
- tcx,
body,
&mut state,
- (bb, bb_data),
+ bb,
+ edges,
|target: BasicBlock, state: &A::Domain| {
let set_changed = entry_sets[target].join(state);
if set_changed {
diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
index 6a256fae3..e3a66bd95 100644
--- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -1,6 +1,7 @@
//! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow
//! analysis.
+use super::lattice::MaybeReachable;
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
use rustc_index::Idx;
use std::fmt;
@@ -124,6 +125,37 @@ where
}
}
+impl<S, C> DebugWithContext<C> for MaybeReachable<S>
+where
+ S: DebugWithContext<C>,
+{
+ fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ MaybeReachable::Unreachable => {
+ write!(f, "unreachable")
+ }
+ MaybeReachable::Reachable(set) => set.fmt_with(ctxt, f),
+ }
+ }
+
+ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match (self, old) {
+ (MaybeReachable::Unreachable, MaybeReachable::Unreachable) => Ok(()),
+ (MaybeReachable::Unreachable, MaybeReachable::Reachable(set)) => {
+ write!(f, "\u{001f}+")?;
+ set.fmt_with(ctxt, f)
+ }
+ (MaybeReachable::Reachable(set), MaybeReachable::Unreachable) => {
+ write!(f, "\u{001f}-")?;
+ set.fmt_with(ctxt, f)
+ }
+ (MaybeReachable::Reachable(this), MaybeReachable::Reachable(old)) => {
+ this.fmt_diff_with(old, ctxt, f)
+ }
+ }
+ }
+}
+
fn fmt_diff<T, C>(
inserted: &HybridBitSet<T>,
removed: &HybridBitSet<T>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index e331533c3..1421d9b45 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -269,7 +269,11 @@ where
self.write_row(w, "", "(on yield resume)", |this, w, fmt| {
let state_on_generator_drop = this.results.get().clone();
this.results.apply_custom_effect(|analysis, state| {
- analysis.apply_yield_resume_effect(state, resume, resume_arg);
+ analysis.apply_call_return_effect(
+ state,
+ resume,
+ CallReturnPlaces::Yield(resume_arg),
+ );
});
write!(
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 3952f44ad..3b89598d2 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -187,10 +187,6 @@ impl<T: Idx> MeetSemiLattice for ChunkedBitSet<T> {
pub struct Dual<T>(pub T);
impl<T: Idx> BitSetExt<T> for Dual<BitSet<T>> {
- fn domain_size(&self) -> usize {
- self.0.domain_size()
- }
-
fn contains(&self, elem: T) -> bool {
self.0.contains(elem)
}
@@ -276,3 +272,93 @@ impl<T> HasBottom for FlatSet<T> {
impl<T> HasTop for FlatSet<T> {
const TOP: Self = Self::Top;
}
+
+/// Extend a lattice with a bottom value to represent an unreachable execution.
+///
+/// The only useful action on an unreachable state is joining it with a reachable one to make it
+/// reachable. All other actions, gen/kill for instance, are no-ops.
+#[derive(PartialEq, Eq, Debug)]
+pub enum MaybeReachable<T> {
+ Unreachable,
+ Reachable(T),
+}
+
+impl<T> MaybeReachable<T> {
+ pub fn is_reachable(&self) -> bool {
+ matches!(self, MaybeReachable::Reachable(_))
+ }
+}
+
+impl<T> HasBottom for MaybeReachable<T> {
+ const BOTTOM: Self = MaybeReachable::Unreachable;
+}
+
+impl<T: HasTop> HasTop for MaybeReachable<T> {
+ const TOP: Self = MaybeReachable::Reachable(T::TOP);
+}
+
+impl<S> MaybeReachable<S> {
+ /// Return whether the current state contains the given element. If the state is unreachable,
+ /// it does no contain anything.
+ pub fn contains<T>(&self, elem: T) -> bool
+ where
+ S: BitSetExt<T>,
+ {
+ match self {
+ MaybeReachable::Unreachable => false,
+ MaybeReachable::Reachable(set) => set.contains(elem),
+ }
+ }
+}
+
+impl<T, S: BitSetExt<T>> BitSetExt<T> for MaybeReachable<S> {
+ fn contains(&self, elem: T) -> bool {
+ self.contains(elem)
+ }
+
+ fn union(&mut self, other: &HybridBitSet<T>) {
+ match self {
+ MaybeReachable::Unreachable => {}
+ MaybeReachable::Reachable(set) => set.union(other),
+ }
+ }
+
+ fn subtract(&mut self, other: &HybridBitSet<T>) {
+ match self {
+ MaybeReachable::Unreachable => {}
+ MaybeReachable::Reachable(set) => set.subtract(other),
+ }
+ }
+}
+
+impl<V: Clone> Clone for MaybeReachable<V> {
+ fn clone(&self) -> Self {
+ match self {
+ MaybeReachable::Reachable(x) => MaybeReachable::Reachable(x.clone()),
+ MaybeReachable::Unreachable => MaybeReachable::Unreachable,
+ }
+ }
+
+ fn clone_from(&mut self, source: &Self) {
+ match (&mut *self, source) {
+ (MaybeReachable::Reachable(x), MaybeReachable::Reachable(y)) => {
+ x.clone_from(&y);
+ }
+ _ => *self = source.clone(),
+ }
+ }
+}
+
+impl<T: JoinSemiLattice + Clone> JoinSemiLattice for MaybeReachable<T> {
+ fn join(&mut self, other: &Self) -> bool {
+ // Unreachable acts as a bottom.
+ match (&mut *self, &other) {
+ (_, MaybeReachable::Unreachable) => false,
+ (MaybeReachable::Unreachable, _) => {
+ *self = other.clone();
+ true
+ }
+ (MaybeReachable::Reachable(this), MaybeReachable::Reachable(other)) => this.join(other),
+ }
+ }
+}
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 58df9b9a7..ce30c642f 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -34,7 +34,7 @@ use std::cmp::Ordering;
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
use rustc_index::Idx;
-use rustc_middle::mir::{self, BasicBlock, Location};
+use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
use rustc_middle::ty::TyCtxt;
mod cursor;
@@ -48,23 +48,18 @@ mod visitor;
pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
pub use self::direction::{Backward, Direction, Forward};
pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
-pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
+pub use self::lattice::{JoinSemiLattice, MaybeReachable, MeetSemiLattice};
pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
/// Analysis domains are all bitsets of various kinds. This trait holds
/// operations needed by all of them.
pub trait BitSetExt<T> {
- fn domain_size(&self) -> usize;
fn contains(&self, elem: T) -> bool;
fn union(&mut self, other: &HybridBitSet<T>);
fn subtract(&mut self, other: &HybridBitSet<T>);
}
impl<T: Idx> BitSetExt<T> for BitSet<T> {
- fn domain_size(&self) -> usize {
- self.domain_size()
- }
-
fn contains(&self, elem: T) -> bool {
self.contains(elem)
}
@@ -79,10 +74,6 @@ impl<T: Idx> BitSetExt<T> for BitSet<T> {
}
impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> {
- fn domain_size(&self) -> usize {
- self.domain_size()
- }
-
fn contains(&self, elem: T) -> bool {
self.contains(elem)
}
@@ -172,12 +163,12 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// in this function. That should go in `apply_call_return_effect`. For example, in the
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
/// initialized here.
- fn apply_terminator_effect(
+ fn apply_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
- terminator: &mir::Terminator<'tcx>,
+ terminator: &'mir mir::Terminator<'tcx>,
location: Location,
- );
+ ) -> TerminatorEdges<'mir, 'tcx>;
/// Updates the current dataflow state with an effect that occurs immediately *before* the
/// given terminator.
@@ -207,20 +198,6 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
return_places: CallReturnPlaces<'_, 'tcx>,
);
- /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator.
- ///
- /// This is similar to `apply_call_return_effect` in that it only takes place after the
- /// generator is resumed, not when it is dropped.
- ///
- /// By default, no effects happen.
- fn apply_yield_resume_effect(
- &mut self,
- _state: &mut Self::Domain,
- _resume_block: BasicBlock,
- _resume_place: mir::Place<'tcx>,
- ) {
- }
-
/// Updates the current dataflow state with the effect of taking a particular branch in a
/// `SwitchInt` terminator.
///
@@ -295,6 +272,8 @@ where
pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
type Idx: Idx;
+ fn domain_size(&self, body: &mir::Body<'tcx>) -> usize;
+
/// See `Analysis::apply_statement_effect`.
fn statement_effect(
&mut self,
@@ -313,12 +292,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
}
/// See `Analysis::apply_terminator_effect`.
- fn terminator_effect(
+ fn terminator_effect<'mir>(
&mut self,
- trans: &mut impl GenKill<Self::Idx>,
- terminator: &mir::Terminator<'tcx>,
+ trans: &mut Self::Domain,
+ terminator: &'mir mir::Terminator<'tcx>,
location: Location,
- );
+ ) -> TerminatorEdges<'mir, 'tcx>;
/// See `Analysis::apply_before_terminator_effect`.
fn before_terminator_effect(
@@ -339,15 +318,6 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
return_places: CallReturnPlaces<'_, 'tcx>,
);
- /// See `Analysis::apply_yield_resume_effect`.
- fn yield_resume_effect(
- &mut self,
- _trans: &mut impl GenKill<Self::Idx>,
- _resume_block: BasicBlock,
- _resume_place: mir::Place<'tcx>,
- ) {
- }
-
/// See `Analysis::apply_switch_int_edge_effects`.
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
&mut self,
@@ -381,13 +351,13 @@ where
self.before_statement_effect(state, statement, location);
}
- fn apply_terminator_effect(
+ fn apply_terminator_effect<'mir>(
&mut self,
state: &mut A::Domain,
- terminator: &mir::Terminator<'tcx>,
+ terminator: &'mir mir::Terminator<'tcx>,
location: Location,
- ) {
- self.terminator_effect(state, terminator, location);
+ ) -> TerminatorEdges<'mir, 'tcx> {
+ self.terminator_effect(state, terminator, location)
}
fn apply_before_terminator_effect(
@@ -410,15 +380,6 @@ where
self.call_return_effect(state, block, return_places);
}
- fn apply_yield_resume_effect(
- &mut self,
- state: &mut A::Domain,
- resume_block: BasicBlock,
- resume_place: mir::Place<'tcx>,
- ) {
- self.yield_resume_effect(state, resume_block, resume_place);
- }
-
fn apply_switch_int_edge_effects(
&mut self,
block: BasicBlock,
@@ -531,6 +492,24 @@ impl<T: Idx> GenKill<T> for ChunkedBitSet<T> {
}
}
+impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
+ fn gen(&mut self, elem: T) {
+ match self {
+ // If the state is not reachable, adding an element does nothing.
+ MaybeReachable::Unreachable => {}
+ MaybeReachable::Reachable(set) => set.gen(elem),
+ }
+ }
+
+ fn kill(&mut self, elem: T) {
+ match self {
+ // If the state is not reachable, killing an element does nothing.
+ MaybeReachable::Unreachable => {}
+ MaybeReachable::Reachable(set) => set.kill(elem),
+ }
+ }
+}
+
impl<T: Idx> GenKill<T> for lattice::Dual<BitSet<T>> {
fn gen(&mut self, elem: T) {
self.0.insert(elem);
@@ -612,29 +591,5 @@ pub trait SwitchIntEdgeEffects<D> {
fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
}
-/// List of places that are written to after a successful (non-unwind) return
-/// from a `Call` or `InlineAsm`.
-pub enum CallReturnPlaces<'a, 'tcx> {
- Call(mir::Place<'tcx>),
- InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]),
-}
-
-impl<'tcx> CallReturnPlaces<'_, 'tcx> {
- pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) {
- match *self {
- Self::Call(place) => f(place),
- Self::InlineAsm(operands) => {
- for op in operands {
- match *op {
- mir::InlineAsmOperand::Out { place: Some(place), .. }
- | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
- _ => {}
- }
- }
- }
- }
- }
-}
-
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index cb0ec144e..9cce5b26c 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -198,14 +198,15 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx));
}
- fn apply_terminator_effect(
+ fn apply_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
- _terminator: &mir::Terminator<'tcx>,
+ terminator: &'mir mir::Terminator<'tcx>,
location: Location,
- ) {
+ ) -> TerminatorEdges<'mir, 'tcx> {
let idx = self.effect(Effect::Primary.at_index(location.statement_index));
assert!(state.insert(idx));
+ terminator.edges()
}
fn apply_before_terminator_effect(