Skip to content

Add new MIR constant propagation based on dataflow analysis #101168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 76 commits into from
Nov 15, 2022
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
Make more assumptions explicit
  • Loading branch information
jachris committed Nov 7, 2022
commit b5063ab0e543174e416e34fc130c8b8daba34b41
33 changes: 26 additions & 7 deletions compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@
//! Borrows.
//!
//! To be continued...
//!
//! The bottom state denotes uninitalized memory.
//!
//!
//! # Assumptions
//!
//! - (A1) Assignment to any tracked place invalidates all pointers that could be used to change
//! the underlying value.
//! - (A2) `StorageLive`, `StorageDead` and `Deinit` make the underlying memory at least
//! uninitialized (at least in the sense that declaring access UB is also fine).
//! - (A3) An assignment with `State::assign_place_idx` either involves non-overlapping places, or
//! the places are the same.
//! - (A4) If the value behind a reference to a `Freeze` place is changed, dereferencing the
//! reference is UB.

use std::fmt::{Debug, Formatter};

Expand Down Expand Up @@ -91,12 +105,11 @@ pub trait ValueAnalysis<'tcx> {
self.handle_intrinsic(intrinsic, state);
}
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
// We can flood with bottom here, because `StorageLive` makes the local
// uninitialized, and `StorageDead` makes it UB to access.
// (A2)
state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::bottom());
}
StatementKind::Deinit(box place) => {
// The bottom states denotes uninitialized values.
// (A2)
state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
}
StatementKind::Nop
Expand Down Expand Up @@ -200,7 +213,8 @@ pub trait ValueAnalysis<'tcx> {
ValueOrPlace::Value(self.handle_constant(constant, state))
}
Operand::Copy(place) | Operand::Move(place) => {
// Do we want to handle moves differently? Could flood place with bottom.
// On move, we would ideally flood the place with bottom. But with the current
// framework this is not possible (similar to `InterpCx::eval_operand`).
self.map()
.find(place.as_ref())
.map(ValueOrPlace::Place)
Expand Down Expand Up @@ -306,7 +320,6 @@ 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 @@ -440,10 +453,10 @@ 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) {
// We use (A3) and copy all entries one after another.
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.
Expand Down Expand Up @@ -490,6 +503,10 @@ impl<V: Clone + HasTop> State<V> {
if let Some(value_index) = map.places[target].value_index {
values[value_index] = V::top();
}
// Instead of tracking of *where* a reference points to (as in, which place), we
// track *what* it points to (as in, what do we know about the target). For an
// assignment `x = &y`, we thus copy the info we have for `y` to `*x`. This is
// sound because we only track places that are `Freeze`, and (A4).
if let Some(target_deref) = map.apply_elem(target, ProjElem::Deref) {
self.assign_place_idx(target_deref, source, map);
}
Expand Down Expand Up @@ -657,6 +674,8 @@ impl Map {
return Err(());
}

// FIXME: Check that the place is `Freeze`.

let place = self.make_place(local, projection)?;

// Allocate a value slot if it doesn't have one.
Expand Down