Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
4f9c30f
Add initial version of value analysis and dataflow constant propagation
jachris Aug 25, 2022
d0afe68
Try field type normalization instead of forcing it
jachris Aug 29, 2022
601fcc4
Update test results
jachris Aug 29, 2022
56ff16d
Fix spelling
jachris Aug 29, 2022
93ee806
Update test results
jachris Aug 29, 2022
c83489c
Remove empty test
jachris Aug 30, 2022
bb16397
Clarify registration and tracking of references
jachris Aug 30, 2022
2928694
Add additional flooding when assigning a value and corresponding test
jachris Aug 31, 2022
e75ad93
Begin a semi-formal argument for correctness
jachris Aug 31, 2022
1da3033
Change test from usize to i32 to prevent target issues
jachris Aug 31, 2022
3f98dc7
Clarify place expressions vs place objects
jachris Sep 1, 2022
ad99d2e
Move handling of references and simplify flooding
jachris Sep 1, 2022
47a00d5
Flood with bottom instead of top for unreachable branches
jachris Sep 1, 2022
8a789ce
Reject registration of downcasts for now
jachris Sep 1, 2022
469fb19
Update other test results
jachris Sep 1, 2022
16dedba
Ignore terminators explicitly
jachris Sep 1, 2022
fe84bbf
Add tracking of unreachability
jachris Sep 2, 2022
f234419
Rebase onto master
jachris Sep 2, 2022
895181b
Remove leftover test files
jachris Sep 2, 2022
2e4d082
Add more documentation
jachris Sep 2, 2022
2113e45
Remove superfluous line
jachris Sep 2, 2022
904adca
Flood place on drop
jachris Sep 4, 2022
1e5ca57
Use StorageDead and Deinit to flood place
jachris Sep 4, 2022
e2ddf8a
Add comment about downcast projection element
jachris Sep 4, 2022
817c277
Handle StorageLive
jachris Sep 9, 2022
bc82c13
Track Scalar instead of ScalarInt for const prop
jachris Sep 23, 2022
13b7059
Only allow registration of scalars for now
jachris Sep 27, 2022
6868617
Add tests from current const prop
jachris Sep 27, 2022
4cda6e5
Update test results
jachris Sep 27, 2022
97a69a7
Add some more unit-test directives
jachris Sep 27, 2022
c56e99c
Fix typo
jachris Sep 27, 2022
f99950f
Update test results after rebase
jachris Oct 4, 2022
eab7732
Handle NonDivergingIntrinsic and CopyNonOverlapping
jachris Oct 5, 2022
2f66e94
Flood with bottom for Deinit, StorageLive and StorageDead
jachris Oct 5, 2022
b5063ab
Make more assumptions explicit
jachris Oct 5, 2022
1765587
Only track (trivially) freeze types
jachris Oct 5, 2022
7ab1ba9
Remove `Unknown` state in favor of `Value(Top)`
jachris Oct 5, 2022
4478a87
Fix formatting
jachris Oct 5, 2022
111324e
Prevent registration inside references if target is !Freeze
jachris Oct 6, 2022
3c0f3b0
Only assume Stacked Borrows if -Zunsound-mir-opts is given
jachris Oct 6, 2022
7a52e73
Add tests for Stacked Borrows behavior
jachris Oct 6, 2022
b9dbb81
Improve example used for SB tests
jachris Oct 6, 2022
5696d06
Use the same is_enabled as the current const prop
jachris Oct 6, 2022
aaa35b3
Add comment for the current retag situation
jachris Oct 12, 2022
890fae9
Fix rebased CastKind
jachris Oct 12, 2022
8bed0b5
Update issue-50814.rs test result
jachris Oct 15, 2022
1dde908
Update test results
jachris Oct 15, 2022
be9013f
Make overflow flag propagation conditional
jachris Oct 15, 2022
931d99f
Make overflow handling more precise
jachris Oct 15, 2022
274a491
Improve documentation, plus some small changes
jachris Oct 19, 2022
062053b
Fix unimplemented binary_ptr_op
jachris Oct 19, 2022
5b7b309
Improve documentation of assumptions
jachris Oct 21, 2022
d86acdd
Prevent propagation of overflow if overflow occured
jachris Oct 23, 2022
de69d08
Explicitly match all terminators
jachris Oct 23, 2022
efc7ca8
Use ParamEnv consistently
jachris Oct 23, 2022
f29533b
Small documentation changes
jachris Oct 24, 2022
1f82a9f
Move HasTop and HasBottom into lattice.rs
jachris Oct 24, 2022
da4a40f
Remove copy of current const prop tests and add a few new tests
jachris Oct 25, 2022
630e17d
Limit number of tracked places, and some other perf improvements
jachris Oct 25, 2022
b478fcf
Use new cast methods
jachris Oct 26, 2022
72196ee
Limit number of basic blocks and tracked places to 100 for now
jachris Oct 27, 2022
89f9349
Small corrections of documentation
jachris Nov 7, 2022
3997893
Fix rebase
jachris Nov 7, 2022
bfbca6c
Completely remove tracking of references for now
jachris Nov 9, 2022
9766ee0
Fix struct field tracking and add tests for it
jachris Nov 9, 2022
8ecb276
Simplify creation of map
jachris Nov 10, 2022
3c6d1a7
Add test for repr(transparent) with scalar
jachris Nov 11, 2022
b3f6489
Add comment for guessed constants
jachris Nov 12, 2022
2e034dc
Exclude locals completely, instead of individual places
jachris Nov 12, 2022
74d53ab
Require -Zmir-opt-level >= 3 for now
jachris Nov 12, 2022
abe31a9
Partially revert 74d53ab
jachris Nov 12, 2022
d66a00a
Expand upon comment regarding self-assignment
jachris Nov 12, 2022
ea23585
Disable limits if mir-opt-level >= 4
jachris Nov 12, 2022
108790b
Remove log statement that was commented out
jachris Nov 12, 2022
c27ddc9
Remove redundant graphviz escaping
jachris Nov 14, 2022
24d2e90
Bless graphviz tests
jachris Nov 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add more documentation
  • Loading branch information
