1212//! will still not cause any further changes.
1313//!
1414
15+ use rustc_index:: bit_set:: DenseBitSet ;
1516use rustc_middle:: bug;
1617use rustc_middle:: mir:: visit:: Visitor ;
1718use rustc_middle:: mir:: * ;
1819use rustc_middle:: ty:: TyCtxt ;
19- use rustc_mir_dataflow:: Analysis ;
2020use rustc_mir_dataflow:: debuginfo:: debuginfo_locals;
2121use rustc_mir_dataflow:: impls:: {
2222 LivenessTransferFunction , MaybeTransitiveLiveLocals , borrowed_locals,
2323} ;
24+ use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
2425
2526use crate :: util:: is_within_packed;
2627
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+
2780/// Performs the optimization on the body
2881///
2982/// 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>) {
3689 let mut always_live = debuginfo_locals ( body) ;
3790 always_live. union ( & borrowed_locals) ;
3891
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) ;
4293
4394 // For blocks with a call terminator, if an argument copy can be turned into a move,
4495 // record it as (block, argument index).
@@ -50,8 +101,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
50101 let loc = Location { block : bb, statement_index : bb_data. statements . len ( ) } ;
51102
52103 // 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 ( ) ;
55106
56107 for ( index, arg) in args. iter ( ) . map ( |a| & a. node ) . enumerate ( ) . rev ( ) {
57108 if let Operand :: Copy ( place) = * arg
@@ -73,38 +124,10 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
73124 LivenessTransferFunction ( & mut state) . visit_operand ( arg, loc) ;
74125 }
75126 }
76-
77127 for ( statement_index, statement) in bb_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
78128 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) ;
108131 }
109132 }
110133 }
0 commit comments