1
- use rustc_index:: { Idx , IndexVec } ;
1
+ use rustc_data_structures:: fx:: FxHashMap ;
2
+ use rustc_index:: Idx ;
2
3
use rustc_middle:: mir:: * ;
3
4
use rustc_middle:: ty:: Ty ;
4
5
use rustc_span:: Span ;
@@ -9,7 +10,7 @@ use tracing::debug;
9
10
/// and replacement of terminators, and then apply the queued changes all at
10
11
/// once with `apply`. This is useful for MIR transformation passes.
11
12
pub ( crate ) struct MirPatch < ' tcx > {
12
- term_patch_map : IndexVec < BasicBlock , Option < TerminatorKind < ' tcx > > > ,
13
+ term_patch_map : FxHashMap < BasicBlock , TerminatorKind < ' tcx > > ,
13
14
new_blocks : Vec < BasicBlockData < ' tcx > > ,
14
15
new_statements : Vec < ( Location , StatementKind < ' tcx > ) > ,
15
16
new_locals : Vec < LocalDecl < ' tcx > > ,
@@ -22,17 +23,19 @@ pub(crate) struct MirPatch<'tcx> {
22
23
terminate_block : Option < ( BasicBlock , UnwindTerminateReason ) > ,
23
24
body_span : Span ,
24
25
next_local : usize ,
26
+ next_block : usize ,
25
27
}
26
28
27
29
impl < ' tcx > MirPatch < ' tcx > {
28
30
/// Creates a new, empty patch.
29
31
pub ( crate ) fn new ( body : & Body < ' tcx > ) -> Self {
30
32
let mut result = MirPatch {
31
- term_patch_map : IndexVec :: from_elem ( None , & body . basic_blocks ) ,
33
+ term_patch_map : Default :: default ( ) ,
32
34
new_blocks : vec ! [ ] ,
33
35
new_statements : vec ! [ ] ,
34
36
new_locals : vec ! [ ] ,
35
37
next_local : body. local_decls . len ( ) ,
38
+ next_block : body. basic_blocks . len ( ) ,
36
39
resume_block : None ,
37
40
unreachable_cleanup_block : None ,
38
41
unreachable_no_cleanup_block : None ,
@@ -141,7 +144,7 @@ impl<'tcx> MirPatch<'tcx> {
141
144
142
145
/// Has a replacement of this block's terminator been queued in this patch?
143
146
pub ( crate ) fn is_term_patched ( & self , bb : BasicBlock ) -> bool {
144
- self . term_patch_map [ bb ] . is_some ( )
147
+ self . term_patch_map . contains_key ( & bb )
145
148
}
146
149
147
150
/// Universal getter for block data, either it is in 'old' blocks or in patched ones
@@ -194,18 +197,17 @@ impl<'tcx> MirPatch<'tcx> {
194
197
195
198
/// Queues the addition of a new basic block.
196
199
pub ( crate ) fn new_block ( & mut self , data : BasicBlockData < ' tcx > ) -> BasicBlock {
197
- let block = self . term_patch_map . next_index ( ) ;
200
+ let block = BasicBlock :: from_usize ( self . next_block + self . new_blocks . len ( ) ) ;
198
201
debug ! ( "MirPatch: new_block: {:?}: {:?}" , block, data) ;
199
202
self . new_blocks . push ( data) ;
200
- self . term_patch_map . push ( None ) ;
201
203
block
202
204
}
203
205
204
206
/// Queues the replacement of a block's terminator.
205
207
pub ( crate ) fn patch_terminator ( & mut self , block : BasicBlock , new : TerminatorKind < ' tcx > ) {
206
- assert ! ( self . term_patch_map[ block ] . is_none ( ) ) ;
208
+ assert ! ( ! self . term_patch_map. contains_key ( & block ) ) ;
207
209
debug ! ( "MirPatch: patch_terminator({:?}, {:?})" , block, new) ;
208
- self . term_patch_map [ block] = Some ( new) ;
210
+ self . term_patch_map . insert ( block, new) ;
209
211
}
210
212
211
213
/// Queues the insertion of a statement at a given location. The statement
@@ -244,18 +246,20 @@ impl<'tcx> MirPatch<'tcx> {
244
246
self . new_blocks. len( ) ,
245
247
body. basic_blocks. len( )
246
248
) ;
247
- let bbs = if self . term_patch_map . iter ( ) . all ( Option :: is_none) && self . new_blocks . is_empty ( ) {
249
+ debug_assert_eq ! ( self . next_block, body. basic_blocks. len( ) ) ;
250
+ let bbs = if self . term_patch_map . is_empty ( ) && self . new_blocks . is_empty ( ) {
248
251
body. basic_blocks . as_mut_preserves_cfg ( )
249
252
} else {
250
253
body. basic_blocks . as_mut ( )
251
254
} ;
252
255
bbs. extend ( self . new_blocks ) ;
253
256
body. local_decls . extend ( self . new_locals ) ;
254
- for ( src, patch) in self . term_patch_map . into_iter_enumerated ( ) {
255
- if let Some ( patch) = patch {
256
- debug ! ( "MirPatch: patching block {:?}" , src) ;
257
- bbs[ src] . terminator_mut ( ) . kind = patch;
258
- }
257
+
258
+ // The order in which we patch terminators does not change the result.
259
+ #[ allow( rustc:: potential_query_instability) ]
260
+ for ( src, patch) in self . term_patch_map {
261
+ debug ! ( "MirPatch: patching block {:?}" , src) ;
262
+ bbs[ src] . terminator_mut ( ) . kind = patch;
259
263
}
260
264
261
265
let mut new_statements = self . new_statements ;
0 commit comments