1- use rustc_index:: { Idx , IndexVec } ;
1+ use rustc_data_structures:: fx:: FxHashMap ;
2+ use rustc_index:: Idx ;
23use rustc_middle:: mir:: * ;
34use rustc_middle:: ty:: Ty ;
45use rustc_span:: Span ;
@@ -9,7 +10,7 @@ use tracing::debug;
910/// and replacement of terminators, and then apply the queued changes all at
1011/// once with `apply`. This is useful for MIR transformation passes.
1112pub ( crate ) struct MirPatch < ' tcx > {
12- term_patch_map : IndexVec < BasicBlock , Option < TerminatorKind < ' tcx > > > ,
13+ term_patch_map : FxHashMap < BasicBlock , TerminatorKind < ' tcx > > ,
1314 new_blocks : Vec < BasicBlockData < ' tcx > > ,
1415 new_statements : Vec < ( Location , StatementKind < ' tcx > ) > ,
1516 new_locals : Vec < LocalDecl < ' tcx > > ,
@@ -22,17 +23,21 @@ pub(crate) struct MirPatch<'tcx> {
2223 terminate_block : Option < ( BasicBlock , UnwindTerminateReason ) > ,
2324 body_span : Span ,
2425 next_local : usize ,
26+ /// The number of blocks at the start of the transformation. New blocks
27+ /// get appended at the end.
28+ next_block : usize ,
2529}
2630
2731impl < ' tcx > MirPatch < ' tcx > {
2832 /// Creates a new, empty patch.
2933 pub ( crate ) fn new ( body : & Body < ' tcx > ) -> Self {
3034 let mut result = MirPatch {
31- term_patch_map : IndexVec :: from_elem ( None , & body . basic_blocks ) ,
35+ term_patch_map : Default :: default ( ) ,
3236 new_blocks : vec ! [ ] ,
3337 new_statements : vec ! [ ] ,
3438 new_locals : vec ! [ ] ,
3539 next_local : body. local_decls . len ( ) ,
40+ next_block : body. basic_blocks . len ( ) ,
3641 resume_block : None ,
3742 unreachable_cleanup_block : None ,
3843 unreachable_no_cleanup_block : None ,
@@ -141,7 +146,7 @@ impl<'tcx> MirPatch<'tcx> {
141146
142147 /// Has a replacement of this block's terminator been queued in this patch?
143148 pub ( crate ) fn is_term_patched ( & self , bb : BasicBlock ) -> bool {
144- self . term_patch_map [ bb ] . is_some ( )
149+ self . term_patch_map . contains_key ( & bb )
145150 }
146151
147152 /// Universal getter for block data, either it is in 'old' blocks or in patched ones
@@ -194,18 +199,17 @@ impl<'tcx> MirPatch<'tcx> {
194199
195200 /// Queues the addition of a new basic block.
196201 pub ( crate ) fn new_block ( & mut self , data : BasicBlockData < ' tcx > ) -> BasicBlock {
197- let block = self . term_patch_map . next_index ( ) ;
202+ let block = BasicBlock :: from_usize ( self . next_block + self . new_blocks . len ( ) ) ;
198203 debug ! ( "MirPatch: new_block: {:?}: {:?}" , block, data) ;
199204 self . new_blocks . push ( data) ;
200- self . term_patch_map . push ( None ) ;
201205 block
202206 }
203207
204208 /// Queues the replacement of a block's terminator.
205209 pub ( crate ) fn patch_terminator ( & mut self , block : BasicBlock , new : TerminatorKind < ' tcx > ) {
206- assert ! ( self . term_patch_map[ block ] . is_none ( ) ) ;
210+ assert ! ( ! self . term_patch_map. contains_key ( & block ) ) ;
207211 debug ! ( "MirPatch: patch_terminator({:?}, {:?})" , block, new) ;
208- self . term_patch_map [ block] = Some ( new) ;
212+ self . term_patch_map . insert ( block, new) ;
209213 }
210214
211215 /// Queues the insertion of a statement at a given location. The statement
@@ -244,18 +248,20 @@ impl<'tcx> MirPatch<'tcx> {
244248 self . new_blocks. len( ) ,
245249 body. basic_blocks. len( )
246250 ) ;
251+ debug_assert_eq ! ( self . next_block, body. basic_blocks. len( ) ) ;
247252 let bbs = if self . term_patch_map . is_empty ( ) && self . new_blocks . is_empty ( ) {
248253 body. basic_blocks . as_mut_preserves_cfg ( )
249254 } else {
250255 body. basic_blocks . as_mut ( )
251256 } ;
252257 bbs. extend ( self . new_blocks ) ;
253258 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- }
259+
260+ // The order in which we patch terminators does not change the result.
261+ #[ allow( rustc:: potential_query_instability) ]
262+ for ( src, patch) in self . term_patch_map {
263+ debug ! ( "MirPatch: patching block {:?}" , src) ;
264+ bbs[ src] . terminator_mut ( ) . kind = patch;
259265 }
260266
261267 let mut new_statements = self . new_statements ;
@@ -273,8 +279,8 @@ impl<'tcx> MirPatch<'tcx> {
273279 }
274280 debug ! ( "MirPatch: adding statement {:?} at loc {:?}+{}" , stmt, loc, delta) ;
275281 loc. statement_index += delta;
276- let source_info = Self :: source_info_for_index ( & body [ loc. block ] , loc) ;
277- body [ loc. block ]
282+ let source_info = Self :: source_info_for_index ( & bbs [ loc. block ] , loc) ;
283+ bbs [ loc. block ]
278284 . statements
279285 . insert ( loc. statement_index , Statement :: new ( source_info, stmt) ) ;
280286 delta += 1 ;
0 commit comments