1
1
use std:: iter;
2
2
3
3
use rustc_abi:: Integer ;
4
- use rustc_index:: IndexSlice ;
4
+ use rustc_index:: { IndexSlice , IndexVec } ;
5
+ use rustc_middle:: mir:: visit:: Visitor ;
5
6
use rustc_middle:: mir:: * ;
6
7
use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
7
8
use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
8
9
use tracing:: instrument;
9
10
10
11
use super :: simplify:: simplify_cfg;
12
+ use crate :: dead_store_elimination:: { self , ModifyBasicBlocks } ;
11
13
use crate :: patch:: MirPatch ;
14
+ use crate :: simplify:: strip_nops;
12
15
13
16
pub ( super ) struct MatchBranchSimplification ;
14
17
@@ -20,6 +23,17 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
20
23
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
21
24
let typing_env = body. typing_env ( tcx) ;
22
25
let mut apply_patch = false ;
26
+ let mut bbs = body. basic_blocks . clone ( ) ;
27
+ let bbs = bbs. as_mut_preserves_cfg ( ) ;
28
+ // We can ignore the dead store statements when merging branches.
29
+ dead_store_elimination:: eliminate (
30
+ tcx,
31
+ ModifyBasicBlocks :: BasicBlocks ( body, bbs) ,
32
+ true ,
33
+ false ,
34
+ ) ;
35
+ eliminate_unused_storage_mark ( body, bbs) ;
36
+ strip_nops ( bbs. as_mut_slice ( ) ) ;
23
37
let mut patch = MirPatch :: new ( body) ;
24
38
for ( bb, data) in body. basic_blocks . iter_enumerated ( ) {
25
39
match data. terminator ( ) . kind {
@@ -33,11 +47,17 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
33
47
_ => continue ,
34
48
} ;
35
49
36
- if SimplifyToIf . simplify ( tcx, body, & mut patch, bb, typing_env) . is_some ( ) {
50
+ if SimplifyToIf
51
+ . simplify ( tcx, body, bbs. as_slice ( ) , & mut patch, bb, typing_env)
52
+ . is_some ( )
53
+ {
37
54
apply_patch = true ;
38
55
continue ;
39
56
}
40
- if SimplifyToExp :: default ( ) . simplify ( tcx, body, & mut patch, bb, typing_env) . is_some ( ) {
57
+ if SimplifyToExp :: default ( )
58
+ . simplify ( tcx, body, bbs. as_slice ( ) , & mut patch, bb, typing_env)
59
+ . is_some ( )
60
+ {
41
61
apply_patch = true ;
42
62
continue ;
43
63
}
@@ -62,11 +82,11 @@ trait SimplifyMatch<'tcx> {
62
82
& mut self ,
63
83
tcx : TyCtxt < ' tcx > ,
64
84
body : & Body < ' tcx > ,
85
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
65
86
patch : & mut MirPatch < ' tcx > ,
66
87
switch_bb_idx : BasicBlock ,
67
88
typing_env : ty:: TypingEnv < ' tcx > ,
68
89
) -> Option < ( ) > {
69
- let bbs = & body. basic_blocks ;
70
90
let ( discr, targets) = match bbs[ switch_bb_idx] . terminator ( ) . kind {
71
91
TerminatorKind :: SwitchInt { ref discr, ref targets, .. } => ( discr, targets) ,
72
92
_ => unreachable ! ( ) ,
@@ -83,7 +103,7 @@ trait SimplifyMatch<'tcx> {
83
103
let discr_local = patch. new_temp ( discr_ty, source_info. span ) ;
84
104
85
105
let ( _, first) = targets. iter ( ) . next ( ) . unwrap ( ) ;
86
- let statement_index = bbs [ switch_bb_idx] . statements . len ( ) ;
106
+ let statement_index = body . basic_blocks [ switch_bb_idx] . statements . len ( ) ;
87
107
let parent_end = Location { block : switch_bb_idx, statement_index } ;
88
108
patch. add_statement ( parent_end, StatementKind :: StorageLive ( discr_local) ) ;
89
109
patch. add_assign ( parent_end, Place :: from ( discr_local) , Rvalue :: Use ( discr) ) ;
@@ -526,3 +546,43 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
526
546
}
527
547
}
528
548
}
549
+
550
+ struct EliminateUnusedStorageMark {
551
+ storage_live_locals : IndexVec < Local , Option < usize > > ,
552
+ }
553
+
554
+ impl < ' tcx > Visitor < ' tcx > for EliminateUnusedStorageMark {
555
+ fn visit_local ( & mut self , local : Local , _: visit:: PlaceContext , _: Location ) {
556
+ self . storage_live_locals [ local] = None ;
557
+ }
558
+ }
559
+
560
+ fn eliminate_unused_storage_mark < ' tcx > (
561
+ body : & Body < ' tcx > ,
562
+ basic_blocks : & mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
563
+ ) {
564
+ for ( bb, data) in basic_blocks. iter_enumerated_mut ( ) {
565
+ let mut unused_storage_mark = EliminateUnusedStorageMark {
566
+ storage_live_locals : IndexVec :: from_elem_n ( None , body. local_decls . len ( ) ) ,
567
+ } ;
568
+ for stmt_index in 0 ..data. statements . len ( ) {
569
+ let loc = Location { block : bb, statement_index : stmt_index } ;
570
+ match data. statements [ stmt_index] . kind {
571
+ StatementKind :: StorageLive ( local) => {
572
+ unused_storage_mark. storage_live_locals [ local] = Some ( stmt_index) ;
573
+ }
574
+ StatementKind :: StorageDead ( local)
575
+ if let Some ( live_stmt_index) =
576
+ unused_storage_mark. storage_live_locals [ local] =>
577
+ {
578
+ data. statements [ live_stmt_index] . make_nop ( ) ;
579
+ data. statements [ stmt_index] . make_nop ( ) ;
580
+ unused_storage_mark. storage_live_locals [ local] = None ;
581
+ }
582
+ _ => {
583
+ unused_storage_mark. visit_statement ( & data. statements [ stmt_index] , loc) ;
584
+ }
585
+ }
586
+ }
587
+ }
588
+ }
0 commit comments