Swap encapsulation of DCP state.
This commit is contained in:
parent
2975a21b5d
commit
1834f5a272
@ -39,7 +39,7 @@
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
@ -336,14 +336,14 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
|
|||||||
const NAME: &'static str = T::NAME;
|
const NAME: &'static str = T::NAME;
|
||||||
|
|
||||||
fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
|
fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
|
||||||
State(StateData::Unreachable)
|
State::Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
||||||
// The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
|
// The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
|
||||||
assert!(matches!(state.0, StateData::Unreachable));
|
assert!(matches!(state, State::Unreachable));
|
||||||
let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count);
|
let values = StateData::from_elem_n(T::Value::BOTTOM, self.0.map().value_count);
|
||||||
*state = State(StateData::Reachable(values));
|
*state = State::Reachable(values);
|
||||||
for arg in body.args_iter() {
|
for arg in body.args_iter() {
|
||||||
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
|
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
|
||||||
}
|
}
|
||||||
@ -415,27 +415,30 @@ struct ValueIndex {}
|
|||||||
|
|
||||||
/// See [`State`].
|
/// See [`State`].
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
enum StateData<V> {
|
struct StateData<V> {
|
||||||
Reachable(IndexVec<ValueIndex, V>),
|
map: IndexVec<ValueIndex, V>,
|
||||||
Unreachable,
|
}
|
||||||
|
|
||||||
|
impl<V: Clone> StateData<V> {
|
||||||
|
fn from_elem_n(elem: V, n: usize) -> StateData<V> {
|
||||||
|
StateData { map: IndexVec::from_elem_n(elem, n) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Clone> Clone for StateData<V> {
|
impl<V: Clone> Clone for StateData<V> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
StateData { map: self.map.clone() }
|
||||||
Self::Reachable(x) => Self::Reachable(x.clone()),
|
|
||||||
Self::Unreachable => Self::Unreachable,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_from(&mut self, source: &Self) {
|
fn clone_from(&mut self, source: &Self) {
|
||||||
match (&mut *self, source) {
|
|
||||||
(Self::Reachable(x), Self::Reachable(y)) => {
|
|
||||||
// We go through `raw` here, because `IndexVec` currently has a naive `clone_from`.
|
// We go through `raw` here, because `IndexVec` currently has a naive `clone_from`.
|
||||||
x.raw.clone_from(&y.raw);
|
self.map.raw.clone_from(&source.map.raw)
|
||||||
}
|
|
||||||
_ => *self = source.clone(),
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
|
||||||
|
fn join(&mut self, other: &Self) -> bool {
|
||||||
|
self.map.join(&other.map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,33 +453,43 @@ fn clone_from(&mut self, source: &Self) {
|
|||||||
///
|
///
|
||||||
/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
|
/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct State<V>(StateData<V>);
|
pub enum State<V> {
|
||||||
|
Unreachable,
|
||||||
|
Reachable(StateData<V>),
|
||||||
|
}
|
||||||
|
|
||||||
impl<V: Clone> Clone for State<V> {
|
impl<V: Clone> Clone for State<V> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0.clone())
|
match self {
|
||||||
|
Self::Reachable(x) => Self::Reachable(x.clone()),
|
||||||
|
Self::Unreachable => Self::Unreachable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_from(&mut self, source: &Self) {
|
fn clone_from(&mut self, source: &Self) {
|
||||||
self.0.clone_from(&source.0);
|
match (&mut *self, source) {
|
||||||
|
(Self::Reachable(x), Self::Reachable(y)) => {
|
||||||
|
x.clone_from(&y);
|
||||||
|
}
|
||||||
|
_ => *self = source.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Clone> State<V> {
|
impl<V: Clone> State<V> {
|
||||||
pub fn new(init: V, map: &Map) -> State<V> {
|
pub fn new(init: V, map: &Map) -> State<V> {
|
||||||
let values = IndexVec::from_elem_n(init, map.value_count);
|
State::Reachable(StateData::from_elem_n(init, map.value_count))
|
||||||
State(StateData::Reachable(values))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
|
pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
|
||||||
match self.0 {
|
match self {
|
||||||
StateData::Unreachable => true,
|
State::Unreachable => true,
|
||||||
StateData::Reachable(ref values) => values.iter().all(f),
|
State::Reachable(ref values) => values.map.iter().all(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_reachable(&self) -> bool {
|
fn is_reachable(&self) -> bool {
|
||||||
matches!(&self.0, StateData::Reachable(_))
|
matches!(self, State::Reachable(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assign `value` to all places that are contained in `place` or may alias one.
|
/// Assign `value` to all places that are contained in `place` or may alias one.
|
||||||
@ -519,9 +532,9 @@ pub fn flood_with_tail_elem(
|
|||||||
map: &Map,
|
map: &Map,
|
||||||
value: V,
|
value: V,
|
||||||
) {
|
) {
|
||||||
let StateData::Reachable(values) = &mut self.0 else { return };
|
let State::Reachable(values) = self else { return };
|
||||||
map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
|
map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
|
||||||
values[vi] = value.clone();
|
values.map[vi] = value.clone();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,9 +554,9 @@ fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map)
|
|||||||
///
|
///
|
||||||
/// The target place must have been flooded before calling this method.
|
/// The target place must have been flooded before calling this method.
|
||||||
pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) {
|
pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) {
|
||||||
let StateData::Reachable(values) = &mut self.0 else { return };
|
let State::Reachable(values) = self else { return };
|
||||||
if let Some(value_index) = map.places[target].value_index {
|
if let Some(value_index) = map.places[target].value_index {
|
||||||
values[value_index] = value;
|
values.map[value_index] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,14 +568,14 @@ pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) {
|
|||||||
///
|
///
|
||||||
/// The target place must have been flooded before calling this method.
|
/// The target place must have been flooded before calling this method.
|
||||||
pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
|
pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
|
||||||
let StateData::Reachable(values) = &mut self.0 else { return };
|
let State::Reachable(values) = self else { return };
|
||||||
|
|
||||||
// If both places are tracked, we copy the value to the target.
|
// If both places are tracked, we copy the value to the target.
|
||||||
// If the target is tracked, but the source is not, we do nothing, as invalidation has
|
// If the target is tracked, but the source is not, we do nothing, as invalidation has
|
||||||
// already been performed.
|
// already been performed.
|
||||||
if let Some(target_value) = map.places[target].value_index {
|
if let Some(target_value) = map.places[target].value_index {
|
||||||
if let Some(source_value) = map.places[source].value_index {
|
if let Some(source_value) = map.places[source].value_index {
|
||||||
values[target_value] = values[source_value].clone();
|
values.map[target_value] = values.map[source_value].clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for target_child in map.children(target) {
|
for target_child in map.children(target) {
|
||||||
@ -616,11 +629,11 @@ pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
|
|||||||
|
|
||||||
/// Retrieve the value stored for a place index, or `None` if it is not tracked.
|
/// Retrieve the value stored for a place index, or `None` if it is not tracked.
|
||||||
pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
|
pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(values) => {
|
State::Reachable(values) => {
|
||||||
map.places[place].value_index.map(|v| values[v].clone())
|
map.places[place].value_index.map(|v| values.map[v].clone())
|
||||||
}
|
}
|
||||||
StateData::Unreachable => None,
|
State::Unreachable => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,10 +644,10 @@ pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V
|
|||||||
where
|
where
|
||||||
V: HasBottom + HasTop,
|
V: HasBottom + HasTop,
|
||||||
{
|
{
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
|
State::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
|
||||||
// Because this is unreachable, we can return any value we want.
|
// Because this is unreachable, we can return any value we want.
|
||||||
StateData::Unreachable => V::BOTTOM,
|
State::Unreachable => V::BOTTOM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,10 +658,10 @@ pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V
|
|||||||
where
|
where
|
||||||
V: HasBottom + HasTop,
|
V: HasBottom + HasTop,
|
||||||
{
|
{
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
|
State::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
|
||||||
// Because this is unreachable, we can return any value we want.
|
// Because this is unreachable, we can return any value we want.
|
||||||
StateData::Unreachable => V::BOTTOM,
|
State::Unreachable => V::BOTTOM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,10 +672,10 @@ pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V
|
|||||||
where
|
where
|
||||||
V: HasBottom + HasTop,
|
V: HasBottom + HasTop,
|
||||||
{
|
{
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP),
|
State::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP),
|
||||||
// Because this is unreachable, we can return any value we want.
|
// Because this is unreachable, we can return any value we want.
|
||||||
StateData::Unreachable => V::BOTTOM,
|
State::Unreachable => V::BOTTOM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,11 +686,11 @@ pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
|
|||||||
where
|
where
|
||||||
V: HasBottom + HasTop,
|
V: HasBottom + HasTop,
|
||||||
{
|
{
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(values) => {
|
State::Reachable(values) => {
|
||||||
map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)
|
map.places[place].value_index.map(|v| values.map[v].clone()).unwrap_or(V::TOP)
|
||||||
}
|
}
|
||||||
StateData::Unreachable => {
|
State::Unreachable => {
|
||||||
// Because this is unreachable, we can return any value we want.
|
// Because this is unreachable, we can return any value we want.
|
||||||
V::BOTTOM
|
V::BOTTOM
|
||||||
}
|
}
|
||||||
@ -687,13 +700,13 @@ pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
|
|||||||
|
|
||||||
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
|
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
|
||||||
fn join(&mut self, other: &Self) -> bool {
|
fn join(&mut self, other: &Self) -> bool {
|
||||||
match (&mut self.0, &other.0) {
|
match (&mut *self, other) {
|
||||||
(_, StateData::Unreachable) => false,
|
(_, State::Unreachable) => false,
|
||||||
(StateData::Unreachable, _) => {
|
(State::Unreachable, _) => {
|
||||||
*self = other.clone();
|
*self = other.clone();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
(StateData::Reachable(this), StateData::Reachable(other)) => this.join(other),
|
(State::Reachable(this), State::Reachable(ref other)) => this.join(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1194,9 +1207,9 @@ impl<'tcx, T> DebugWithContext<ValueAnalysisWrapper<T>> for State<T::Value>
|
|||||||
T::Value: Debug,
|
T::Value: Debug,
|
||||||
{
|
{
|
||||||
fn fmt_with(&self, ctxt: &ValueAnalysisWrapper<T>, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt_with(&self, ctxt: &ValueAnalysisWrapper<T>, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match &self.0 {
|
match self {
|
||||||
StateData::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f),
|
State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f),
|
||||||
StateData::Unreachable => write!(f, "unreachable"),
|
State::Unreachable => write!(f, "unreachable"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1206,8 +1219,8 @@ fn fmt_diff_with(
|
|||||||
ctxt: &ValueAnalysisWrapper<T>,
|
ctxt: &ValueAnalysisWrapper<T>,
|
||||||
f: &mut Formatter<'_>,
|
f: &mut Formatter<'_>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
match (&self.0, &old.0) {
|
match (self, old) {
|
||||||
(StateData::Reachable(this), StateData::Reachable(old)) => {
|
(State::Reachable(this), State::Reachable(old)) => {
|
||||||
debug_with_context(this, Some(old), ctxt.0.map(), f)
|
debug_with_context(this, Some(old), ctxt.0.map(), f)
|
||||||
}
|
}
|
||||||
_ => Ok(()), // Consider printing something here.
|
_ => Ok(()), // Consider printing something here.
|
||||||
@ -1218,18 +1231,18 @@ fn fmt_diff_with(
|
|||||||
fn debug_with_context_rec<V: Debug + Eq>(
|
fn debug_with_context_rec<V: Debug + Eq>(
|
||||||
place: PlaceIndex,
|
place: PlaceIndex,
|
||||||
place_str: &str,
|
place_str: &str,
|
||||||
new: &IndexSlice<ValueIndex, V>,
|
new: &StateData<V>,
|
||||||
old: Option<&IndexSlice<ValueIndex, V>>,
|
old: Option<&StateData<V>>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
f: &mut Formatter<'_>,
|
f: &mut Formatter<'_>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
if let Some(value) = map.places[place].value_index {
|
if let Some(value) = map.places[place].value_index {
|
||||||
match old {
|
match old {
|
||||||
None => writeln!(f, "{}: {:?}", place_str, new[value])?,
|
None => writeln!(f, "{}: {:?}", place_str, new.map[value])?,
|
||||||
Some(old) => {
|
Some(old) => {
|
||||||
if new[value] != old[value] {
|
if new.map[value] != old.map[value] {
|
||||||
writeln!(f, "\u{001f}-{}: {:?}", place_str, old[value])?;
|
writeln!(f, "\u{001f}-{}: {:?}", place_str, old.map[value])?;
|
||||||
writeln!(f, "\u{001f}+{}: {:?}", place_str, new[value])?;
|
writeln!(f, "\u{001f}+{}: {:?}", place_str, new.map[value])?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1262,8 +1275,8 @@ fn debug_with_context_rec<V: Debug + Eq>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn debug_with_context<V: Debug + Eq>(
|
fn debug_with_context<V: Debug + Eq>(
|
||||||
new: &IndexSlice<ValueIndex, V>,
|
new: &StateData<V>,
|
||||||
old: Option<&IndexSlice<ValueIndex, V>>,
|
old: Option<&StateData<V>>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
f: &mut Formatter<'_>,
|
f: &mut Formatter<'_>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
|
Loading…
Reference in New Issue
Block a user