1
- use rustc_index:: IndexVec ;
1
+ use rustc_index:: IndexSlice ;
2
+ use rustc_middle:: mir:: patch:: MirPatch ;
2
3
use rustc_middle:: mir:: * ;
3
4
use rustc_middle:: ty:: { ParamEnv , ScalarInt , Ty , TyCtxt } ;
4
5
use std:: iter;
@@ -16,9 +17,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
16
17
let def_id = body. source . def_id ( ) ;
17
18
let param_env = tcx. param_env_reveal_all_normalized ( def_id) ;
18
19
19
- let bbs = body. basic_blocks . as_mut ( ) ;
20
20
let mut should_cleanup = false ;
21
- for bb_idx in bbs. indices ( ) {
21
+ for i in 0 ..body. basic_blocks . len ( ) {
22
+ let bbs = & * body. basic_blocks ;
23
+ let bb_idx = BasicBlock :: from_usize ( i) ;
22
24
if !tcx. consider_optimizing ( || format ! ( "MatchBranchSimplification {def_id:?} " ) ) {
23
25
continue ;
24
26
}
@@ -34,12 +36,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
34
36
_ => continue ,
35
37
} ;
36
38
37
- if SimplifyToIf . simplify ( tcx, & mut body. local_decls , bbs , bb_idx, param_env) {
39
+ if SimplifyToIf . simplify ( tcx, body, bb_idx, param_env) {
38
40
should_cleanup = true ;
39
41
continue ;
40
42
}
41
- if SimplifyToExp :: default ( ) . simplify ( tcx, & mut body. local_decls , bbs, bb_idx, param_env)
42
- {
43
+ if SimplifyToExp :: default ( ) . simplify ( tcx, body, bb_idx, param_env) {
43
44
should_cleanup = true ;
44
45
continue ;
45
46
}
@@ -57,43 +58,41 @@ trait SimplifyMatch<'tcx> {
57
58
fn simplify (
58
59
& mut self ,
59
60
tcx : TyCtxt < ' tcx > ,
60
- local_decls : & mut IndexVec < Local , LocalDecl < ' tcx > > ,
61
- bbs : & mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
61
+ body : & mut Body < ' tcx > ,
62
62
switch_bb_idx : BasicBlock ,
63
63
param_env : ParamEnv < ' tcx > ,
64
64
) -> bool {
65
+ let bbs = & body. basic_blocks ;
65
66
let ( discr, targets) = match bbs[ switch_bb_idx] . terminator ( ) . kind {
66
67
TerminatorKind :: SwitchInt { ref discr, ref targets, .. } => ( discr, targets) ,
67
68
_ => unreachable ! ( ) ,
68
69
} ;
69
70
70
- let discr_ty = discr. ty ( local_decls, tcx) ;
71
+ let discr_ty = discr. ty ( body . local_decls ( ) , tcx) ;
71
72
if !self . can_simplify ( tcx, targets, param_env, bbs, discr_ty) {
72
73
return false ;
73
74
}
74
75
76
+ let mut patch = MirPatch :: new ( body) ;
77
+
75
78
// Take ownership of items now that we know we can optimize.
76
79
let discr = discr. clone ( ) ;
77
80
78
81
// Introduce a temporary for the discriminant value.
79
82
let source_info = bbs[ switch_bb_idx] . terminator ( ) . source_info ;
80
- let discr_local = local_decls . push ( LocalDecl :: new ( discr_ty, source_info. span ) ) ;
83
+ let discr_local = patch . new_temp ( discr_ty, source_info. span ) ;
81
84
82
85
// We already checked that targets are different blocks,
83
86
// and bb_idx has a different terminator from both of them.
84
- let new_stmts = self . new_stmts ( tcx, targets, param_env, bbs, discr_local, discr_ty) ;
85
87
let ( _, first) = targets. iter ( ) . next ( ) . unwrap ( ) ;
86
- let ( from, first) = bbs. pick2_mut ( switch_bb_idx, first) ;
87
- from. statements
88
- . push ( Statement { source_info, kind : StatementKind :: StorageLive ( discr_local) } ) ;
89
- from. statements . push ( Statement {
90
- source_info,
91
- kind : StatementKind :: Assign ( Box :: new ( ( Place :: from ( discr_local) , Rvalue :: Use ( discr) ) ) ) ,
92
- } ) ;
93
- from. statements . extend ( new_stmts) ;
94
- from. statements
95
- . push ( Statement { source_info, kind : StatementKind :: StorageDead ( discr_local) } ) ;
96
- from. terminator_mut ( ) . kind = first. terminator ( ) . kind . clone ( ) ;
88
+ let statement_index = bbs[ switch_bb_idx] . statements . len ( ) ;
89
+ let parent_end = Location { block : switch_bb_idx, statement_index } ;
90
+ patch. add_statement ( parent_end, StatementKind :: StorageLive ( discr_local) ) ;
91
+ patch. add_assign ( parent_end, Place :: from ( discr_local) , Rvalue :: Use ( discr) ) ;
92
+ self . new_stmts ( tcx, targets, param_env, & mut patch, parent_end, bbs, discr_local, discr_ty) ;
93
+ patch. add_statement ( parent_end, StatementKind :: StorageDead ( discr_local) ) ;
94
+ patch. patch_terminator ( switch_bb_idx, bbs[ first] . terminator ( ) . kind . clone ( ) ) ;
95
+ patch. apply ( body) ;
97
96
true
98
97
}
99
98
@@ -102,7 +101,7 @@ trait SimplifyMatch<'tcx> {
102
101
tcx : TyCtxt < ' tcx > ,
103
102
targets : & SwitchTargets ,
104
103
param_env : ParamEnv < ' tcx > ,
105
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
104
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
106
105
discr_ty : Ty < ' tcx > ,
107
106
) -> bool ;
108
107
@@ -111,10 +110,12 @@ trait SimplifyMatch<'tcx> {
111
110
tcx : TyCtxt < ' tcx > ,
112
111
targets : & SwitchTargets ,
113
112
param_env : ParamEnv < ' tcx > ,
114
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
113
+ patch : & mut MirPatch < ' tcx > ,
114
+ parent_end : Location ,
115
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
115
116
discr_local : Local ,
116
117
discr_ty : Ty < ' tcx > ,
117
- ) -> Vec < Statement < ' tcx > > ;
118
+ ) ;
118
119
}
119
120
120
121
struct SimplifyToIf ;
@@ -156,7 +157,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
156
157
tcx : TyCtxt < ' tcx > ,
157
158
targets : & SwitchTargets ,
158
159
param_env : ParamEnv < ' tcx > ,
159
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
160
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
160
161
_discr_ty : Ty < ' tcx > ,
161
162
) -> bool {
162
163
if targets. iter ( ) . len ( ) != 1 {
@@ -207,20 +208,23 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
207
208
tcx : TyCtxt < ' tcx > ,
208
209
targets : & SwitchTargets ,
209
210
param_env : ParamEnv < ' tcx > ,
210
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
211
+ patch : & mut MirPatch < ' tcx > ,
212
+ parent_end : Location ,
213
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
211
214
discr_local : Local ,
212
215
discr_ty : Ty < ' tcx > ,
213
- ) -> Vec < Statement < ' tcx > > {
216
+ ) {
214
217
let ( val, first) = targets. iter ( ) . next ( ) . unwrap ( ) ;
215
218
let second = targets. otherwise ( ) ;
216
219
// We already checked that first and second are different blocks,
217
220
// and bb_idx has a different terminator from both of them.
218
221
let first = & bbs[ first] ;
219
222
let second = & bbs[ second] ;
220
-
221
- let new_stmts = iter:: zip ( & first. statements , & second. statements ) . map ( |( f, s) | {
223
+ for ( f, s) in iter:: zip ( & first. statements , & second. statements ) {
222
224
match ( & f. kind , & s. kind ) {
223
- ( f_s, s_s) if f_s == s_s => ( * f) . clone ( ) ,
225
+ ( f_s, s_s) if f_s == s_s => {
226
+ patch. add_statement ( parent_end, f. kind . clone ( ) ) ;
227
+ }
224
228
225
229
(
226
230
StatementKind :: Assign ( box ( lhs, Rvalue :: Use ( Operand :: Constant ( f_c) ) ) ) ,
@@ -231,7 +235,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
231
235
let s_b = s_c. const_ . try_eval_bool ( tcx, param_env) . unwrap ( ) ;
232
236
if f_b == s_b {
233
237
// Same value in both blocks. Use statement as is.
234
- ( * f ) . clone ( )
238
+ patch . add_statement ( parent_end , f . kind . clone ( ) ) ;
235
239
} else {
236
240
// Different value between blocks. Make value conditional on switch condition.
237
241
let size = tcx. layout_of ( param_env. and ( discr_ty) ) . unwrap ( ) . size ;
@@ -246,17 +250,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
246
250
op,
247
251
Box :: new ( ( Operand :: Copy ( Place :: from ( discr_local) ) , const_cmp) ) ,
248
252
) ;
249
- Statement {
250
- source_info : f. source_info ,
251
- kind : StatementKind :: Assign ( Box :: new ( ( * lhs, rhs) ) ) ,
252
- }
253
+ patch. add_assign ( parent_end, * lhs, rhs) ;
253
254
}
254
255
}
255
256
256
257
_ => unreachable ! ( ) ,
257
258
}
258
- } ) ;
259
- new_stmts. collect ( )
259
+ }
260
260
}
261
261
}
262
262
@@ -333,7 +333,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
333
333
tcx : TyCtxt < ' tcx > ,
334
334
targets : & SwitchTargets ,
335
335
param_env : ParamEnv < ' tcx > ,
336
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
336
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
337
337
discr_ty : Ty < ' tcx > ,
338
338
) -> bool {
339
339
if targets. iter ( ) . len ( ) < 2 || targets. iter ( ) . len ( ) > 64 {
@@ -467,16 +467,20 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
467
467
_tcx : TyCtxt < ' tcx > ,
468
468
targets : & SwitchTargets ,
469
469
_param_env : ParamEnv < ' tcx > ,
470
- bbs : & IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
470
+ patch : & mut MirPatch < ' tcx > ,
471
+ parent_end : Location ,
472
+ bbs : & IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
471
473
discr_local : Local ,
472
474
discr_ty : Ty < ' tcx > ,
473
- ) -> Vec < Statement < ' tcx > > {
475
+ ) {
474
476
let ( _, first) = targets. iter ( ) . next ( ) . unwrap ( ) ;
475
477
let first = & bbs[ first] ;
476
478
477
- let new_stmts =
478
- iter:: zip ( & self . transfrom_types , & first. statements ) . map ( |( t, s) | match ( t, & s. kind ) {
479
- ( TransfromType :: Same , _) | ( TransfromType :: Eq , _) => ( * s) . clone ( ) ,
479
+ for ( t, s) in iter:: zip ( & self . transfrom_types , & first. statements ) {
480
+ match ( t, & s. kind ) {
481
+ ( TransfromType :: Same , _) | ( TransfromType :: Eq , _) => {
482
+ patch. add_statement ( parent_end, s. kind . clone ( ) ) ;
483
+ }
480
484
(
481
485
TransfromType :: Discr ,
482
486
StatementKind :: Assign ( box ( lhs, Rvalue :: Use ( Operand :: Constant ( f_c) ) ) ) ,
@@ -487,13 +491,10 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
487
491
} else {
488
492
Rvalue :: Cast ( CastKind :: IntToInt , operand, f_c. const_ . ty ( ) )
489
493
} ;
490
- Statement {
491
- source_info : s. source_info ,
492
- kind : StatementKind :: Assign ( Box :: new ( ( * lhs, r_val) ) ) ,
493
- }
494
+ patch. add_assign ( parent_end, * lhs, r_val) ;
494
495
}
495
496
_ => unreachable ! ( ) ,
496
- } ) ;
497
- new_stmts . collect ( )
497
+ }
498
+ }
498
499
}
499
500
}
0 commit comments