Skip to content

Commit 4877167

Browse files
committed
Do not recompute liveness for DestinationPropagation.
1 parent 23e2853 commit 4877167

File tree

2 files changed

+90
-44
lines changed

2 files changed

+90
-44
lines changed

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

+64-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
2+
use rustc_index::bit_set::ChunkedBitSet;
13
use rustc_index::interval::IntervalSet;
24
use rustc_index::interval::SparseIntervalMatrix;
35
use rustc_index::Idx;
46
use rustc_index::IndexVec;
5-
use rustc_middle::mir::{BasicBlock, Body, Location};
7+
use rustc_middle::mir::{self, BasicBlock, Body, Location};
68
use std::rc::Rc;
79

810
/// Maps between a `Location` and a `PointIndex` (and vice versa).
@@ -162,4 +164,65 @@ impl<N: Idx> LivenessValues<N> {
162164
pub fn get_intervals(&self, region: N) -> Option<&IntervalSet<PointIndex>> {
163165
self.points.row(region)
164166
}
167+
168+
/// Insert all the elements from the `src` region into the `dest` region.
169+
pub fn union_regions(&mut self, src: N, dest: N) {
170+
self.points.union_rows(src, dest);
171+
}
172+
173+
/// Add points depending on the result of the given dataflow analysis.
174+
pub fn fill_from_dataflow<'tcx, R>(body: &mir::Body<'tcx>, mut results: R) -> Self
175+
where
176+
R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet<N>>,
177+
{
178+
let elements = Rc::new(DenseLocationMap::new(body));
179+
let values = Self::new(elements);
180+
let mut visitor = Visitor { values };
181+
visit_results(
182+
body,
183+
body.basic_blocks.reverse_postorder().iter().copied(),
184+
&mut results,
185+
&mut visitor,
186+
);
187+
visitor.values
188+
}
189+
}
190+
191+
struct Visitor<N: Idx> {
192+
values: LivenessValues<N>,
193+
}
194+
195+
impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<N>
196+
where
197+
N: Idx,
198+
{
199+
type FlowState = ChunkedBitSet<N>;
200+
201+
fn visit_statement_after_primary_effect(
202+
&mut self,
203+
_results: &mut R,
204+
state: &Self::FlowState,
205+
_statement: &'mir mir::Statement<'tcx>,
206+
location: Location,
207+
) {
208+
let point = self.values.elements.point_from_location(location);
209+
// Use internal iterator manually as it is much more efficient.
210+
state.iter().fold((), |(), node| {
211+
self.values.points.insert(node, point);
212+
});
213+
}
214+
215+
fn visit_terminator_after_primary_effect(
216+
&mut self,
217+
_results: &mut R,
218+
state: &Self::FlowState,
219+
_terminator: &'mir mir::Terminator<'tcx>,
220+
location: Location,
221+
) {
222+
let point = self.values.elements.point_from_location(location);
223+
// Use internal iterator manually as it is much more efficient.
224+
state.iter().fold((), |(), node| {
225+
self.values.points.insert(node, point);
226+
});
227+
}
165228
}

Diff for: compiler/rustc_mir_transform/src/dest_prop.rs

+26-43
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ use rustc_middle::mir::{
146146
};
147147
use rustc_middle::ty::TyCtxt;
148148
use rustc_mir_dataflow::impls::MaybeLiveLocals;
149-
use rustc_mir_dataflow::{Analysis, ResultsCursor};
149+
use rustc_mir_dataflow::points::LivenessValues;
150+
use rustc_mir_dataflow::Analysis;
150151

151152
pub struct DestinationPropagation;
152153

@@ -170,6 +171,12 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
170171

171172
let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
172173

174+
let live = MaybeLiveLocals
175+
.into_engine(tcx, body)
176+
.pass_name("MaybeLiveLocals-DestinationPropagation")
177+
.iterate_to_fixpoint();
178+
let mut live = LivenessValues::fill_from_dataflow(body, live);
179+
173180
// In order to avoid having to collect data for every single pair of locals in the body, we
174181
// do not allow doing more than one merge for places that are derived from the same local at
175182
// once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to
@@ -193,11 +200,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
193200
&mut allocations.candidates_reverse,
194201
);
195202
trace!(?candidates);
196-
let mut live = MaybeLiveLocals
197-
.into_engine(tcx, body)
198-
.iterate_to_fixpoint()
199-
.into_results_cursor(body);
200-
dest_prop_mir_dump(tcx, body, &mut live, round_count);
203+
dest_prop_mir_dump(tcx, body, &live, round_count);
201204