jachris committed Nov 7, 2022
commit 2e4d0820d2f36d97f5db22496c1f71087d0e5323
31 changes: 29 additions & 2 deletions compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ pub trait ValueAnalysis<'tcx> {
Self::Value::top()
}

/// The effect of a successful function call return should not be
/// applied here, see [`Analysis::apply_terminator_effect`].
fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
self.super_terminator(terminator, state)
}
Expand Down Expand Up @@ -267,6 +269,8 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
}

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 ⊥.
// This utilizes that reading from an uninitialized place is UB.
assert!(matches!(state.0, StateData::Unreachable));
let values = IndexVec::from_elem_n(T::Value::bottom(), self.0.map().value_count);
*state = State(StateData::Reachable(values));
Expand Down Expand Up @@ -325,20 +329,38 @@ where
}

rustc_index::newtype_index!(
/// This index uniquely identifies a place.
///
/// Not every place has a `PlaceIndex`, and not every `PlaceIndex` correspondends to a tracked
/// place. However, every tracked place and all places along its projection have a `PlaceIndex`.
pub struct PlaceIndex {}
);

rustc_index::newtype_index!(
/// This index uniquely identifies a tracked place and therefore a slot in [`State`].
///
/// It is an implementation detail of this module.
struct ValueIndex {}
);

/// See [`State`].
#[derive(PartialEq, Eq, Clone, Debug)]
enum StateData<V> {
Reachable(IndexVec<ValueIndex, V>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had one more idea for perf - what if you replace the IndexVec here with a FxHashMap (or some similar datastructure) and represent either index => Top or index => Bottom by having index be missing from the map. I expect that at any given time almost all locals will be in one of these states, and so the size might shrink quite a bit. We'd probably want to gather some data as to which of Bottom or Top would be more effective.

Copy link
Contributor Author

@jachris jachris Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. Most of the values start with bottom, and become either constant or top during the analysis. I would even say that top/bottom are somewhat equally distributed. This will perhaps make it difficult to get any positive impact from such a change. But we should certainly consider alternative state representations.

Copy link
Contributor

@JakobDegen JakobDegen Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... What if you run MaybeLiveLocals first and then mark things as Bottom if they're not live. This should make things be Bottom most of the time (hmm, this gets complicated quickly though...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm mistaken, V here is significantly larger than a usize. So one reasonable compression scheme is:

struct ReachableState {
    tops: HashSet<ValueIndex>,
    bottoms: HashSet<ValueIndex>,
    elems: HashMap<ValueIndex, V>,
}

Or something a bit more diabolical, like storing a HashMap<ValueIndex, V> with a BitSet where each 2 bits indicates if a ValueIndex is a Top, Bottom, or in the map.

Unreachable,
}

/// All operations on unreachable states are ignored.
/// The dataflow state for an instance of [`ValueAnalysis`].
///
/// Every instance specifies a lattice that represents the possible values of a single tracked
/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an
/// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is
/// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not
/// the bottom element (because joining an unreachable and any other reachable state yields a
/// reachable state). All operations on unreachable states are ignored.
///
/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
/// Assigning a place (or reference thereof) to another place assumes that
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct State<V>(StateData<V>);

Expand Down Expand Up @@ -383,8 +405,13 @@ impl<V: Clone + HasTop> State<V> {
self.flood_idx_with(place, map, V::top())
}

/// This method assumes that the given places are not overlapping, and that we can therefore
/// copy all entries one after another.
pub fn assign_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
let StateData::Reachable(values) = &mut self.0 else { return };
// If both places are tracked, we copy the value to the target. If the target is tracked,
// but the source is not, we have to invalidate the value in target. If the target is not
// tracked, then we don't have to do anything.
if let Some(target_value) = map.places[target].value_index {
if let Some(source_value) = map.places[source].value_index {
values[target_value] = values[source_value].clone();
Expand All @@ -393,7 +420,7 @@ impl<V: Clone + HasTop> State<V> {
}
}
for target_child in map.children(target) {
// Try to find corresponding child in source.
// Try to find corresponding child and recurse. Reasoning is similar as above.
let projection = map.places[target_child].proj_elem.unwrap();
if let Some(source_child) = map.projections.get(&(source, projection)) {
self.assign_place_idx(target_child, *source_child, map);
Expand Down