@@ -146,7 +146,8 @@ use rustc_middle::mir::{
146
146
} ;
147
147
use rustc_middle:: ty:: TyCtxt ;
148
148
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 ;
150
151
151
152
pub struct DestinationPropagation ;
152
153
@@ -170,6 +171,12 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
170
171
171
172
let borrowed = rustc_mir_dataflow:: impls:: borrowed_locals ( body) ;
172
173
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
+
173
180
// In order to avoid having to collect data for every single pair of locals in the body, we
174
181
// do not allow doing more than one merge for places that are derived from the same local at
175
182
// 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 {
193
200
& mut allocations. candidates_reverse ,
194
201
) ;
195
202
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) ;
201
204
202
205
FilterInformation :: filter_liveness (
203
206
& mut candidates,
@@ -206,9 +209,9 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
206
209
body,
207
210
) ;
208
211
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.
212
215
let mut merged_locals: BitSet < Local > = BitSet :: new_empty ( body. local_decls . len ( ) ) ;
213
216
214
217
// 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 {
227
230
} ) {
228
231
break ;
229
232
}
233
+
234
+ // Replace `src` by `dest` everywhere.
230
235
merges. insert ( * src, * dest) ;
231
236
merged_locals. insert ( * src) ;
232
237
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) ;
233
242
}
234
243
trace ! ( merging = ?merges) ;
235
244
@@ -358,7 +367,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
358
367
359
368
struct FilterInformation < ' a , ' body , ' alloc , ' tcx > {
360
369
body : & ' body Body < ' tcx > ,
361
- live : & ' a mut ResultsCursor < ' body , ' tcx , MaybeLiveLocals > ,
370
+ live : & ' a LivenessValues < Local > ,
362
371
candidates : & ' a mut Candidates < ' alloc > ,
363
372
write_info : & ' alloc mut WriteInfo ,
364
373
at : Location ,
@@ -461,7 +470,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
461
470
/// locals as also being read from.
462
471
fn filter_liveness < ' b > (
463
472
candidates : & mut Candidates < ' alloc > ,
464
- live : & mut ResultsCursor < ' b , ' tcx , MaybeLiveLocals > ,
473
+ live : & LivenessValues < Local > ,
465
474
write_info_alloc : & ' alloc mut WriteInfo ,
466
475
body : & ' b Body < ' tcx > ,
467
476
) {
@@ -481,13 +490,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
481
490
fn internal_filter_liveness ( & mut self ) {
482
491
for ( block, data) in traversal:: preorder ( self . body ) {
483
492
self . at = Location { block, statement_index : data. statements . len ( ) } ;
484
- self . live . seek_after_primary_effect ( self . at ) ;
485
493
self . write_info . for_terminator ( & data. terminator ( ) . kind ) ;
486
494
self . apply_conflicts ( ) ;
487
495
488
496
for ( i, statement) in data. statements . iter ( ) . enumerate ( ) . rev ( ) {
489
497
self . at = Location { block, statement_index : i } ;
490
- self . live . seek_after_primary_effect ( self . at ) ;
491
498
self . write_info . for_statement ( & statement. kind , self . body ) ;
492
499
self . apply_conflicts ( ) ;
493
500
}
@@ -517,7 +524,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
517
524
// calls or inline asm. Because of this, we also mark locals as
518
525
// conflicting when both of them are written to in the same
519
526
// statement.
520
- if self . live . contains ( q) || writes. contains ( & q) {
527
+ if self . live . contains ( q, self . at ) || writes. contains ( & q) {
521
528
CandidateFilter :: Remove
522
529
} else {
523
530
CandidateFilter :: Keep
@@ -810,38 +817,14 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
810
817
fn dest_prop_mir_dump < ' body , ' tcx > (
811
818
tcx : TyCtxt < ' tcx > ,
812
819
body : & ' body Body < ' tcx > ,
813
- live : & mut ResultsCursor < ' body , ' tcx , MaybeLiveLocals > ,
820
+ live : & LivenessValues < Local > ,
814
821
round : usize ,
815
822
) {
816
- let mut reachable = None ;
823
+ let locals_live_at =
824
+ |location| live. rows ( ) . filter ( |& r| live. contains ( r, location) ) . collect :: < Vec < _ > > ( ) ;
817
825
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) ) ?;
845
828
}
846
829
847
830
Ok ( ( ) )
0 commit comments