202205
FilterInformation::filter_liveness(
203206
&mut candidates,
@@ -206,9 +209,9 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
206209
body,
207210
);
208211

209-
// Because we do not update liveness information, it is unsound to use a local for more
210-
// than one merge operation within a single round of optimizations. We store here which
211-
// ones we have already used.
212+
// Because we only filter once per round, it is unsound to use a local for more than
213+
// one merge operation within a single round of optimizations. We store here which ones
214+
// we have already used.
212215
let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len());
213216

214217
// This is the set of merges we will apply this round. It is a subset of the candidates.
@@ -227,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
227230
}) {
228231
break;
229232
}
233+
234+
// Replace `src` by `dest` everywhere.
230235
merges.insert(*src, *dest);
231236
merged_locals.insert(*src);
232237
merged_locals.insert(*dest);
238+
239+
// Update liveness information based on the merge we just performed.
240+
// Every location where `src` was live, `dest` will be live.
241+
live.union_regions(*src, *dest);
233242
}
234243
trace!(merging = ?merges);
235244

@@ -358,7 +367,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
358367

359368
struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
360369
body: &'body Body<'tcx>,
361-
live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
370+
live: &'a LivenessValues<Local>,
362371
candidates: &'a mut Candidates<'alloc>,
363372
write_info: &'alloc mut WriteInfo,
364373
at: Location,
@@ -461,7 +470,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
461470
/// locals as also being read from.
462471
fn filter_liveness<'b>(
463472
candidates: &mut Candidates<'alloc>,
464-
live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>,
473+
live: &LivenessValues<Local>,
465474
write_info_alloc: &'alloc mut WriteInfo,
466475
body: &'b Body<'tcx>,
467476
) {
@@ -481,13 +490,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
481490
fn internal_filter_liveness(&mut self) {
482491
for (block, data) in traversal::preorder(self.body) {
483492
self.at = Location { block, statement_index: data.statements.len() };
484-
self.live.seek_after_primary_effect(self.at);
485493
self.write_info.for_terminator(&data.terminator().kind);
486494
self.apply_conflicts();
487495

488496
for (i, statement) in data.statements.iter().enumerate().rev() {
489497
self.at = Location { block, statement_index: i };
490-
self.live.seek_after_primary_effect(self.at);
491498
self.write_info.for_statement(&statement.kind, self.body);
492499
self.apply_conflicts();
493500
}
@@ -517,7 +524,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
517524
// calls or inline asm. Because of this, we also mark locals as
518525
// conflicting when both of them are written to in the same
519526
// statement.
520-
if self.live.contains(q) || writes.contains(&q) {
527+
if self.live.contains(q, self.at) || writes.contains(&q) {
521528
CandidateFilter::Remove
522529
} else {
523530
CandidateFilter::Keep
@@ -810,38 +817,14 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
810817
fn dest_prop_mir_dump<'body, 'tcx>(
811818
tcx: TyCtxt<'tcx>,
812819
body: &'body Body<'tcx>,
813-
live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
820+
live: &LivenessValues<Local>,
814821
round: usize,
815822
) {
816-
let mut reachable = None;
823+
let locals_live_at =
824+
|location| live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>();
817825
dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
818-
let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
819-
820-
match pass_where {
821-
PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
822-
live.seek_after_primary_effect(loc);
823-
writeln!(w, " // live: {:?}", live.get())?;
824-
}
825-
PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
826-
let loc = body.terminator_loc(bb);
827-
live.seek_before_primary_effect(loc);
828-
writeln!(w, " // live: {:?}", live.get())?;
829-
}
830-
831-
PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
832-
live.seek_to_block_start(bb);
833-
writeln!(w, " // live: {:?}", live.get())?;
834-
}
835-
836-
PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
837-
838-
PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
839-
writeln!(w, " // live: <unreachable>")?;
840-
}
841-
842-
PassWhere::BeforeBlock(_) => {
843-
writeln!(w, " // live: <unreachable>")?;
844-
}
826+
if let PassWhere::BeforeLocation(loc) = pass_where {
827+
writeln!(w, " // live: {:?}", locals_live_at(loc))?;
845828
}
846829

847830
Ok(())

0 commit comments

Comments
 (0)