Skip to content

Commit 83ece2f

Browse files
Auto merge of #145541 - cjgillot:dest-prop-live-range, r=<try>
Reimplement DestinationPropagation according to live ranges.
2 parents 3776358 + 808ce08 commit 83ece2f

File tree

33 files changed

+981
-1486
lines changed

33 files changed

+981
-1486
lines changed

compiler/rustc_index/src/interval.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,30 @@ impl<I: Idx> IntervalSet<I> {
140140
result
141141
}
142142

143+
/// Specialized version of `insert` when we know that the inserted point is *after* any
144+
/// contained.
145+
pub fn append(&mut self, point: I) {
146+
let point = point.index() as u32;
147+
148+
if let Some((_, last_end)) = self.map.last_mut() {
149+
assert!(*last_end <= point);
150+
if point == *last_end {
151+
// The point is already in the set.
152+
} else if point == *last_end + 1 {
153+
*last_end = point;
154+
} else {
155+
self.map.push((point, point));
156+
}
157+
} else {
158+
self.map.push((point, point));
159+
}
160+
161+
debug_assert!(
162+
self.check_invariants(),
163+
"wrong intervals after append {point:?} to {self:?}"
164+
);
165+
}
166+
143167
pub fn contains(&self, needle: I) -> bool {
144168
let needle = needle.index() as u32;
145169
let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
@@ -176,6 +200,32 @@ impl<I: Idx> IntervalSet<I> {
176200
})
177201
}
178202

203+
pub fn disjoint(&self, other: &IntervalSet<I>) -> bool
204+
where
205+
I: Step,
206+
{
207+
let helper = move || {
208+
let mut self_iter = self.iter_intervals();
209+
let mut other_iter = other.iter_intervals();
210+
211+
let mut self_current = self_iter.next()?;
212+
let mut other_current = other_iter.next()?;
213+
214+
loop {
215+
if self_current.end <= other_current.start {
216+
self_current = self_iter.next()?;
217+
continue;
218+
}
219+
if other_current.end <= self_current.start {
220+
other_current = other_iter.next()?;
221+
continue;
222+
}
223+
return Some(false);
224+
}
225+
};
226+
helper().unwrap_or(true)
227+
}
228+
179229
pub fn is_empty(&self) -> bool {
180230
self.map.is_empty()
181231
}
@@ -325,6 +375,10 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
325375
self.ensure_row(row).insert(point)
326376
}
327377

378+
pub fn append(&mut self, row: R, point: C) {
379+
self.ensure_row(row).append(point)
380+
}
381+
328382
pub fn contains(&self, row: R, point: C) -> bool {
329383
self.row(row).is_some_and(|r| r.contains(point))
330384
}

compiler/rustc_mir_dataflow/src/impls/liveness.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_> {
9292
}
9393

9494
match DefUse::for_place(*place, context) {
95-
Some(DefUse::Def) => {
95+
DefUse::Def => {
9696
if let PlaceContext::MutatingUse(
9797
MutatingUseContext::Call | MutatingUseContext::AsmOutput,
9898
) = context
@@ -105,8 +105,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_> {
105105
self.0.kill(place.local);
106106
}
107107
}
108-
Some(DefUse::Use) => self.0.gen_(place.local),
109-
None => {}
108+
DefUse::Use => self.0.gen_(place.local),
109+
DefUse::PartialWrite | DefUse::NonUse => {}
110110
}
111111

112112
self.visit_projection(place.as_ref(), context, location);
@@ -131,23 +131,29 @@ impl<'tcx> Visitor<'tcx> for YieldResumeEffect<'_> {
131131
}
132132

