Skip to content

Commit d0d5f20

Browse files
committed
Reimplement DestinationPropagation according to live ranges.
1 parent a60548a commit d0d5f20

11 files changed

+627
-731
lines changed

compiler/rustc_index/src/interval.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,32 @@ impl<I: Idx> IntervalSet<I> {
219219
})
220220
}
221221

222+
pub fn disjoint(&self, other: &IntervalSet<I>) -> bool
223+
where
224+
I: Step,
225+
{
226+
let helper = move || {
227+
let mut self_iter = self.iter_intervals();
228+
let mut other_iter = other.iter_intervals();
229+
230+
let mut self_current = self_iter.next()?;
231+
let mut other_current = other_iter.next()?;
232+
233+
loop {
234+
if self_current.end <= other_current.start {
235+
self_current = self_iter.next()?;
236+
continue;
237+
}
238+
if other_current.end <= self_current.start {
239+
other_current = other_iter.next()?;
240+
continue;
241+
}
242+
return Some(false);
243+
}
244+
};
245+
helper().unwrap_or(true)
246+
}
247+
222248
pub fn is_empty(&self) -> bool {
223249
self.map.is_empty()
224250
}

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,
Lines changed: 2 additions & 88 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;
3-
use rustc_index::{Idx, IndexSlice, IndexVec};
4-
use rustc_middle::mir::{self, BasicBlock, Body, Location};
5-
6-
use crate::framework::{Analysis, Direction, Results, ResultsVisitor, visit_results};
1+
use rustc_index::{Idx, IndexVec};
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,85 +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, M, A>(
99-
elements: &DenseLocationMap,
100-
body: &mir::Body<'tcx>,
101-
relevant: &IndexSlice<N, M>,
102-
mut analysis: A,
103-
results: Results<A::Domain>,
104-
) -> SparseIntervalMatrix<N, PointIndex>
105-
where
106-
N: Idx,
107-
M: Idx,
108-
A: Analysis<'tcx, Domain = DenseBitSet<M>>,
109-
{
110-
let mut values = SparseIntervalMatrix::new(elements.num_points());
111-
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
112-
if A::Direction::IS_BACKWARD {
113-
// Iterate blocks in decreasing order, to visit locations in decreasing order. This
114-
// allows to use the more efficient `prepend` method to interval sets.
115-
let callback = |state: &DenseBitSet<M>, location| {
116-
let point = elements.point_from_location(location);
117-
for (relevant, &original) in relevant.iter_enumerated() {
118-
if state.contains(original) {
119-
values.prepend(relevant, point);
120-
}
121-
}
122-
};
123-
let mut visitor = Visitor { callback };
124-
visit_results(
125-
body,
126-
// Note the `.rev()`.
127-
body.basic_blocks.indices().filter(|&bb| reachable_blocks.contains(bb)).rev(),
128-
&mut analysis,
129-
&results,
130-
&mut visitor,
131-
);
132-
} else {
133-
// Iterate blocks in increasing order, to visit locations in increasing order. This
134-
// allows to use the more efficient `append` method to interval sets.
135-
let callback = |state: &DenseBitSet<M>, location| {
136-
let point = elements.point_from_location(location);
137-
for (relevant, &original) in relevant.iter_enumerated() {
138-
if state.contains(original) {
139-
values.append(relevant, point);
140-
}
141-
}
142-
};
143-
let mut visitor = Visitor { callback };
144-
visit_results(body, reachable_blocks.iter(), &mut analysis, &results, &mut visitor);
145-
}
146-
values
147-
}
148-
149-
struct Visitor<F> {
150-
callback: F,
151-
}
152-
153-
impl<'tcx, A, F> ResultsVisitor<'tcx, A> for Visitor<F>
154-
where
155-
A: Analysis<'tcx>,
156-
F: FnMut(&A::Domain, Location),
157-
{
158-
fn visit_after_primary_statement_effect<'mir>(
159-
&mut self,
160-
_analysis: &mut A,
161-
state: &A::Domain,
162-
_statement: &'mir mir::Statement<'tcx>,
163-
location: Location,
164-
) {
165-
(self.callback)(state, location);
166-
}
167-
168-
fn visit_after_primary_terminator_effect<'mir>(
169-
&mut self,
170-
_analysis: &mut A,
171-
state: &A::Domain,
172-
_terminator: &'mir mir::Terminator<'tcx>,
173-
location: Location,
174-
) {
175-
(self.callback)(state, location);
176-
}
177-
}

0 commit comments

Comments
 (0)