Skip to content

Commit 10dd016

Browse files
authored
Rollup merge of #137203 - nnethercote:improve-MIR-modification, r=compiler-errors
Improve MIR modification A few commits that simplify code that manipulates MIR bodies. r? `@tmiasko`
2 parents 05dbe6d + 04eeda4 commit 10dd016

11 files changed

+135
-206
lines changed

compiler/rustc_middle/src/mir/mod.rs

+1-61
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
55
use std::borrow::Cow;
66
use std::fmt::{self, Debug, Formatter};
7+
use std::iter;
78
use std::ops::{Index, IndexMut};
8-
use std::{iter, mem};
99

1010
pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
1111
use either::Either;
@@ -1365,66 +1365,6 @@ impl<'tcx> BasicBlockData<'tcx> {
13651365
self.terminator.as_mut().expect("invalid terminator state")
13661366
}
13671367

1368-
pub fn retain_statements<F>(&mut self, mut f: F)
1369-
where
1370-
F: FnMut(&mut Statement<'_>) -> bool,
1371-
{
1372-
for s in &mut self.statements {
1373-
if !f(s) {
1374-
s.make_nop();
1375-
}
1376-
}
1377-
}
1378-
1379-
pub fn expand_statements<F, I>(&mut self, mut f: F)
1380-
where
1381-
F: FnMut(&mut Statement<'tcx>) -> Option<I>,
1382-
I: iter::TrustedLen<Item = Statement<'tcx>>,
1383-
{
1384-
// Gather all the iterators we'll need to splice in, and their positions.
1385-
let mut splices: Vec<(usize, I)> = vec![];
1386-
let mut extra_stmts = 0;
1387-
for (i, s) in self.statements.iter_mut().enumerate() {
1388-
if let Some(mut new_stmts) = f(s) {
1389-
if let Some(first) = new_stmts.next() {
1390-
// We can already store the first new statement.
1391-
*s = first;
1392-
1393-
// Save the other statements for optimized splicing.
1394-
let remaining = new_stmts.size_hint().0;
1395-
if remaining > 0 {
1396-
splices.push((i + 1 + extra_stmts, new_stmts));
1397-
extra_stmts += remaining;
1398-
}
1399-
} else {
1400-
s.make_nop();
1401-
}
1402-
}
1403-
}
1404-
1405-
// Splice in the new statements, from the end of the block.
1406-
// FIXME(eddyb) This could be more efficient with a "gap buffer"
1407-
// where a range of elements ("gap") is left uninitialized, with
1408-
// splicing adding new elements to the end of that gap and moving
1409-
// existing elements from before the gap to the end of the gap.
1410-
// For now, this is safe code, emulating a gap but initializing it.
1411-
let mut gap = self.statements.len()..self.statements.len() + extra_stmts;
1412-
self.statements.resize(
1413-
gap.end,
1414-
Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop },
1415-
);
1416-
for (splice_start, new_stmts) in splices.into_iter().rev() {
1417-
let splice_end = splice_start + new_stmts.size_hint().0;
1418-
while gap.end > splice_end {
1419-
gap.start -= 1;
1420-
gap.end -= 1;
1421-
self.statements.swap(gap.start, gap.end);
1422-
}
1423-
self.statements.splice(splice_start..splice_end, new_stmts);
1424-
gap.end = splice_start;
1425-
}
1426-
}
1427-
14281368
pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
14291369
if index < self.statements.len() { &self.statements[index] } else { &self.terminator }
14301370
}

compiler/rustc_middle/src/mir/statement.rs

-9
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,6 @@ impl Statement<'_> {
1919
pub fn make_nop(&mut self) {
2020
self.kind = StatementKind::Nop
2121
}
22-
23-
/// Changes a statement to a nop and returns the original statement.
24-
#[must_use = "If you don't need the statement, use `make_nop` instead"]
25-
pub fn replace_nop(&mut self) -> Self {
26-
Statement {
27-
source_info: self.source_info,
28-
kind: mem::replace(&mut self.kind, StatementKind::Nop),
29-
}
30-
}
3122
}
3223

