mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Move handling of references and simplify flooding
This commit is contained in:
parent
3f98dc7838
commit
ad99d2e15d
@ -115,35 +115,15 @@ pub trait ValueAnalysis<'tcx> {
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
state: &mut State<Self::Value>,
|
||||
) {
|
||||
match rvalue {
|
||||
Rvalue::Ref(_, BorrowKind::Shared, place) => {
|
||||
let target_deref = self
|
||||
.map()
|
||||
.find(target.as_ref())
|
||||
.and_then(|target| self.map().apply_elem(target, ProjElem::Deref));
|
||||
let place = self.map().find(place.as_ref());
|
||||
match (target_deref, place) {
|
||||
(Some(target_deref), Some(place)) => {
|
||||
state.assign_idx(target_deref, ValueOrPlace::Place(place), self.map())
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
||||
state.flood(place.as_ref(), self.map(), Self::Value::top());
|
||||
}
|
||||
_ => {
|
||||
let result = self.handle_rvalue(rvalue, state);
|
||||
state.assign(target.as_ref(), result, self.map());
|
||||
}
|
||||
}
|
||||
let result = self.handle_rvalue(rvalue, state);
|
||||
state.assign(target.as_ref(), result, self.map());
|
||||
}
|
||||
|
||||
fn handle_rvalue(
|
||||
&self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
state: &mut State<Self::Value>,
|
||||
) -> ValueOrPlace<Self::Value> {
|
||||
) -> ValueOrPlaceOrRef<Self::Value> {
|
||||
self.super_rvalue(rvalue, state)
|
||||
}
|
||||
|
||||
@ -151,16 +131,24 @@ pub trait ValueAnalysis<'tcx> {
|
||||
&self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
state: &mut State<Self::Value>,
|
||||
) -> ValueOrPlace<Self::Value> {
|
||||
) -> ValueOrPlaceOrRef<Self::Value> {
|
||||
match rvalue {
|
||||
Rvalue::Use(operand) => self.handle_operand(operand, state),
|
||||
Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state),
|
||||
Rvalue::Ref(..) | Rvalue::AddressOf(..) => {
|
||||
bug!("this rvalue must be handled by handle_assign() or super_assign()")
|
||||
Rvalue::Use(operand) => self.handle_operand(operand, state).into(),
|
||||
Rvalue::Ref(_, BorrowKind::Shared, place) => self
|
||||
.map()
|
||||
.find(place.as_ref())
|
||||
.map(ValueOrPlaceOrRef::Ref)
|
||||
.unwrap_or(ValueOrPlaceOrRef::Unknown),
|
||||
Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
||||
state.flood(place.as_ref(), self.map());
|
||||
ValueOrPlaceOrRef::Unknown
|
||||
}
|
||||
Rvalue::CopyForDeref(place) => {
|
||||
self.handle_operand(&Operand::Copy(*place), state).into()
|
||||
}
|
||||
_ => {
|
||||
// FIXME: Check that other Rvalues really have no side-effect.
|
||||
ValueOrPlace::Unknown
|
||||
ValueOrPlaceOrRef::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,7 +216,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||
state: &mut State<Self::Value>,
|
||||
) {
|
||||
return_places.for_each(|place| {
|
||||
state.flood(place.as_ref(), self.map(), Self::Value::top());
|
||||
state.flood(place.as_ref(), self.map());
|
||||
})
|
||||
}
|
||||
|
||||
@ -270,7 +258,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
|
||||
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
||||
for arg in body.args_iter() {
|
||||
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map(), T::Value::top());
|
||||
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,17 +316,25 @@ rustc_index::newtype_index!(
|
||||
pub struct State<V>(IndexVec<ValueIndex, V>);
|
||||
|
||||
impl<V: Clone + HasTop> State<V> {
|
||||
pub fn flood_all(&mut self, value: V) {
|
||||
pub fn flood_all(&mut self) {
|
||||
self.flood_all_with(V::top())
|
||||
}
|
||||
|
||||
pub fn flood_all_with(&mut self, value: V) {
|
||||
self.0.raw.fill(value);
|
||||
}
|
||||
|
||||
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
|
||||
pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
|
||||
if let Some(root) = map.find(place) {
|
||||
self.flood_idx(root, map, value);
|
||||
self.flood_idx_with(root, map, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flood_idx(&mut self, place: PlaceIndex, map: &Map, value: V) {
|
||||
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
|
||||
self.flood_with(place, map, V::top())
|
||||
}
|
||||
|
||||
pub fn flood_idx_with(&mut self, place: PlaceIndex, map: &Map, value: V) {
|
||||
map.preorder_invoke(place, &mut |place| {
|
||||
if let Some(vi) = map.places[place].value_index {
|
||||
self.0[vi] = value.clone();
|
||||
@ -346,6 +342,10 @@ impl<V: Clone + HasTop> State<V> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn flood_idx(&mut self, place: PlaceIndex, map: &Map) {
|
||||
self.flood_idx_with(place, map, V::top())
|
||||
}
|
||||
|
||||
pub fn assign_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
|
||||
if let Some(target_value) = map.places[target].value_index {
|
||||
if let Some(source_value) = map.places[source].value_index {
|
||||
@ -360,30 +360,40 @@ impl<V: Clone + HasTop> State<V> {
|
||||
if let Some(source_child) = map.projections.get(&(source, projection)) {
|
||||
self.assign_place_idx(target_child, *source_child, map);
|
||||
} else {
|
||||
self.flood_idx(target_child, map, V::top());
|
||||
self.flood_idx(target_child, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
|
||||
pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlaceOrRef<V>, map: &Map) {
|
||||
if let Some(target) = map.find(target) {
|
||||
self.assign_idx(target, result, map);
|
||||
} else {
|
||||
// We don't track this place nor any projections, assignment can be ignored.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map) {
|
||||
pub fn assign_idx(&mut self, target: PlaceIndex, result: ValueOrPlaceOrRef<V>, map: &Map) {
|
||||
match result {
|
||||
ValueOrPlace::Value(value) => {
|
||||
ValueOrPlaceOrRef::Value(value) => {
|
||||
// First flood the target place in case we also track any projections (although
|
||||
// this scenario is currently not well-supported with the ValueOrPlace interface).
|
||||
self.flood_idx(target, map, V::top());
|
||||
// this scenario is currently not well-supported by the API).
|
||||
self.flood_idx(target, map);
|
||||
if let Some(value_index) = map.places[target].value_index {
|
||||
self.0[value_index] = value;
|
||||
}
|
||||
}
|
||||
ValueOrPlace::Place(source) => self.assign_place_idx(target, source, map),
|
||||
ValueOrPlace::Unknown => {
|
||||
self.flood_idx(target, map, V::top());
|
||||
ValueOrPlaceOrRef::Place(source) => self.assign_place_idx(target, source, map),
|
||||
ValueOrPlaceOrRef::Ref(source) => {
|
||||
if let Some(value_index) = map.places[target].value_index {
|
||||
self.0[value_index] = V::top();
|
||||
}
|
||||
if let Some(target_deref) = map.apply_elem(target, ProjElem::Deref) {
|
||||
self.assign_place_idx(target_deref, source, map);
|
||||
}
|
||||
}
|
||||
ValueOrPlaceOrRef::Unknown => {
|
||||
self.flood_idx(target, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -578,6 +588,23 @@ pub enum ValueOrPlace<V> {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
pub enum ValueOrPlaceOrRef<V> {
|
||||
Value(V),
|
||||
Place(PlaceIndex),
|
||||
Ref(PlaceIndex),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl<V> From<ValueOrPlace<V>> for ValueOrPlaceOrRef<V> {
|
||||
fn from(x: ValueOrPlace<V>) -> Self {
|
||||
match x {
|
||||
ValueOrPlace::Value(value) => ValueOrPlaceOrRef::Value(value),
|
||||
ValueOrPlace::Place(place) => ValueOrPlaceOrRef::Place(place),
|
||||
ValueOrPlace::Unknown => ValueOrPlaceOrRef::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasBottom {
|
||||
fn bottom() -> Self;
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::value_analysis::{Map, ProjElem, State, ValueAnalysis, ValueOrPlace};
|
||||
use rustc_mir_dataflow::value_analysis::{
|
||||
Map, ProjElem, State, ValueAnalysis, ValueOrPlace, ValueOrPlaceOrRef,
|
||||
};
|
||||
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
@ -59,6 +61,12 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> {
|
||||
match rvalue {
|
||||
Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
||||
let target = self.map().find(target.as_ref());
|
||||
if let Some(target) = target {
|
||||
// We should not track any projections other than
|
||||
// what is overwritten below, but just in case...
|
||||
state.flood_idx(target, self.map());
|
||||
}
|
||||
|
||||
let value_target = target.and_then(|target| {
|
||||
self.map().apply_elem(target, ProjElem::Field(0_u32.into()))
|
||||
});
|
||||
@ -70,12 +78,12 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> {
|
||||
let (val, overflow) = self.binary_op(state, *op, left, right);
|
||||
|
||||
if let Some(value_target) = value_target {
|
||||
state.assign_idx(value_target, ValueOrPlace::Value(val), self.map());
|
||||
state.assign_idx(value_target, ValueOrPlaceOrRef::Value(val), self.map());
|
||||
}
|
||||
if let Some(overflow_target) = overflow_target {
|
||||
state.assign_idx(
|
||||
overflow_target,
|
||||
ValueOrPlace::Value(overflow),
|
||||
ValueOrPlaceOrRef::Value(overflow),
|
||||
self.map(),
|
||||
);
|
||||
}
|
||||
@ -89,7 +97,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> {
|
||||
&self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
state: &mut State<Self::Value>,
|
||||
) -> ValueOrPlace<Self::Value> {
|
||||
) -> ValueOrPlaceOrRef<Self::Value> {
|
||||
match rvalue {
|
||||
Rvalue::Cast(CastKind::Misc, operand, ty) => {
|
||||
let operand = self.eval_operand(operand, state);
|
||||
@ -97,24 +105,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> {
|
||||
FlatSet::Elem(operand) => self
|
||||
.ecx
|
||||
.misc_cast(&operand, *ty)
|
||||
.map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty)))
|
||||
.unwrap_or(ValueOrPlace::Unknown),
|
||||
_ => ValueOrPlace::Unknown,
|
||||
.map(|result| ValueOrPlaceOrRef::Value(self.wrap_immediate(result, *ty)))
|
||||
.unwrap_or(ValueOrPlaceOrRef::Unknown),
|
||||
_ => ValueOrPlaceOrRef::Unknown,
|
||||
}
|
||||
}
|
||||
Rvalue::BinaryOp(op, box (left, right)) => {
|
||||
let (val, _overflow) = self.binary_op(state, *op, left, right);
|
||||
// FIXME: Just ignore overflow here?
|
||||
ValueOrPlace::Value(val)
|
||||
ValueOrPlaceOrRef::Value(val)
|
||||
}
|
||||
Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(value) => self
|
||||
.ecx
|
||||
.unary_op(*op, &value)
|
||||
.map(|val| ValueOrPlace::Value(self.wrap_immty(val)))
|
||||
.unwrap_or(ValueOrPlace::Value(FlatSet::Top)),
|
||||
FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom),
|
||||
FlatSet::Top => ValueOrPlace::Value(FlatSet::Top),
|
||||
.map(|val| ValueOrPlaceOrRef::Value(self.wrap_immty(val)))
|
||||
.unwrap_or(ValueOrPlaceOrRef::Value(FlatSet::Top)),
|
||||
FlatSet::Bottom => ValueOrPlaceOrRef::Value(FlatSet::Bottom),
|
||||
FlatSet::Top => ValueOrPlaceOrRef::Value(FlatSet::Top),
|
||||
},
|
||||
_ => self.super_rvalue(rvalue, state),
|
||||
}
|
||||
@ -175,7 +183,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> {
|
||||
handled = true;
|
||||
} else {
|
||||
// Branch is not taken, we can flood everything.
|
||||
state.flood_all(FlatSet::Bottom);
|
||||
state.flood_all();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user