Skip to content

Commit e3316ae

Browse files
committed
Improve MirPatch documentation and naming.
It's currently lacking comments. This commit adds some, which is useful because there are some methods with non-obvious behaviour. The commit also renames two things: - `patch_map` becomes `term_patch_map`, because it's only about terminators. - `is_patched` becomes `is_term_patched`, for the same reason. (I would guess that originally `MirPatch` only handled terminators, and then over time it expanded to allow other modifications, but these names weren't updated.)
1 parent a1daa34 commit e3316ae

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

compiler/rustc_mir_transform/src/elaborate_drops.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
417417
..
418418
} = data.terminator().kind
419419
{
420-
assert!(!self.patch.is_patched(bb));
420+
assert!(!self.patch.is_term_patched(bb));
421421

422422
let loc = Location { block: tgt, statement_index: 0 };
423423
let path = self.move_data().rev_lookup.find(destination.as_ref());
@@ -462,7 +462,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
462462
// a Goto; see `MirPatch::new`).
463463
}
464464
_ => {
465-
assert!(!self.patch.is_patched(bb));
465+
assert!(!self.patch.is_term_patched(bb));
466466
}
467467
}
468468
}
@@ -486,7 +486,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
486486
..
487487
} = data.terminator().kind
488488
{
489-
assert!(!self.patch.is_patched(bb));
489+
assert!(!self.patch.is_term_patched(bb));
490490

491491
let loc = Location { block: bb, statement_index: data.statements.len() };
492492
let path = self.move_data().rev_lookup.find(destination.as_ref());

compiler/rustc_mir_transform/src/patch.rs

+38-13
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use rustc_middle::ty::Ty;
44
use rustc_span::Span;
55
use 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.
1011
pub(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

2627
impl<'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

Comments
 (0)