@@ -4,11 +4,12 @@ use rustc_middle::ty::Ty;
44use rustc_span:: Span ;
55use tracing:: debug;
66
7- /// This struct represents a patch to MIR, which can add
8- /// new statements and basic blocks and patch over block
9- /// terminators.
7+ /// This struct lets you "patch" a MIR body, i.e. modify it. You can queue up
8+ /// various changes, such as the addition of new statements and basic blocks
9+ /// and replacement of terminators, and then apply the queued changes all at
10+ /// once with `apply`. This is useful for MIR transformation passes.
1011pub ( crate ) struct MirPatch < ' tcx > {
11- patch_map : IndexVec < BasicBlock , Option < TerminatorKind < ' tcx > > > ,
12+ term_patch_map : IndexVec < BasicBlock , Option < TerminatorKind < ' tcx > > > ,
1213 new_blocks : Vec < BasicBlockData < ' tcx > > ,
1314 new_statements : Vec < ( Location , StatementKind < ' tcx > ) > ,
1415 new_locals : Vec < LocalDecl < ' tcx > > ,
@@ -24,9 +25,10 @@ pub(crate) struct MirPatch<'tcx> {
2425}
2526
2627impl < ' tcx > MirPatch < ' tcx > {
28+ /// Creates a new, empty patch.
2729 pub ( crate ) fn new ( body : & Body < ' tcx > ) -> Self {
2830 let mut result = MirPatch {
29- patch_map : IndexVec :: from_elem ( None , & body. basic_blocks ) ,
31+ term_patch_map : IndexVec :: from_elem ( None , & body. basic_blocks ) ,
3032 new_blocks : vec ! [ ] ,
3133 new_statements : vec ! [ ] ,
3234 new_locals : vec ! [ ] ,
@@ -141,10 +143,12 @@ impl<'tcx> MirPatch<'tcx> {
141143 bb
142144 }
143145
144- pub ( crate ) fn is_patched ( & self , bb : BasicBlock ) -> bool {
145- self . patch_map [ bb] . is_some ( )
146+ /// Has a replacement of this block's terminator been queued in this patch?
147+ pub ( crate ) fn is_term_patched ( & self , bb : BasicBlock ) -> bool {
148+ self . term_patch_map [ bb] . is_some ( )
146149 }
147150
151+ /// Queues the addition of a new temporary with additional local info.
148152 pub ( crate ) fn new_local_with_info (
149153 & mut self ,
150154 ty : Ty < ' tcx > ,
@@ -159,6 +163,7 @@ impl<'tcx> MirPatch<'tcx> {
159163 Local :: new ( index)
160164 }
161165
166+ /// Queues the addition of a new temporary.
162167 pub ( crate ) fn new_temp ( & mut self , ty : Ty < ' tcx > , span : Span ) -> Local {
163168 let index = self . next_local ;
164169 self . next_local += 1 ;
@@ -174,29 +179,46 @@ impl<'tcx> MirPatch<'tcx> {
174179 self . new_locals [ new_local_idx] . ty
175180 }
176181
182+ /// Queues the addition of a new basic block.
177183 pub ( crate ) fn new_block ( & mut self , data : BasicBlockData < ' tcx > ) -> BasicBlock {
178- let block = BasicBlock :: new ( self . patch_map . len ( ) ) ;
184+ let block = BasicBlock :: new ( self . term_patch_map . len ( ) ) ;
179185 debug ! ( "MirPatch: new_block: {:?}: {:?}" , block, data) ;
180186 self . new_blocks . push ( data) ;
181- self . patch_map . push ( None ) ;
187+ self . term_patch_map . push ( None ) ;
182188 block
183189 }
184190
191+ /// Queues the replacement of a block's terminator.
185192 pub ( crate ) fn patch_terminator ( & mut self , block : BasicBlock , new : TerminatorKind < ' tcx > ) {
186- assert ! ( self . patch_map [ block] . is_none( ) ) ;
193+ assert ! ( self . term_patch_map [ block] . is_none( ) ) ;
187194 debug ! ( "MirPatch: patch_terminator({:?}, {:?})" , block, new) ;
188- self . patch_map [ block] = Some ( new) ;
195+ self . term_patch_map [ block] = Some ( new) ;
189196 }
190197
198+ /// Queues the insertion of a statement at a given location. The statement
199+ /// currently at that location, and all statements that follow, are shifted
200+ /// down. If multiple statements are queued for addition at the same
201+ /// location, the final statement order after calling `apply` will match
202+ /// the queue insertion order.
203+ ///
204+ /// E.g. if we have `s0` at location `loc` and do these calls:
205+ ///
206+ /// p.add_statement(loc, s1);
207+ /// p.add_statement(loc, s2);
208+ /// p.apply(body);
209+ ///
210+ /// then the final order will be `s1, s2, s0`, with `s1` at `loc`.
191211 pub ( crate ) fn add_statement ( & mut self , loc : Location , stmt : StatementKind < ' tcx > ) {
192212 debug ! ( "MirPatch: add_statement({:?}, {:?})" , loc, stmt) ;
193213 self . new_statements . push ( ( loc, stmt) ) ;
194214 }
195215
216+ /// Like `add_statement`, but specialized for assignments.
196217 pub ( crate ) fn add_assign ( & mut self , loc : Location , place : Place < ' tcx > , rv : Rvalue < ' tcx > ) {
197218 self . add_statement ( loc, StatementKind :: Assign ( Box :: new ( ( place, rv) ) ) ) ;
198219 }
199220
221+ /// Applies the queued changes.
200222 pub ( crate ) fn apply ( self , body : & mut Body < ' tcx > ) {
201223 debug ! (
202224 "MirPatch: {:?} new temps, starting from index {}: {:?}" ,
@@ -209,21 +231,24 @@ impl<'tcx> MirPatch<'tcx> {
209231 self . new_blocks. len( ) ,
210232 body. basic_blocks. len( )
211233 ) ;
212- let bbs = if self . patch_map . is_empty ( ) && self . new_blocks . is_empty ( ) {
234+ let bbs = if self . term_patch_map . is_empty ( ) && self . new_blocks . is_empty ( ) {
213235 body. basic_blocks . as_mut_preserves_cfg ( )
214236 } else {
215237 body. basic_blocks . as_mut ( )
216238 } ;
217239 bbs. extend ( self . new_blocks ) ;
218240 body. local_decls . extend ( self . new_locals ) ;
219- for ( src, patch) in self . patch_map . into_iter_enumerated ( ) {
241+ for ( src, patch) in self . term_patch_map . into_iter_enumerated ( ) {
220242 if let Some ( patch) = patch {
221243 debug ! ( "MirPatch: patching block {:?}" , src) ;
222244 bbs[ src] . terminator_mut ( ) . kind = patch;
223245 }
224246 }
225247
226248 let mut new_statements = self . new_statements ;
249+
250+ // This must be a stable sort to provide the ordering described in the
251+ // comment for `add_statement`.
227252 new_statements. sort_by_key ( |s| s. 0 ) ;
228253
229254 let mut delta = 0 ;
0 commit comments