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,19 @@ pub(crate) struct MirPatch<'tcx> {
2223 terminate_block : Option < ( BasicBlock , UnwindTerminateReason ) > ,
2324 body_span : Span ,
2425 next_local : usize ,
26+ next_block : usize ,
2527}
2628
2729impl < ' tcx > MirPatch < ' tcx > {
2830 /// Creates a new, empty patch.
2931 pub ( crate ) fn new ( body : & Body < ' tcx > ) -> Self {
3032 let mut result = MirPatch {
31- term_patch_map : IndexVec :: from_elem ( None , & body . basic_blocks ) ,
33+ term_patch_map : Default :: default ( ) ,
3234 new_blocks : vec ! [ ] ,
3335 new_statements : vec ! [ ] ,
3436 new_locals : vec ! [ ] ,
3537 next_local : body. local_decls . len ( ) ,
38+ next_block : body. basic_blocks . len ( ) ,
3639 resume_block : None ,
3740 unreachable_cleanup_block : None ,
3841 unreachable_no_cleanup_block : None ,
@@ -141,7 +144,7 @@ impl<'tcx> MirPatch<'tcx> {
141144
142145 /// Has a replacement of this block's terminator been queued in this patch?
143146 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 )
145148 }
146149
147150 /// Universal getter for block data, either it is in 'old' blocks or in patched ones
@@ -194,18 +197,17 @@ impl<'tcx> MirPatch<'tcx> {
194197
195198 /// Queues the addition of a new basic block.
196199 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 ( ) ) ;
198201 debug ! ( "MirPatch: new_block: {:?}: {:?}" , block, data) ;
199202 self . new_blocks . push ( data) ;
200- self . term_patch_map . push ( None ) ;
201203 block
202204 }
203205
204206 /// Queues the replacement of a block's terminator.
205207 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 ) ) ;
207209 debug ! ( "MirPatch: patch_terminator({:?}, {:?})" , block, new) ;
208- self . term_patch_map [ block] = Some ( new) ;
210+ self . term_patch_map . insert ( block, new) ;
209211 }
210212
211213 /// Queues the insertion of a statement at a given location. The statement
@@ -244,18 +246,20 @@ impl<'tcx> MirPatch<'tcx> {
244246 self . new_blocks. len( ) ,
245247 body. basic_blocks. len( )
246248 ) ;
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 ( ) {
248251 body. basic_blocks . as_mut_preserves_cfg ( )
249252 } else {
250253 body. basic_blocks . as_mut ( )
251254 } ;
252255 bbs. extend ( self . new_blocks ) ;
253256 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;
259263 }
260264
261265 let mut new_statements = self . new_statements ;
0 commit comments