3324
impl<'tcx> StatementKind<'tcx> {

compiler/rustc_mir_transform/src/coroutine.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,13 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
393393

394394
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
395395
// Remove StorageLive and StorageDead statements for remapped locals
396-
data.retain_statements(|s| match s.kind {
397-
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
398-
!self.remap.contains(l)
396+
for s in &mut data.statements {
397+
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind
398+
&& self.remap.contains(l)
399+
{
400+
s.make_nop();
399401
}
400-
_ => true,
401-
});
402+
}
402403

403404
let ret_val = match data.terminator().kind {
404405
TerminatorKind::Return => {

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/large_enums.rs

+74-112
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use rustc_middle::ty::util::IntTypeExt;
66
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
77
use rustc_session::Session;
88

9+
use crate::patch::MirPatch;
10+
911
/// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
1012
/// enough discrepancy between them.
1113
///
@@ -41,31 +43,34 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
4143
let mut alloc_cache = FxHashMap::default();
4244
let typing_env = body.typing_env(tcx);
4345

44-
let blocks = body.basic_blocks.as_mut();
45-
let local_decls = &mut body.local_decls;
46+
let mut patch = MirPatch::new(body);
4647

47-
for bb in blocks {
48-
bb.expand_statements(|st| {
48+
for (block, data) in body.basic_blocks.as_mut().iter_enumerated_mut() {
49+
for (statement_index, st) in data.statements.iter_mut().enumerate() {
4950
let StatementKind::Assign(box (
5051
lhs,
5152
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
5253
)) = &st.kind
5354
else {
54-
return None;
55+
continue;
5556
};
5657

57-
let ty = lhs.ty(local_decls, tcx).ty;
58+
let location = Location { block, statement_index };
5859

59-
let (adt_def, num_variants, alloc_id) =
60-
self.candidate(tcx, typing_env, ty, &mut alloc_cache)?;
60+
let ty = lhs.ty(&body.local_decls, tcx).ty;
6161

62-
let source_info = st.source_info;
63-
let span = source_info.span;
62+
let Some((adt_def, num_variants, alloc_id)) =
63+
self.candidate(tcx, typing_env, ty, &mut alloc_cache)
64+
else {
65+
continue;
66+
};
67+
68+
let span = st.source_info.span;
6469

6570
let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64);
66-
let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
67-
let store_live =
68-
Statement { source_info, kind: StatementKind::StorageLive(size_array_local) };
71+
let size_array_local = patch.new_temp(tmp_ty, span);
72+
73+
let store_live = StatementKind::StorageLive(size_array_local);
6974

7075
let place = Place::from(size_array_local);
7176
let constant_vals = ConstOperand {
@@ -77,108 +82,63 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
7782
),
7883
};
7984
let rval = Rvalue::Use(Operand::Constant(Box::new(constant_vals)));
80-
let const_assign =
81-
Statement { source_info, kind: StatementKind::Assign(Box::new((place, rval))) };
82-
83-
let discr_place = Place::from(
84-
local_decls.push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
85-
);
86-
let store_discr = Statement {
87-
source_info,
88-
kind: StatementKind::Assign(Box::new((
89-
discr_place,
90-
Rvalue::Discriminant(*rhs),
91-
))),
92-
};
93-
94-
let discr_cast_place =
95-
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
96-
let cast_discr = Statement {
97-
source_info,
98-
kind: StatementKind::Assign(Box::new((
99-
discr_cast_place,
100-
Rvalue::Cast(
101-
CastKind::IntToInt,
102-
Operand::Copy(discr_place),
103-
tcx.types.usize,
104-
),
105-
))),
106-
};
107-
108-
let size_place =
109-
Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
110-
let store_size = Statement {
111-
source_info,
112-
kind: StatementKind::Assign(Box::new((
113-
size_place,
114-
Rvalue::Use(Operand::Copy(Place {
115-
local: size_array_local,
116-
projection: tcx
117-
.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
118-
})),
119-
))),
120-
};
121-
122-
let dst =
123-
Place::from(local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)));
124-
let dst_ptr = Statement {
125-
source_info,
126-
kind: StatementKind::Assign(Box::new((
127-
dst,
128-
Rvalue::RawPtr(RawPtrKind::Mut, *lhs),
129-
))),
130-
};
85+
let const_assign = StatementKind::Assign(Box::new((place, rval)));
86+
87+
let discr_place =
88+
Place::from(patch.new_temp(adt_def.repr().discr_type().to_ty(tcx), span));
89+
let store_discr =
90+
StatementKind::Assign(Box::new((discr_place, Rvalue::Discriminant(*rhs))));
91+
92+
let discr_cast_place = Place::from(patch.new_temp(tcx.types.usize, span));
93+
let cast_discr = StatementKind::Assign(Box::new((
94+
discr_cast_place,
95+
Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_place), tcx.types.usize),
96+
)));
97+
98+
let size_place = Place::from(patch.new_temp(tcx.types.usize, span));
99+
let store_size = StatementKind::Assign(Box::new((
100+
size_place,
101+
Rvalue::Use(Operand::Copy(Place {
102+
local: size_array_local,
103+
projection: tcx.mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
104+
})),
105+
)));
106+
107+
let dst = Place::from(patch.new_temp(Ty::new_mut_ptr(tcx, ty), span));
108+
let dst_ptr =
109+
StatementKind::Assign(Box::new((dst, Rvalue::RawPtr(RawPtrKind::Mut, *lhs))));
131110

132111
let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8);
133-
let dst_cast_place =
134-
Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
135-
let dst_cast = Statement {
136-
source_info,
137-
kind: StatementKind::Assign(Box::new((
138-
dst_cast_place,
139-
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
140-
))),
141-
};
112+
let dst_cast_place = Place::from(patch.new_temp(dst_cast_ty, span));
113+
let dst_cast = StatementKind::Assign(Box::new((
114+
dst_cast_place,
115+
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
116+
)));
142117

143-
let src =
144-
Place::from(local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)));
145-
let src_ptr = Statement {
146-
source_info,
147-
kind: StatementKind::Assign(Box::new((
148-
src,
149-
Rvalue::RawPtr(RawPtrKind::Const, *rhs),
150-
))),
151-
};
118+
let src = Place::from(patch.new_temp(Ty::new_imm_ptr(tcx, ty), span));
119+
let src_ptr =
120+
StatementKind::Assign(Box::new((src, Rvalue::RawPtr(RawPtrKind::Const, *rhs))));
152121

