Skip to content

Commit d27b44e

Browse files
committed
Auto merge of #142821 - cjgillot:jump-threading-single, r=<try>
Compute jump threading opportunities in a single pass The current implementation of jump threading walks MIR CFG backwards from each `SwitchInt` terminator. This PR replaces this by a single postorder traversal of MIR. In theory, we could do a full fixpoint dataflow analysis, but this has low returns as we forbid threading through a loop header, and we do not merge TOs yet. The second commit in this PR modifies the carried state to a lighter data structure. The current implementation uses some kind of `IndexVec<ValueIndex, &[Condition]>`. This is needlessly heavy, as the state rarely ever carries more than a few `Condition`s. The first commit replaces this state with a simpler `&[Condition]`, and puts the corresponding `ValueIndex` inside `Condition`. The last commit is the main change. It needs a fair amount of data structure tweaks, as each condition now needs to carry its chain of blocks with it.
2 parents df4ad9e + bdf9d85 commit d27b44e

9 files changed

+583
-358
lines changed

compiler/rustc_mir_dataflow/src/value_analysis.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ rustc_index::newtype_index!(
2626
/// This index uniquely identifies a tracked place and therefore a slot in [`State`].
2727
///
2828
/// It is an implementation detail of this module.
29-
struct ValueIndex {}
29+
pub struct ValueIndex {}
3030
);
3131

3232
/// See [`State`].
@@ -211,22 +211,9 @@ impl<V: Clone + HasBottom> State<V> {
211211
/// The target place must have been flooded before calling this method.
212212
pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) {
213213
let State::Reachable(values) = self else { return };
214-
215-
// If both places are tracked, we copy the value to the target.
216-
// If the target is tracked, but the source is not, we do nothing, as invalidation has
217-
// already been performed.
218-
if let Some(target_value) = map.places[target].value_index {
219-
if let Some(source_value) = map.places[source].value_index {
220-
values.insert(target_value, values.get(source_value).clone());
221-
}
222-
}
223-
for target_child in map.children(target) {
224-
// Try to find corresponding child and recurse. Reasoning is similar as above.
225-
let projection = map.places[target_child].proj_elem.unwrap();
226-
if let Some(source_child) = map.projections.get(&(source, projection)) {
227-
self.insert_place_idx(target_child, *source_child, map);
228-
}
229-
}
214+
map.for_each_value_pair(target, source, &mut |target, source| {
215+
values.insert(target, values.get(source).clone());
216+
});
230217
}
231218

232219
/// Helper method to interpret `target = result`.
@@ -677,6 +664,26 @@ impl<'tcx> Map<'tcx> {
677664
self.find_extra(place, [TrackElem::DerefLen])
678665
}
679666

667+
/// Locates the value corresponding to the given place.
668+
pub fn value(&self, place: PlaceIndex) -> Option<ValueIndex> {
669+
self.places[place].value_index
670+
}
671+
672+
/// Locates the value corresponding to the given place.
673+
pub fn find_value(&self, place: PlaceRef<'_>) -> Option<ValueIndex> {
674+
self.value(self.find(place)?)
675+
}
676+
677+
/// Locates the value corresponding to the given discriminant.
678+
pub fn find_discr_value(&self, place: PlaceRef<'_>) -> Option<ValueIndex> {
679+
self.value(self.find_discr(place)?)
680+
}
681+
682+
/// Locates the value corresponding to the given length.
683+
pub fn find_len_value(&self, place: PlaceRef<'_>) -> Option<ValueIndex> {
684+
self.value(self.find_len(place)?)
685+
}
686+
680687
/// Iterate over all direct children.
681688
fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> {
682689
Children::new(self, parent)
@@ -689,7 +696,7 @@ impl<'tcx> Map<'tcx> {
689696
///
690697
/// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
691698
/// as such.
692-
fn for_each_aliasing_place(
699+
pub fn for_each_aliasing_place(
693700
&self,
694701
place: PlaceRef<'_>,
695702
tail_elem: Option<TrackElem>,
@@ -778,6 +785,31 @@ impl<'tcx> Map<'tcx> {
778785
}
779786
}
780787
}
788+
789+
/// Recursively iterates on each value contained in `target`, paired with matching projection
790+
/// inside `source`.
791+
pub fn for_each_value_pair(
792+
&self,
793+
target: PlaceIndex,
794+
source: PlaceIndex,
795+
f: &mut impl FnMut(ValueIndex, ValueIndex),
796+
) {
797+
// If both places are tracked, we copy the value to the target.
798+
// If the target is tracked, but the source is not, we do nothing, as invalidation has
799+
// already been performed.
800+
if let Some(target_value) = self.places[target].value_index {
801+
if let Some(source_value) = self.places[source].value_index {
802+
f(target_value, source_value)
803+
}
804+
}
805+
for target_child in self.children(target) {
806+
// Try to find corresponding child and recurse. Reasoning is similar as above.
807+
let projection = self.places[target_child].proj_elem.unwrap();
808+
if let Some(source_child) = self.projections.get(&(source, projection)) {
809+
self.for_each_value_pair(target_child, *source_child, f);
810+
}
811+
}
812+
}
781813
}
782814

783815
/// This is the information tracked for every [`PlaceIndex`] and is stored by [`Map`].

0 commit comments

Comments
 (0)