1
- use crate :: transform:: { simplify , MirPass , MirSource } ;
1
+ use crate :: transform:: { MirPass , MirSource } ;
2
2
use rustc_middle:: mir:: * ;
3
3
use rustc_middle:: ty:: TyCtxt ;
4
4
@@ -12,71 +12,63 @@ pub struct MatchBranchSimplification;
12
12
impl < ' tcx > MirPass < ' tcx > for MatchBranchSimplification {
13
13
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , src : MirSource < ' tcx > , body : & mut Body < ' tcx > ) {
14
14
let param_env = tcx. param_env ( src. def_id ( ) ) ;
15
- let mut did_remove_blocks = false ;
16
15
let bbs = body. basic_blocks_mut ( ) ;
17
16
' outer: for bb_idx in bbs. indices ( ) {
18
- let ( discr, val, switch_ty, targets ) = match bbs[ bb_idx] . terminator ( ) . kind {
17
+ let ( discr, val, switch_ty, first , second ) = match bbs[ bb_idx] . terminator ( ) . kind {
19
18
TerminatorKind :: SwitchInt {
20
19
discr : Operand :: Move ( ref place) ,
21
20
switch_ty,
22
21
ref targets,
23
22
ref values,
24
23
..
25
24
} if targets. len ( ) == 2 && values. len ( ) == 1 => {
26
- ( place. clone ( ) , values[ 0 ] , switch_ty, targets)
25
+ ( place, values[ 0 ] , switch_ty, targets[ 0 ] , targets [ 1 ] )
27
26
}
27
+ // Only optimize switch int statements
28
28
_ => continue ,
29
29
} ;
30
- let ( first, rest) = if let ( [ first] , rest) = targets. split_at ( 1 ) {
31
- ( * first, rest)
32
- } else {
33
- unreachable ! ( ) ;
34
- } ;
35
- let first_dest = bbs[ first] . terminator ( ) . kind . clone ( ) ;
36
- let same_destinations = rest
37
- . iter ( )
38
- . map ( |target| & bbs[ * target] . terminator ( ) . kind )
39
- . all ( |t_kind| t_kind == & first_dest) ;
40
- if !same_destinations {
30
+
31
+ // Check that destinations are identical, and if not, then don't optimize this block
32
+ if & bbs[ first] . terminator ( ) . kind != & bbs[ second] . terminator ( ) . kind {
41
33
continue ;
42
34
}
35
+
36
+ // Check that blocks are assignments of consts to the same place or same statement,
37
+ // and match up 1-1, if not don't optimize this block.
43
38
let first_stmts = & bbs[ first] . statements ;
44
- for s in first_stmts. iter ( ) {
45
- match & s. kind {
46
- StatementKind :: Assign ( box ( _, rhs) ) => {
47
- if let Rvalue :: Use ( Operand :: Constant ( _) ) = rhs {
48
- } else {
49
- continue ' outer;
50
- }
51
- }
52
- _ => continue ' outer,
53
- }
39
+ let scnd_stmts = & bbs[ second] . statements ;
40
+ if first_stmts. len ( ) != scnd_stmts. len ( ) {
41
+ continue ;
54
42
}
55
- for target in rest . iter ( ) {
56
- for s in bbs [ * target ] . statements . iter ( ) {
57
- if let StatementKind :: Assign ( box ( ref lhs , rhs ) ) = & s . kind {
58
- if let Rvalue :: Use ( Operand :: Constant ( _ ) ) = rhs {
59
- let has_matching_assn = first_stmts
60
- . iter ( )
61
- . find ( |s| {
62
- if let StatementKind :: Assign ( box ( lhs_f , _ ) ) = & s . kind {
63
- lhs_f == lhs
64
- } else {
65
- false
66
- }
67
- } )
68
- . is_some ( ) ;
69
- if has_matching_assn {
70
- continue ;
43
+ for ( f , s ) in first_stmts . iter ( ) . zip ( scnd_stmts . iter ( ) ) {
44
+ match ( & f . kind , & s . kind ) {
45
+ // If two statements are exactly the same just ignore them.
46
+ ( f_s , s_s ) if f_s == s_s => ( ) ,
47
+
48
+ (
49
+ StatementKind :: Assign ( box ( lhs_f , Rvalue :: Use ( Operand :: Constant ( f_c ) ) ) ) ,
50
+ StatementKind :: Assign ( box ( lhs_s , Rvalue :: Use ( Operand :: Constant ( s_c ) ) ) ) ,
51
+ ) if lhs_f == lhs_s => {
52
+ if let Some ( f_c ) = f_c . literal . try_eval_bool ( tcx , param_env ) {
53
+ // This should also be a bool because it's writing to the same place
54
+ let s_c = s_c . literal . try_eval_bool ( tcx , param_env ) . unwrap ( ) ;
55
+ // Check that only const assignments of opposite bool values are
56
+ // permitted.
57
+ if f_c != s_c {
58
+ continue
71
59
}
72
60
}
61
+ continue ' outer;
73
62
}
74
-
75
- continue ' outer;
63
+ // If there are not exclusively assignments, then ignore this
64
+ _ => continue ' outer,
76
65
}
77
66
}
78
- let ( first_block, to_add) = bbs. pick2_mut ( first, bb_idx) ;
79
- let new_stmts = first_block. statements . iter ( ) . cloned ( ) . map ( |mut s| {
67
+ // Take owenership of items now that we know we can optimize.
68
+ let discr = discr. clone ( ) ;
69
+
70
+ bbs[ bb_idx] . terminator_mut ( ) . kind = TerminatorKind :: Goto { target : first } ;
71
+ for s in bbs[ first] . statements . iter_mut ( ) {
80
72
if let StatementKind :: Assign ( box ( _, ref mut rhs) ) = s. kind {
81
73
let size = tcx. layout_of ( param_env. and ( switch_ty) ) . unwrap ( ) . size ;
82
74
let const_cmp = Operand :: const_from_scalar (
@@ -86,17 +78,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
86
78
rustc_span:: DUMMY_SP ,
87
79
) ;
88
80
* rhs = Rvalue :: BinaryOp ( BinOp :: Eq , Operand :: Move ( discr) , const_cmp) ;
89
- } else {
90
- unreachable ! ( )
91
81
}
92
- s
93
- } ) ;
94
- to_add. statements . extend ( new_stmts) ;
95
- to_add. terminator_mut ( ) . kind = first_dest;
96
- did_remove_blocks = true ;
97
- }
98
- if did_remove_blocks {
99
- simplify:: remove_dead_blocks ( body) ;
82
+ }
100
83
}
101
84
}
102
85
}
0 commit comments