Use TerminatorEdge for dataflow-const-prop.
This commit is contained in:
parent
3acfa092db
commit
f19cd3f2e1
2 changed files with 48 additions and 62 deletions
|
@ -241,11 +241,19 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
|
|
||||||
/// The effect of a successful function call return should not be
|
/// The effect of a successful function call return should not be
|
||||||
/// applied here, see [`Analysis::apply_terminator_effect`].
|
/// applied here, see [`Analysis::apply_terminator_effect`].
|
||||||
fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
|
fn handle_terminator<'mir>(
|
||||||
|
&self,
|
||||||
|
terminator: &'mir Terminator<'tcx>,
|
||||||
|
state: &mut State<Self::Value>,
|
||||||
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
self.super_terminator(terminator, state)
|
self.super_terminator(terminator, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
|
fn super_terminator<'mir>(
|
||||||
|
&self,
|
||||||
|
terminator: &'mir Terminator<'tcx>,
|
||||||
|
state: &mut State<Self::Value>,
|
||||||
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
|
TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
|
||||||
// Effect is applied by `handle_call_return`.
|
// Effect is applied by `handle_call_return`.
|
||||||
|
@ -257,8 +265,10 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
// They would have an effect, but are not allowed in this phase.
|
// They would have an effect, but are not allowed in this phase.
|
||||||
bug!("encountered disallowed terminator");
|
bug!("encountered disallowed terminator");
|
||||||
}
|
}
|
||||||
|
TerminatorKind::SwitchInt { discr, targets } => {
|
||||||
|
return self.handle_switch_int(discr, targets, state);
|
||||||
|
}
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Terminate
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
|
@ -270,6 +280,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
// These terminators have no effect on the analysis.
|
// These terminators have no effect on the analysis.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
terminator.edges()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_call_return(
|
fn handle_call_return(
|
||||||
|
@ -290,19 +301,22 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_switch_int(
|
fn handle_switch_int<'mir>(
|
||||||
&self,
|
&self,
|
||||||
discr: &Operand<'tcx>,
|
discr: &'mir Operand<'tcx>,
|
||||||
apply_edge_effects: &mut impl SwitchIntEdgeEffects<State<Self::Value>>,
|
targets: &'mir SwitchTargets,
|
||||||
) {
|
state: &mut State<Self::Value>,
|
||||||
self.super_switch_int(discr, apply_edge_effects)
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
|
self.super_switch_int(discr, targets, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_switch_int(
|
fn super_switch_int<'mir>(
|
||||||
&self,
|
&self,
|
||||||
_discr: &Operand<'tcx>,
|
discr: &'mir Operand<'tcx>,
|
||||||
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<State<Self::Value>>,
|
targets: &'mir SwitchTargets,
|
||||||
) {
|
_state: &mut State<Self::Value>,
|
||||||
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
|
TerminatorEdge::SwitchInt { discr, targets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap(self) -> ValueAnalysisWrapper<Self>
|
fn wrap(self) -> ValueAnalysisWrapper<Self>
|
||||||
|
@ -359,9 +373,10 @@ where
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) -> TerminatorEdge<'mir, 'tcx> {
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
if state.is_reachable() {
|
if state.is_reachable() {
|
||||||
self.0.handle_terminator(terminator, state);
|
self.0.handle_terminator(terminator, state)
|
||||||
|
} else {
|
||||||
|
TerminatorEdge::None
|
||||||
}
|
}
|
||||||
terminator.edges()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_call_return_effect(
|
fn apply_call_return_effect(
|
||||||
|
@ -378,11 +393,9 @@ where
|
||||||
fn apply_switch_int_edge_effects(
|
fn apply_switch_int_edge_effects(
|
||||||
&mut self,
|
&mut self,
|
||||||
_block: BasicBlock,
|
_block: BasicBlock,
|
||||||
discr: &Operand<'tcx>,
|
_discr: &Operand<'tcx>,
|
||||||
apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||||
) {
|
) {
|
||||||
// FIXME: Dataflow framework provides no access to current state here.
|
|
||||||
self.0.handle_switch_int(discr, apply_edge_effects)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_mir_dataflow::value_analysis::{
|
use rustc_mir_dataflow::value_analysis::{
|
||||||
Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
|
Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
|
||||||
};
|
};
|
||||||
use rustc_mir_dataflow::{
|
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
|
||||||
lattice::FlatSet, Analysis, Results, ResultsVisitor, SwitchIntEdgeEffects,
|
|
||||||
};
|
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
|
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
|
||||||
|
|
||||||
|
@ -249,49 +247,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
||||||
.unwrap_or(FlatSet::Top)
|
.unwrap_or(FlatSet::Top)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_switch_int(
|
fn handle_switch_int<'mir>(
|
||||||
&self,
|
&self,
|
||||||
discr: &Operand<'tcx>,
|
discr: &'mir Operand<'tcx>,
|
||||||
apply_edge_effects: &mut impl SwitchIntEdgeEffects<State<Self::Value>>,
|
targets: &'mir SwitchTargets,
|
||||||
) {
|
state: &mut State<Self::Value>,
|
||||||
// FIXME: The dataflow framework only provides the state if we call `apply()`, which makes
|
) -> TerminatorEdge<'mir, 'tcx> {
|
||||||
// this more inefficient than it has to be.
|
|
||||||
let mut discr_value = None;
|
|
||||||
let mut handled = false;
|
|
||||||
apply_edge_effects.apply(|state, target| {
|
|
||||||
let discr_value = match discr_value {
|
|
||||||
Some(value) => value,
|
|
||||||
None => {
|
|
||||||
let value = match self.handle_operand(discr, state) {
|
let value = match self.handle_operand(discr, state) {
|
||||||
ValueOrPlace::Value(value) => value,
|
ValueOrPlace::Value(value) => value,
|
||||||
ValueOrPlace::Place(place) => state.get_idx(place, self.map()),
|
ValueOrPlace::Place(place) => state.get_idx(place, self.map()),
|
||||||
};
|
};
|
||||||
let result = match value {
|
let FlatSet::Elem(ScalarTy(scalar, _)) = value else {
|
||||||
FlatSet::Top => FlatSet::Top,
|
|
||||||
FlatSet::Elem(ScalarTy(scalar, _)) => {
|
|
||||||
let int = scalar.assert_int();
|
|
||||||
FlatSet::Elem(int.assert_bits(int.size()))
|
|
||||||
}
|
|
||||||
FlatSet::Bottom => FlatSet::Bottom,
|
|
||||||
};
|
|
||||||
discr_value = Some(result);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let FlatSet::Elem(choice) = discr_value else {
|
|
||||||
// Do nothing if we don't know which branch will be taken.
|
// Do nothing if we don't know which branch will be taken.
|
||||||
return;
|
return TerminatorEdge::SwitchInt { discr, targets };
|
||||||
};
|
};
|
||||||
|
|
||||||
if target.value.map(|n| n == choice).unwrap_or(!handled) {
|
let int = scalar.assert_int();
|
||||||
// Branch is taken. Has no effect on state.
|
let choice = int.assert_bits(int.size());
|
||||||
handled = true;
|
TerminatorEdge::Single(targets.target_for_value(choice))
|
||||||
} else {
|
|
||||||
// Branch is not taken.
|
|
||||||
state.mark_unreachable();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue