Skip to content

Commit 5b733e2

Browse files
committed
Auto merge of #113316 - DrMeepster:underefer_perf, r=oli-obk
Rewrite `UnDerefer`, again This PR is intended to improve the perf regression introduced by #112882. `UnDerefer` has been separated out again for borrowck reasons. It was a bit overzealous to remove it in the previous PR. r? `@oli-obk`
2 parents fcaf04e + b0dbd60 commit 5b733e2

File tree

6 files changed

+186
-124
lines changed

6 files changed

+186
-124
lines changed

compiler/rustc_borrowck/src/type_check/liveness/polonius.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct UseFactsExtractor<'me, 'tcx> {
2020
}
2121

2222
// A Visitor to walk through the MIR and extract point-wise facts
23-
impl UseFactsExtractor<'_, '_> {
23+
impl<'tcx> UseFactsExtractor<'_, 'tcx> {
2424
fn location_to_index(&self, location: Location) -> LocationIndex {
2525
self.location_table.mid_index(location)
2626
}
@@ -45,7 +45,7 @@ impl UseFactsExtractor<'_, '_> {
4545
self.path_accessed_at_base.push((path, self.location_to_index(location)));
4646
}
4747

48-
fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
48+
fn place_to_mpi(&self, place: &Place<'tcx>) -> Option<MovePathIndex> {
4949
match self.move_data.rev_lookup.find(place.as_ref()) {
5050
LookupResult::Exact(mpi) => Some(mpi),
5151
LookupResult::Parent(mmpi) => mmpi,

compiler/rustc_mir_dataflow/src/impls/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -731,11 +731,11 @@ fn switch_on_enum_discriminant<'mir, 'tcx>(
731731

732732
struct OnMutBorrow<F>(F);
733733

734-
impl<F> Visitor<'_> for OnMutBorrow<F>
734+
impl<'tcx, F> Visitor<'tcx> for OnMutBorrow<F>
735735
where
736-
F: FnMut(&mir::Place<'_>),
736+
F: FnMut(&mir::Place<'tcx>),
737737
{
738-
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
738+
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
739739
// FIXME: Does `&raw const foo` allow mutation? See #90413.
740740
match rvalue {
741741
mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
@@ -756,7 +756,7 @@ where
756756
fn for_each_mut_borrow<'tcx>(
757757
mir: &impl MirVisitable<'tcx>,
758758
location: Location,
759-
f: impl FnMut(&mir::Place<'_>),
759+
f: impl FnMut(&mir::Place<'tcx>),
760760
) {
761761
let mut vis = OnMutBorrow(f);
762762

compiler/rustc_mir_dataflow/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub mod impls;
4343
pub mod move_paths;
4444
pub mod rustc_peek;
4545
pub mod storage;
46+
pub mod un_derefer;
4647
pub mod value_analysis;
4748

4849
fluent_messages! { "../messages.ftl" }

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+66-59
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use rustc_middle::mir::*;
44
use rustc_middle::ty::{self, TyCtxt};
55
use smallvec::{smallvec, SmallVec};
66

7-
use std::iter;
87
use std::mem;
98

109
use super::abs_domain::Lift;
@@ -40,22 +39,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
4039
locals: body
4140
.local_decls
4241
.iter_enumerated()
43-
.filter(|(_, l)| !l.is_deref_temp())
44-
.map(|(i, _)| {
45-
(
46-
i,
42+
.map(|(i, l)| {
43+
if l.is_deref_temp() {
44+
MovePathIndex::MAX
45+
} else {
4746
Self::new_move_path(
4847
&mut move_paths,
4948
&mut path_map,
5049
&mut init_path_map,
5150
None,
5251
Place::from(i),
53-
),
54-
)
52+
)
53+
}
5554
})
5655
.collect(),
5756
projections: Default::default(),
58-
derefer_sidetable: Default::default(),
57+
un_derefer: Default::default(),
5958
},
6059
move_paths,
6160
path_map,
@@ -100,11 +99,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
10099
///
101100
/// Maybe we should have separate "borrowck" and "moveck" modes.
102101
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
103-
let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref());
102+
let data = &mut self.builder.data;
104103

105104
debug!("lookup({:?})", place);
106-
let mut base =
107-
self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local);
105+
let mut base = data.rev_lookup.find_local(place.local);
108106

109107
// The move path index of the first union that we find. Once this is
110108
// some we stop creating child move paths, since moves from unions
@@ -113,55 +111,60 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
113111
// from `*(u.f: &_)` isn't allowed.
114112
let mut union_path = None;
115113

116-
for place in deref_chain.into_iter().chain(iter::once(place)) {
117-
for (place_ref, elem) in place.as_ref().iter_projections() {
118-
let body = self.builder.body;
119-
let tcx = self.builder.tcx;
120-
let place_ty = place_ref.ty(body, tcx).ty;
121-
match place_ty.kind() {
122-
ty::Ref(..) | ty::RawPtr(..) => {
123-
return Err(MoveError::cannot_move_out_of(
124-
self.loc,
125-
BorrowedContent {
126-
target_place: place_ref.project_deeper(&[elem], tcx),
127-
},
128-
));
129-
}
130-
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
131-
return Err(MoveError::cannot_move_out_of(
132-
self.loc,
133-
InteriorOfTypeWithDestructor { container_ty: place_ty },
134-
));
135-
}
136-
ty::Adt(adt, _) if adt.is_union() => {
137-
union_path.get_or_insert(base);
138-
}
139-
ty::Slice(_) => {
114+
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
115+
let body = self.builder.body;
116+
let tcx = self.builder.tcx;
117+
let place_ty = place_ref.ty(body, tcx).ty;
118+
match place_ty.kind() {
119+
ty::Ref(..) | ty::RawPtr(..) => {
120+
return Err(MoveError::cannot_move_out_of(
121+
self.loc,
122+
BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
123+
));
124+
}
125+
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
126+
return Err(MoveError::cannot_move_out_of(
127+
self.loc,
128+
InteriorOfTypeWithDestructor { container_ty: place_ty },
129+
));
130+
}
131+
ty::Adt(adt, _) if adt.is_union() => {
132+
union_path.get_or_insert(base);
133+
}
134+
ty::Slice(_) => {
135+
return Err(MoveError::cannot_move_out_of(
136+
self.loc,
137+
InteriorOfSliceOrArray {
138+
ty: place_ty,
139+
is_index: matches!(elem, ProjectionElem::Index(..)),
140+
},
141+
));
142+
}
143+
144+
ty::Array(..) => {
145+
if let ProjectionElem::Index(..) = elem {
140146
return Err(MoveError::cannot_move_out_of(
141147
self.loc,
142-
InteriorOfSliceOrArray {
143-
ty: place_ty,
144-
is_index: matches!(elem, ProjectionElem::Index(..)),
145-
},
148+
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
146149
));
147150
}
151+
}
148152

149-
ty::Array(..) => {
150-
if let ProjectionElem::Index(..) = elem {
151-
return Err(MoveError::cannot_move_out_of(
152-
self.loc,
153-
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
154-
));
155-
}
156-
}
157-
158-
_ => {}
159-
};
153+
_ => {}
154+
};
160155

161-
if union_path.is_none() {
162-
base = self
163-
.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
164-
}
156+
if union_path.is_none() {
157+
// inlined from add_move_path because of a borrowck conflict with the iterator
158+
base =
159+
*data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| {
160+
MoveDataBuilder::new_move_path(
161+
&mut data.move_paths,
162+
&mut data.path_map,
163+
&mut data.init_path_map,
164+
Some(base),
165+
place_ref.project_deeper(&[elem], tcx),
166+
)
167+
})
165168
}
166169
}
167170

@@ -282,10 +285,14 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
282285
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
283286
match &stmt.kind {
284287
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
285-
assert!(place.projection.is_empty());
286-
if self.builder.body.local_decls[place.local].is_deref_temp() {
287-
self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed);
288-
}
288+
let local = place.as_local().unwrap();
289+
assert!(self.builder.body.local_decls[local].is_deref_temp());
290+
291+
let rev_lookup = &mut self.builder.data.rev_lookup;
292+
293+
rev_lookup.un_derefer.insert(local, reffed.as_ref());
294+
let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local;
295+
rev_lookup.locals[local] = rev_lookup.locals[base_local];
289296
}
290297
StatementKind::Assign(box (place, rval)) => {
291298
self.create_move_path(*place);
@@ -306,7 +313,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
306313
StatementKind::StorageLive(_) => {}
307314
StatementKind::StorageDead(local) => {
308315
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
309-
if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) {
316+
if !self.builder.body.local_decls[*local].is_deref_temp() {
310317
self.gather_move(Place::from(*local));
311318
}
312319
}

compiler/rustc_mir_dataflow/src/move_paths/mod.rs

+13-59
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::move_paths::builder::MoveDat;
2-
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
2+
use crate::un_derefer::UnDerefer;
3+
use rustc_data_structures::fx::FxHashMap;
34
use rustc_index::{IndexSlice, IndexVec};
45
use rustc_middle::mir::*;
56
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
@@ -290,7 +291,7 @@ impl Init {
290291
/// Tables mapping from a place to its MovePathIndex.
291292
#[derive(Debug)]
292293
pub struct MovePathLookup<'tcx> {
293-
locals: FxIndexMap<Local, MovePathIndex>,
294+
locals: IndexVec<Local, MovePathIndex>,
294295

295296
/// projections are made from a base-place and a projection
296297
/// elem. The base-place will have a unique MovePathIndex; we use
@@ -300,8 +301,7 @@ pub struct MovePathLookup<'tcx> {
300301
/// elem to the associated MovePathIndex.
301302
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
302303

303-
/// Maps `DerefTemp` locals to the `Place`s assigned to them.
304-
derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
304+
un_derefer: UnDerefer<'tcx>,
305305
}
306306

307307
mod builder;
@@ -317,77 +317,31 @@ impl<'tcx> MovePathLookup<'tcx> {
317317
// alternative will *not* create a MovePath on the fly for an
318318
// unknown place, but will rather return the nearest available
319319
// parent.
320-
pub fn find(&self, place: PlaceRef<'_>) -> LookupResult {
321-
let deref_chain = self.deref_chain(place);
320+
pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult {
321+
let mut result = self.find_local(place.local);
322322

323-
let local = match deref_chain.first() {
324-
Some(place) => place.local,
325-
None => place.local,
326-
};
327-
328-
let mut result = *self.locals.get(&local).unwrap_or_else(|| {
329-
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
330-
});
331-
332-
// this needs to be a closure because `place` has a different lifetime than `prefix`'s places
333-
let mut subpaths_for_place = |place: PlaceRef<'_>| {
334-
for elem in place.projection.iter() {
335-
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
336-
result = subpath;
337-
} else {
338-
return Some(result);
339-
}
340-
}
341-
None
342-
};
343-
344-
for place in deref_chain {
345-
if let Some(result) = subpaths_for_place(place.as_ref()) {
323+
for (_, elem) in self.un_derefer.iter_projections(place) {
324+
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
325+
result = subpath;
326+
} else {
346327
return LookupResult::Parent(Some(result));
347328
}
348329
}
349330

350-
if let Some(result) = subpaths_for_place(place) {
351-
return LookupResult::Parent(Some(result));
352-
}
353-
354331
LookupResult::Exact(result)
355332
}
356333

334+
#[inline]
357335
pub fn find_local(&self, local: Local) -> MovePathIndex {
358-
let deref_chain = self.deref_chain(Place::from(local).as_ref());
359-
360-
let local = match deref_chain.last() {
361-
Some(place) => place.local,
362-
None => local,
363-
};
364-
365-
*self.locals.get(&local).unwrap_or_else(|| {
366-
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
367-
})
336+
self.locals[local]
368337
}
369338

370339
/// An enumerated iterator of `local`s and their associated
371340
/// `MovePathIndex`es.
372341
pub fn iter_locals_enumerated(
373342
&self,
374343
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
375-
self.locals.iter().map(|(&l, &idx)| (l, idx))
376-
}
377-
378-
/// Returns the chain of places behind `DerefTemp` locals in `place`
379-
pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> {
380-
let mut prefix = Vec::new();
381-
let mut local = place.local;
382-
383-
while let Some(&reffed) = self.derefer_sidetable.get(&local) {
384-
prefix.insert(0, reffed);
385-
local = reffed.local;
386-
}
387-
388-
debug!("deref_chain({place:?}) = {prefix:?}");
389-
390-
prefix
344+
self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
391345
}
392346
}
393347

0 commit comments

Comments
 (0)