@@ -146,7 +146,8 @@ use rustc_middle::mir::{
146146};
147147use rustc_middle::ty::TyCtxt;
148148use 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
151152pub 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
359368struct 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 {
810817fn 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