133133
#[derive(Eq, PartialEq, Clone)]
134-
enum DefUse {
134+
pub enum DefUse {
135+
/// Full write to the local.
135136
Def,
137+
/// Read of any part of the local.
136138
Use,
139+
/// Partial write to the local.
140+
PartialWrite,
141+
/// Non-use, like debuginfo.
142+
NonUse,
137143
}
138144

139145
impl DefUse {
140146
fn apply(state: &mut DenseBitSet<Local>, place: Place<'_>, context: PlaceContext) {
141147
match DefUse::for_place(place, context) {
142-
Some(DefUse::Def) => state.kill(place.local),
143-
Some(DefUse::Use) => state.gen_(place.local),
144-
None => {}
148+
DefUse::Def => state.kill(place.local),
149+
DefUse::Use => state.gen_(place.local),
150+
DefUse::PartialWrite | DefUse::NonUse => {}
145151
}
146152
}
147153

148-
fn for_place(place: Place<'_>, context: PlaceContext) -> Option<DefUse> {
154+
pub fn for_place(place: Place<'_>, context: PlaceContext) -> DefUse {
149155
match context {
150-
PlaceContext::NonUse(_) => None,
156+
PlaceContext::NonUse(_) => DefUse::NonUse,
151157

152158
PlaceContext::MutatingUse(
153159
MutatingUseContext::Call
@@ -156,21 +162,20 @@ impl DefUse {
156162
| MutatingUseContext::Store
157163
| MutatingUseContext::Deinit,
158164
) => {
165+
// Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
159166
if place.is_indirect() {
160-
// Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a
161-
// use.
162-
Some(DefUse::Use)
167+
DefUse::Use
163168
} else if place.projection.is_empty() {
164-
Some(DefUse::Def)
169+
DefUse::Def
165170
} else {
166-
None
171+
DefUse::PartialWrite
167172
}
168173
}
169174

170175
// Setting the discriminant is not a use because it does no reading, but it is also not
171176
// a def because it does not overwrite the whole place
172177
PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => {
173-
place.is_indirect().then_some(DefUse::Use)
178+
if place.is_indirect() { DefUse::Use } else { DefUse::PartialWrite }
174179
}
175180

176181
// All other contexts are uses...
@@ -188,7 +193,7 @@ impl DefUse {
188193
| NonMutatingUseContext::PlaceMention
189194
| NonMutatingUseContext::FakeBorrow
190195
| NonMutatingUseContext::SharedBorrow,
191-
) => Some(DefUse::Use),
196+
) => DefUse::Use,
192197

193198
PlaceContext::MutatingUse(MutatingUseContext::Projection)
194199
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {

compiler/rustc_mir_dataflow/src/impls/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ pub use self::initialized::{
99
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
1010
};
1111
pub use self::liveness::{
12-
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
12+
DefUse, MaybeLiveLocals, MaybeTransitiveLiveLocals,
13+
TransferFunction as LivenessTransferFunction,
1314
};
1415
pub use self::storage_liveness::{
1516
MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive, always_storage_live_locals,

compiler/rustc_mir_dataflow/src/points.rs

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
use rustc_index::bit_set::DenseBitSet;
2-
use rustc_index::interval::SparseIntervalMatrix;
31
use rustc_index::{Idx, IndexVec};
4-
use rustc_middle::mir::{self, BasicBlock, Body, Location};
5-
6-
use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
2+
use rustc_middle::mir::{BasicBlock, Body, Location};
73

84
/// Maps between a `Location` and a `PointIndex` (and vice versa).
95
pub struct DenseLocationMap {
@@ -93,65 +89,3 @@ rustc_index::newtype_index! {
9389
#[debug_format = "PointIndex({})"]
9490
pub struct PointIndex {}
9591
}
96-
97-
/// Add points depending on the result of the given dataflow analysis.
98-
pub fn save_as_intervals<'tcx, N, A>(
99-
elements: &DenseLocationMap,
100-
body: &mir::Body<'tcx>,
101-
mut analysis: A,
102-
results: Results<A::Domain>,
103-
) -> SparseIntervalMatrix<N, PointIndex>
104-
where
105-
N: Idx,
106-
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
107-
{
108-
let values = SparseIntervalMatrix::new(elements.num_points());
109-
let mut visitor = Visitor { elements, values };
110-
visit_results(
111-
body,
112-
body.basic_blocks.reverse_postorder().iter().copied(),
113-
&mut analysis,
114-
&results,
115-
&mut visitor,
116-
);
117-
visitor.values
118-
}
119-
120-
struct Visitor<'a, N: Idx> {
121-
elements: &'a DenseLocationMap,
122-
values: SparseIntervalMatrix<N, PointIndex>,
123-
}
124-
125-
impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N>
126-
where
127-
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
128-
N: Idx,
129-
{
130-
fn visit_after_primary_statement_effect<'mir>(
131-
&mut self,
132-
_analysis: &mut A,
133-
state: &A::Domain,
134-
_statement: &'mir mir::Statement<'tcx>,
135-
location: Location,
136-
) {
137-
let point = self.elements.point_from_location(location);
138-
// Use internal iterator manually as it is much more efficient.
139-
state.iter().for_each(|node| {
140-
self.values.insert(node, point);
141-
});
142-
}
143-
144-
fn visit_after_primary_terminator_effect<'mir>(
145-
&mut self,
146-
_analysis: &mut A,
147-
state: &A::Domain,
148-
_terminator: &'mir mir::Terminator<'tcx>,
149-
location: Location,
150-
) {
151-
let point = self.elements.point_from_location(location);
152-
// Use internal iterator manually as it is much more efficient.
153-
state.iter().for_each(|node| {
154-
self.values.insert(node, point);
155-
});
156-
}
157-
}

0 commit comments

Comments
 (0)