Skip to content

Commit b84d659

Browse files
committed
Auto merge of #115612 - cjgillot:const-prop-int, r=oli-obk
Improvements to dataflow const-prop Partially cherry-picked from #110719 r? `@oli-obk` cc `@jachris`
2 parents 69ec430 + b7a925a commit b84d659

File tree

63 files changed

+1979
-188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1979
-188
lines changed

Diff for: compiler/rustc_middle/src/mir/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,13 @@ impl<'tcx> PlaceRef<'tcx> {
17371737
}
17381738
}
17391739

1740+
impl From<Local> for PlaceRef<'_> {
1741+
#[inline]
1742+
fn from(local: Local) -> Self {
1743+
PlaceRef { local, projection: &[] }
1744+
}
1745+
}
1746+
17401747
impl Debug for Place<'_> {
17411748
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
17421749
self.as_ref().fmt(fmt)
@@ -2317,7 +2324,7 @@ impl<'tcx> ConstantKind<'tcx> {
23172324

23182325
#[inline]
23192326
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
2320-
Some(self.try_to_scalar()?.assert_int())
2327+
self.try_to_scalar()?.try_to_int().ok()
23212328
}
23222329

23232330
#[inline]

Diff for: compiler/rustc_middle/src/ty/consts/int.rs

+5
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ impl ScalarInt {
226226
}
227227
}
228228

229+
#[inline]
230+
pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
231+
Self::try_from_uint(i, tcx.data_layout.pointer_size)
232+
}
233+
229234
#[inline]
230235
pub fn assert_bits(self, target_size: Size) -> u128 {
231236
self.to_bits(target_size).unwrap_or_else(|size| {

Diff for: compiler/rustc_mir_dataflow/src/value_analysis.rs

+64-45
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
581581
}
582582
}
583583

584+
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
585+
pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V {
586+
match map.find_len(place) {
587+
Some(place) => self.get_idx(place, map),
588+
None => V::TOP,
589+
}
590+
}
591+
584592
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
585593
pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
586594
match &self.0 {
@@ -626,45 +634,36 @@ pub struct Map {
626634
}
627635

628636
impl Map {
629-
fn new() -> Self {
630-
Self {
637+
/// Returns a map that only tracks places whose type has scalar layout.
638+
///
639+
/// This is currently the only way to create a [`Map`]. The way in which the tracked places are
640+
/// chosen is an implementation detail and may not be relied upon (other than that their type
641+
/// are scalars).
642+
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self {
643+
let mut map = Self {
631644
locals: IndexVec::new(),
632645
projections: FxHashMap::default(),
633646
places: IndexVec::new(),
634647
value_count: 0,
635648
inner_values: IndexVec::new(),
636649
inner_values_buffer: Vec::new(),
637-
}
638-
}
639-
640-
/// Returns a map that only tracks places whose type passes the filter.
641-
///
642-
/// This is currently the only way to create a [`Map`]. The way in which the tracked places are
643-
/// chosen is an implementation detail and may not be relied upon (other than that their type
644-
/// passes the filter).
645-
pub fn from_filter<'tcx>(
646-
tcx: TyCtxt<'tcx>,
647-
body: &Body<'tcx>,
648-
filter: impl Fn(Ty<'tcx>) -> bool,
649-
value_limit: Option<usize>,
650-
) -> Self {
651-
let mut map = Self::new();
650+
};
652651
let exclude = excluded_locals(body);
653-
map.register_with_filter(tcx, body, filter, exclude, value_limit);
652+
map.register(tcx, body, exclude, value_limit);
654653
debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len());
655654
map
656655
}
657656

658-
/// Register all non-excluded places that pass the filter.
659-
fn register_with_filter<'tcx>(
657+
/// Register all non-excluded places that have scalar layout.
658+
fn register<'tcx>(
660659
&mut self,
661660
tcx: TyCtxt<'tcx>,
662661
body: &Body<'tcx>,
663-
filter: impl Fn(Ty<'tcx>) -> bool,
664662
exclude: BitSet<Local>,
665663
value_limit: Option<usize>,
666664
) {
667665
let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len()));
666+
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
668667

669668
// Start by constructing the places for each bare local.
670669
self.locals = IndexVec::from_elem(None, &body.local_decls);
@@ -679,7 +678,7 @@ impl Map {
679678
self.locals[local] = Some(place);
680679

681680
// And push the eventual children places to the worklist.
682-
self.register_children(tcx, place, decl.ty, &filter, &mut worklist);
681+
self.register_children(tcx, param_env, place, decl.ty, &mut worklist);
683682
}
684683

685684
// `place.elem1.elem2` with type `ty`.
@@ -702,7 +701,7 @@ impl Map {
702701
}
703702

704703
// And push the eventual children places to the worklist.
705-
self.register_children(tcx, place, ty, &filter, &mut worklist);
704+
self.register_children(tcx, param_env, place, ty, &mut worklist);
706705
}
707706

708707
// Pre-compute the tree of ValueIndex nested in each PlaceIndex.
@@ -732,42 +731,52 @@ impl Map {
732731
fn register_children<'tcx>(
733732
&mut self,
734733
tcx: TyCtxt<'tcx>,
734+
param_env: ty::ParamEnv<'tcx>,
735735
place: PlaceIndex,
736736
ty: Ty<'tcx>,
737-
filter: &impl Fn(Ty<'tcx>) -> bool,
738737
worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>,
739738
) {
740739
// Allocate a value slot if it doesn't have one, and the user requested one.
741-
if self.places[place].value_index.is_none() && filter(ty) {
740+
assert!(self.places[place].value_index.is_none());
741+
if tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.abi.is_scalar()) {
742742
self.places[place].value_index = Some(self.value_count.into());
743743
self.value_count += 1;
744744
}
745745

746746
// For enums, directly create the `Discriminant`, as that's their main use.
747747
if ty.is_enum() {
748-
let discr_ty = ty.discriminant_ty(tcx);
749-
if filter(discr_ty) {
750-
let discr = *self
751-
.projections
752-
.entry((place, TrackElem::Discriminant))
753-
.or_insert_with(|| {
754-
// Prepend new child to the linked list.
755-
let next = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant)));
756-
self.places[next].next_sibling = self.places[place].first_child;
757-
self.places[place].first_child = Some(next);
758-
next
759-
});
760-
761-
// Allocate a value slot if it doesn't have one.
762-
if self.places[discr].value_index.is_none() {
763-
self.places[discr].value_index = Some(self.value_count.into());
764-
self.value_count += 1;
765-
}
766-
}
748+
// Prepend new child to the linked list.
749+
let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant)));
750+
self.places[discr].next_sibling = self.places[place].first_child;
751+
self.places[place].first_child = Some(discr);
752+
let old = self.projections.insert((place, TrackElem::Discriminant), discr);
753+
assert!(old.is_none());
754+
755+
// Allocate a value slot since it doesn't have one.
756+
assert!(self.places[discr].value_index.is_none());
757+
self.places[discr].value_index = Some(self.value_count.into());
758+
self.value_count += 1;
759+
}
760+
761+
if let Some(ref_ty) = ty.builtin_deref(true) && let ty::Slice(..) = ref_ty.ty.kind() {
762+
assert!(self.places[place].value_index.is_none(), "slices are not scalars");
763+
764+
// Prepend new child to the linked list.
765+
let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen)));
766+
self.places[len].next_sibling = self.places[place].first_child;
767+
self.places[place].first_child = Some(len);
768+
769+
let old = self.projections.insert((place, TrackElem::DerefLen), len);
770+
assert!(old.is_none());
771+
772+
// Allocate a value slot since it doesn't have one.
773+
assert!( self.places[len].value_index.is_none() );
774+
self.places[len].value_index = Some(self.value_count.into());
775+
self.value_count += 1;
767776
}
768777

