diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_mir_dataflow/src/framework | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-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.rs | 173 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/engine.rs | 41 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/fmt.rs | 32 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/graphviz.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/lattice.rs | 94 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/mod.rs | 111 | ||||
-rw-r--r-- | compiler/rustc_mir_dataflow/src/framework/tests.rs | 7 |
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( |