Skip to content

Commit 7c3d551

Browse files
committed
Create tracked places breadth first.
1 parent 71138e9 commit 7c3d551

File tree

1 file changed

+49
-65
lines changed

1 file changed

+49
-65
lines changed

compiler/rustc_mir_dataflow/src/value_analysis.rs

Lines changed: 49 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
//! Because of that, we can assume that the only way to change the value behind a tracked place is
3333
//! by direct assignment.
3434
35+
use std::collections::VecDeque;
3536
use std::fmt::{Debug, Formatter};
3637

3738
use rustc_data_structures::fx::FxHashMap;
@@ -608,7 +609,7 @@ impl Map {
608609
pub fn from_filter<'tcx>(
609610
tcx: TyCtxt<'tcx>,
610611
body: &Body<'tcx>,
611-
filter: impl FnMut(Ty<'tcx>) -> bool,
612+
filter: impl Fn(Ty<'tcx>) -> bool,
612613
place_limit: Option<usize>,
613614
) -> Self {
614615
let mut map = Self::new();
@@ -623,51 +624,67 @@ impl Map {
623624
&mut self,
624625
tcx: TyCtxt<'tcx>,
625626
body: &Body<'tcx>,
626-
mut filter: impl FnMut(Ty<'tcx>) -> bool,
627+
filter: impl Fn(Ty<'tcx>) -> bool,
627628
exclude: BitSet<Local>,
628629
place_limit: Option<usize>,
629630
) {
630631
// We use this vector as stack, pushing and popping projections.
631-
let mut projection = Vec::new();
632+
let mut worklist = VecDeque::with_capacity(place_limit.unwrap_or(body.local_decls.len()));
633+
self.locals = IndexVec::from_elem(None, &body.local_decls);
632634
for (local, decl) in body.local_decls.iter_enumerated() {
633-
if !exclude.contains(local) {
634-
self.register_with_filter_rec(
635-
tcx,
636-
local,
637-
&mut projection,
638-
decl.ty,
639-
&mut filter,
640-
place_limit,
641-
);
635+
if exclude.contains(local) {
636+
continue;
642637
}
638+
639+
// Create a place for the local.
640+
debug_assert!(self.locals[local].is_none());
641+
let place = self.places.push(PlaceInfo::new(None));
642+
self.locals[local] = Some(place);
643+
644+
// And push the eventual children places to the worklist.
645+
self.register_children(tcx, place, decl.ty, &filter, &mut worklist);
646+
}
647+
648+
// `place.elem1.elem2` with type `ty`.
649+
while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() {
650+
if let Some(place_limit) = place_limit && self.value_count >= place_limit {
651+
break
652+
}
653+
654+
// Create a place for this projection.
655+
for elem in [elem1, Some(elem2)].into_iter().flatten() {
656+
place = *self.projections.entry((place, elem)).or_insert_with(|| {
657+
// Prepend new child to the linked list.
658+
let next = self.places.push(PlaceInfo::new(Some(elem)));
659+
self.places[next].next_sibling = self.places[place].first_child;
660+
self.places[place].first_child = Some(next);
661+
next
662+
});
663+
}
664+
665+
// And push the eventual children places to the worklist.
666+
self.register_children(tcx, place, ty, &filter, &mut worklist);
643667
}
644668
}
645669

646670
/// Potentially register the (local, projection) place and its fields, recursively.
647671
///
648672
/// Invariant: The projection must only contain trackable elements.
649-
fn register_with_filter_rec<'tcx>(
673+
fn register_children<'tcx>(
650674
&mut self,
651675
tcx: TyCtxt<'tcx>,
652-
local: Local,
653-
projection: &mut Vec<PlaceElem<'tcx>>,
676+
place: PlaceIndex,
654677
ty: Ty<'tcx>,
655-
filter: &mut impl FnMut(Ty<'tcx>) -> bool,
656-
place_limit: Option<usize>,
678+
filter: &impl Fn(Ty<'tcx>) -> bool,
679+
worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>,
657680
) {
658-
if let Some(place_limit) = place_limit && self.value_count >= place_limit {
659-
return
660-
}
661-
662-
// We know that the projection only contains trackable elements.
663-
let place = self.make_place(local, projection).unwrap();
664-
665681
// Allocate a value slot if it doesn't have one, and the user requested one.
666682
if self.places[place].value_index.is_none() && filter(ty) {
667683
self.places[place].value_index = Some(self.value_count.into());
668684
self.value_count += 1;
669685
}
670686

687+
// For enums, directly create the `Discriminant`, as that's their main use.
671688
if ty.is_enum() {
672689
let discr_ty = ty.discriminant_ty(tcx);
673690
if filter(discr_ty) {
@@ -692,48 +709,15 @@ impl Map {
692709

693710
// Recurse with all fields of this place.
694711
iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
695-
if let Some(variant) = variant {
696-
projection.push(PlaceElem::Downcast(None, variant));
697-
let _ = self.make_place(local, projection);
698-
projection.push(PlaceElem::Field(field, ty));
699-
self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit);
700-
projection.pop();
701-
projection.pop();
702-
return;
703-
}
704-
projection.push(PlaceElem::Field(field, ty));
705-
self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit);
706-
projection.pop();
712+
worklist.push_back((
713+
place,
714+
variant.map(TrackElem::Variant),
715+
TrackElem::Field(field),
716+
ty,
717+
))
707718
});
708719
}
709720

710-
/// Tries to add the place to the map, without allocating a value slot.
711-
///
712-
/// Can fail if the projection contains non-trackable elements.
713-
fn make_place<'tcx>(
714-
&mut self,
715-
local: Local,
716-
projection: &[PlaceElem<'tcx>],
717-
) -> Result<PlaceIndex, ()> {
718-
// Get the base index of the local.
719-
let mut index =
720-
*self.locals.get_or_insert_with(local, || self.places.push(PlaceInfo::new(None)));
721-
722-
// Apply the projection.
723-
for &elem in projection {
724-
let elem = elem.try_into()?;
725-
index = *self.projections.entry((index, elem)).or_insert_with(|| {
726-
// Prepend new child to the linked list.
727-
let next = self.places.push(PlaceInfo::new(Some(elem)));
728-
self.places[next].next_sibling = self.places[index].first_child;
729-
self.places[index].first_child = Some(next);
730-
next
731-
});
732-
}
733-
734-
Ok(index)
735-
}
736-
737721
/// Returns the number of tracked places, i.e., those for which a value can be stored.
738722
pub fn tracked_places(&self) -> usize {
739723
self.value_count
@@ -750,7 +734,7 @@ impl Map {
750734
place: PlaceRef<'_>,
751735
extra: impl IntoIterator<Item = TrackElem>,
752736
) -> Option<PlaceIndex> {
753-
let mut index = *self.locals.get(place.local)?.as_ref()?;
737+
let mut index = *self.locals[place.local].as_ref()?;
754738

755739
for &elem in place.projection {
756740
index = self.apply(index, elem.try_into().ok()?)?;
@@ -794,7 +778,7 @@ impl Map {
794778
// We do not track indirect places.
795779
return;
796780
}
797-
let Some(&Some(mut index)) = self.locals.get(place.local) else {
781+
let Some(mut index) = self.locals[place.local] else {
798782
// The local is not tracked at all, so it does not alias anything.
799783
return;
800784
};

0 commit comments

Comments
 (0)