769778
// Recurse with all fields of this place.
770-
iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
779+
iter_fields(ty, tcx, param_env, |variant, field, ty| {
771780
worklist.push_back((
772781
place,
773782
variant.map(TrackElem::Variant),
@@ -834,6 +843,11 @@ impl Map {
834843
self.find_extra(place, [TrackElem::Discriminant])
835844
}
836845

846+
/// Locates the given place and applies `DerefLen`, if it exists in the tree.
847+
pub fn find_len(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
848+
self.find_extra(place, [TrackElem::DerefLen])
849+
}
850+
837851
/// Iterate over all direct children.
838852
pub fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ {
839853
Children::new(self, parent)
@@ -985,6 +999,8 @@ pub enum TrackElem {
985999
Field(FieldIdx),
9861000
Variant(VariantIdx),
9871001
Discriminant,
1002+
// Length of a slice.
1003+
DerefLen,
9881004
}
9891005

9901006
impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
@@ -1124,6 +1140,9 @@ fn debug_with_context_rec<V: Debug + Eq>(
11241140
format!("{}.{}", place_str, field.index())
11251141
}
11261142
}
1143+
TrackElem::DerefLen => {
1144+
format!("Len(*{})", place_str)
1145+
}
11271146
};
11281147
debug_with_context_rec(child, &child_place_str, new, old, map, f)?;
11291148
}

0 commit comments

Comments
 (0)