12
12
//! will still not cause any further changes.
13
13
//!
14
14
15
+ use rustc_index:: bit_set:: DenseBitSet ;
15
16
use rustc_middle:: bug;
16
17
use rustc_middle:: mir:: visit:: Visitor ;
17
18
use rustc_middle:: mir:: * ;
18
19
use rustc_middle:: ty:: TyCtxt ;
19
- use rustc_mir_dataflow:: Analysis ;
20
20
use rustc_mir_dataflow:: debuginfo:: debuginfo_locals;
21
21
use rustc_mir_dataflow:: impls:: {
22
22
LivenessTransferFunction , MaybeTransitiveLiveLocals , borrowed_locals,
23
23
} ;
24
+ use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
24
25
25
26
use crate :: util:: is_within_packed;
26
27
28
+ pub ( crate ) struct DeadStoreAnalysis < ' tcx , ' mir , ' a > {
29
+ live : ResultsCursor < ' mir , ' tcx , MaybeTransitiveLiveLocals < ' a > > ,
30
+ always_live : & ' a DenseBitSet < Local > ,
31
+ }
32
+
33
+ impl < ' tcx , ' mir , ' a > DeadStoreAnalysis < ' tcx , ' mir , ' a > {
34
+ pub ( crate ) fn new (
35
+ tcx : TyCtxt < ' tcx > ,
36
+ body : & ' mir Body < ' tcx > ,
37
+ always_live : & ' a DenseBitSet < Local > ,
38
+ ) -> Self {
39
+ let live = MaybeTransitiveLiveLocals :: new ( & always_live)
40
+ . iterate_to_fixpoint ( tcx, body, None )
41
+ . into_results_cursor ( body) ;
42
+ Self { live, always_live }
43
+ }
44
+
45
+ pub ( crate ) fn is_dead_store ( & mut self , loc : Location , stmt_kind : & StatementKind < ' tcx > ) -> bool {
46
+ if let StatementKind :: Assign ( assign) = stmt_kind {
47
+ if !assign. 1 . is_safe_to_remove ( ) {
48
+ return false ;
49
+ }
50
+ }
51
+ match stmt_kind {
52
+ StatementKind :: Assign ( box ( place, _) )
53
+ | StatementKind :: SetDiscriminant { place : box place, .. }
54
+ | StatementKind :: Deinit ( box place) => {
55
+ if !place. is_indirect ( ) && !self . always_live . contains ( place. local ) {
56
+ self . live . seek_before_primary_effect ( loc) ;
57
+ !self . live . get ( ) . contains ( place. local )
58
+ } else {
59
+ false
60
+ }
61
+ }
62
+
63
+ StatementKind :: Retag ( _, _)
64
+ | StatementKind :: StorageLive ( _)
65
+ | StatementKind :: StorageDead ( _)
66
+ | StatementKind :: Coverage ( _)
67
+ | StatementKind :: Intrinsic ( _)
68
+ | StatementKind :: ConstEvalCounter
69
+ | StatementKind :: PlaceMention ( _)
70
+ | StatementKind :: BackwardIncompatibleDropHint { .. }
71
+ | StatementKind :: Nop => false ,
72
+
73
+ StatementKind :: FakeRead ( _) | StatementKind :: AscribeUserType ( _, _) => {
74
+ bug ! ( "{:?} not found in this MIR phase!" , stmt_kind)
75
+ }
76
+ }
77
+ }
78
+ }
79
+
27
80
/// Performs the optimization on the body
28
81
///
29
82
/// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this
@@ -36,9 +89,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
36
89
let mut always_live = debuginfo_locals ( body) ;
37
90
always_live. union ( & borrowed_locals) ;
38
91
39
- let mut live = MaybeTransitiveLiveLocals :: new ( & always_live)
40
- . iterate_to_fixpoint ( tcx, body, None )
41
- . into_results_cursor ( body) ;
92
+ let mut analysis = DeadStoreAnalysis :: new ( tcx, body, & always_live) ;
42
93
43
94
// For blocks with a call terminator, if an argument copy can be turned into a move,
44
95
// record it as (block, argument index).
@@ -50,8 +101,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
50
101
let loc = Location { block : bb, statement_index : bb_data. statements . len ( ) } ;
51
102
52
103
// Position ourselves between the evaluation of `args` and the write to `destination`.
53
- live. seek_to_block_end ( bb) ;
54
- let mut state = live. get ( ) . clone ( ) ;
104
+ analysis . live . seek_to_block_end ( bb) ;
105
+ let mut state = analysis . live . get ( ) . clone ( ) ;
55
106
56
107
for ( index, arg) in args. iter ( ) . map ( |a| & a. node ) . enumerate ( ) . rev ( ) {
57
108
if let Operand :: Copy ( place) = * arg
@@ -73,38 +124,10 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
73
124
LivenessTransferFunction ( & mut state) . visit_operand ( arg, loc) ;
74
125
}
75
126
}
76
-
77
127
for ( statement_index, statement) in bb_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
78
128
let loc = Location { block : bb, statement_index } ;
79
- if let StatementKind :: Assign ( assign) = & statement. kind {
80
- if !assign. 1 . is_safe_to_remove ( ) {
81
- continue ;
82
- }
83
- }
84
- match & statement. kind {
85
- StatementKind :: Assign ( box ( place, _) )
86
- | StatementKind :: SetDiscriminant { place : box place, .. }
87
- | StatementKind :: Deinit ( box place) => {
88
- if !place. is_indirect ( ) && !always_live. contains ( place. local ) {
89
- live. seek_before_primary_effect ( loc) ;
90
- if !live. get ( ) . contains ( place. local ) {
91
- patch. push ( loc) ;
92
- }
93
- }
94
- }
95
- StatementKind :: Retag ( _, _)
96
- | StatementKind :: StorageLive ( _)
97
- | StatementKind :: StorageDead ( _)
98
- | StatementKind :: Coverage ( _)
99
- | StatementKind :: Intrinsic ( _)
100
- | StatementKind :: ConstEvalCounter
101
- | StatementKind :: PlaceMention ( _)
102
- | StatementKind :: BackwardIncompatibleDropHint { .. }
103
- | StatementKind :: Nop => { }
104
-
105
- StatementKind :: FakeRead ( _) | StatementKind :: AscribeUserType ( _, _) => {
106
- bug ! ( "{:?} not found in this MIR phase!" , statement. kind)
107
- }
129
+ if analysis. is_dead_store ( loc, & statement. kind ) {
130
+ patch. push ( loc) ;
108
131
}
109
132
}
110
133
}
0 commit comments