153122
let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8);
154-
let src_cast_place =
155-
Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
156-
let src_cast = Statement {
157-
source_info,
158-
kind: StatementKind::Assign(Box::new((
159-
src_cast_place,
160-
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
161-
))),
162-
};
123+
let src_cast_place = Place::from(patch.new_temp(src_cast_ty, span));
124+
let src_cast = StatementKind::Assign(Box::new((
125+
src_cast_place,
126+
Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
127+
)));
163128

164-
let deinit_old =
165-
Statement { source_info, kind: StatementKind::Deinit(Box::new(dst)) };
166-
167-
let copy_bytes = Statement {
168-
source_info,
169-
kind: StatementKind::Intrinsic(Box::new(
170-
NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
171-
src: Operand::Copy(src_cast_place),
172-
dst: Operand::Copy(dst_cast_place),
173-
count: Operand::Copy(size_place),
174-
}),
175-
)),
176-
};
129+
let deinit_old = StatementKind::Deinit(Box::new(dst));
130+
131+
let copy_bytes = StatementKind::Intrinsic(Box::new(
132+
NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
133+
src: Operand::Copy(src_cast_place),
134+
dst: Operand::Copy(dst_cast_place),
135+
count: Operand::Copy(size_place),
136+
}),
137+
));
177138

178-
let store_dead =
179-
Statement { source_info, kind: StatementKind::StorageDead(size_array_local) };
139+
let store_dead = StatementKind::StorageDead(size_array_local);
180140

181-
let iter = [
141+
let stmts = [
182142
store_live,
183143
const_assign,
184144
store_discr,
@@ -191,14 +151,16 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
191151
deinit_old,
192152
copy_bytes,
193153
store_dead,
194-
]
195-
.into_iter();
154+
];
155+
for stmt in stmts {
156+
patch.add_statement(location, stmt);
157+
}
196158

197159
st.make_nop();
198-
199-
Some(iter)
200-
});
160+
}
201161
}
162+
163+
patch.apply(body);
202164
}
203165

204166
fn is_required(&self) -> bool {

0 commit comments

Comments
 (0)