@@ -95,6 +95,11 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
95
95
96
96
let mut start = START_BLOCK ;
97
97
98
+ // Vec of the blocks that should be merged. We store the indices here, instead of the
99
+ // statements itself to avoid moving the (relatively) large statements twice.
100
+ // We do not push the statements directly into the target block (`bb`) as that is slower
101
+ // due to additional reallocations
102
+ let mut merged_blocks = Vec :: new ( ) ;
98
103
loop {
99
104
let mut changed = false ;
100
105
@@ -114,18 +119,28 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
114
119
self . collapse_goto_chain ( successor, & mut changed) ;
115
120
}
116
121
117
- let mut new_stmts = vec ! [ ] ;
118
122
let mut inner_changed = true ;
123
+ merged_blocks. clear ( ) ;
119
124
while inner_changed {
120
125
inner_changed = false ;
121
126
inner_changed |= self . simplify_branch ( & mut terminator) ;
122
- inner_changed |= self . merge_successor ( & mut new_stmts , & mut terminator) ;
127
+ inner_changed |= self . merge_successor ( & mut merged_blocks , & mut terminator) ;
123
128
changed |= inner_changed;
124
129
}
125
130
126
- let data = & mut self . basic_blocks [ bb] ;
127
- data. statements . extend ( new_stmts) ;
128
- data. terminator = Some ( terminator) ;
131
+ let statements_to_merge =
132
+ merged_blocks. iter ( ) . map ( |& i| self . basic_blocks [ i] . statements . len ( ) ) . sum ( ) ;
133
+
134
+ if statements_to_merge > 0 {
135
+ let mut statements = std:: mem:: take ( & mut self . basic_blocks [ bb] . statements ) ;
136
+ statements. reserve ( statements_to_merge) ;
137
+ for & from in & merged_blocks {
138
+ statements. append ( & mut self . basic_blocks [ from] . statements ) ;
139
+ }
140
+ self . basic_blocks [ bb] . statements = statements;
141
+ }
142
+
143
+ self . basic_blocks [ bb] . terminator = Some ( terminator) ;
129
144
130
145
changed |= inner_changed;
131
146
}
@@ -199,7 +214,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
199
214
// merge a block with 1 `goto` predecessor to its parent
200
215
fn merge_successor (
201
216
& mut self ,
202
- new_stmts : & mut Vec < Statement < ' tcx > > ,
217
+ merged_blocks : & mut Vec < BasicBlock > ,
203
218
terminator : & mut Terminator < ' tcx > ,
204
219
) -> bool {
205
220
let target = match terminator. kind {
@@ -216,7 +231,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
216
231
return false ;
217
232
}
218
233
} ;
219
- new_stmts. extend ( self . basic_blocks [ target] . statements . drain ( ..) ) ;
234
+
235
+ merged_blocks. push ( target) ;
220
236
self . pred_count [ target] = 0 ;
221
237
222
238
true
0 commit comments