Skip to content

Commit c91a07a

Browse files
committed
mir-opt: ignore dead store stmts in MatchBranchSimplification
1 parent 5638bd3 commit c91a07a

12 files changed

+226
-80
lines changed

compiler/rustc_mir_transform/src/dead_store_elimination.rs

+40-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! will still not cause any further changes.
1313
//!
1414
15+
use rustc_index::IndexVec;
1516
use rustc_middle::bug;
1617
use rustc_middle::mir::visit::Visitor;
1718
use rustc_middle::mir::*;
@@ -24,17 +25,49 @@ use rustc_mir_dataflow::impls::{
2425

2526
use crate::util::is_within_packed;
2627

28+
pub(super) enum ModifyBasicBlocks<'tcx, 'a> {
29+
Direct(&'a mut Body<'tcx>),
30+
BasicBlocks(&'a Body<'tcx>, &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>),
31+
}
32+
33+
impl<'tcx, 'a> ModifyBasicBlocks<'tcx, 'a> {
34+
pub(super) fn body(&self) -> &Body<'tcx> {
35+
match self {
36+
ModifyBasicBlocks::Direct(body) => body,
37+
ModifyBasicBlocks::BasicBlocks(body, _) => body,
38+
}
39+
}
40+
41+
pub(super) fn bbs(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
42+
match self {
43+
ModifyBasicBlocks::Direct(body) => body.basic_blocks.as_mut_preserves_cfg(),
44+
ModifyBasicBlocks::BasicBlocks(_, bbs) => bbs,
45+
}
46+
}
47+
}
48+
2749
/// Performs the optimization on the body
2850
///
2951
/// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this
3052
/// body. It can be generated via the [`borrowed_locals`] function.
31-
fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
53+
pub(super) fn eliminate<'tcx>(
54+
tcx: TyCtxt<'tcx>,
55+
mut modify_basic_blocks: ModifyBasicBlocks<'tcx, '_>,
56+
ignore_debuginfo: bool,
57+
arg_copy_to_move: bool,
58+
) {
59+
let body = modify_basic_blocks.body();
3260
let borrowed_locals = borrowed_locals(body);
3361

3462
// If the user requests complete debuginfo, mark the locals that appear in it as live, so
3563
// we don't remove assignments to them.
36-
let mut always_live = debuginfo_locals(body);
37-
always_live.union(&borrowed_locals);
64+
let always_live = if ignore_debuginfo {
65+
borrowed_locals.clone()
66+
} else {
67+
let mut always_live = debuginfo_locals(body);
68+
always_live.union(&borrowed_locals);
69+
always_live
70+
};
3871

3972
let mut live = MaybeTransitiveLiveLocals::new(&always_live)
4073
.iterate_to_fixpoint(tcx, body, None)
@@ -46,7 +79,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
4679
let mut patch = Vec::new();
4780

4881
for (bb, bb_data) in traversal::preorder(body) {
49-
if let TerminatorKind::Call { ref args, .. } = bb_data.terminator().kind {
82+
if arg_copy_to_move && let TerminatorKind::Call { ref args, .. } = bb_data.terminator().kind
83+
{
5084
let loc = Location { block: bb, statement_index: bb_data.statements.len() };
5185

5286
// Position ourselves between the evaluation of `args` and the write to `destination`.
@@ -113,7 +147,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
113147
return;
114148
}
115149

116-
let bbs = body.basic_blocks.as_mut_preserves_cfg();
150+
let bbs = modify_basic_blocks.bbs();
117151
for Location { block, statement_index } in patch {
118152
bbs[block].statements[statement_index].make_nop();
119153
}
@@ -145,7 +179,7 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
145179
}
146180

147181
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
148-
eliminate(tcx, body);
182+
eliminate(tcx, ModifyBasicBlocks::Direct(body), false, true);
149183
}
150184

151185
fn is_required(&self) -> bool {

compiler/rustc_mir_transform/src/match_branches.rs

+65-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use std::iter;
22

33
use rustc_abi::Integer;
4-
use rustc_index::IndexSlice;
4+
use rustc_index::{IndexSlice, IndexVec};
5+
use rustc_middle::mir::visit::Visitor;
56
use rustc_middle::mir::*;
67
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
78
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
89
use tracing::instrument;
910

1011
use super::simplify::simplify_cfg;
12+
use crate::dead_store_elimination::{self, ModifyBasicBlocks};
1113
use crate::patch::MirPatch;
14+
use crate::simplify::strip_nops;
1215

1316
pub(super) struct MatchBranchSimplification;
1417

@@ -20,6 +23,17 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
2023
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2124
let typing_env = body.typing_env(tcx);
2225
let mut apply_patch = false;
26+
let mut bbs = body.basic_blocks.clone();
27+
let bbs = bbs.as_mut_preserves_cfg();
28+
// We can ignore the dead store statements when merging branches.
29+
dead_store_elimination::eliminate(
30+
tcx,
31+
ModifyBasicBlocks::BasicBlocks(body, bbs),
32+
true,
33+
false,
34+
);
35+
eliminate_unused_storage_mark(body, bbs);
36+
strip_nops(bbs.as_mut_slice());
2337
let mut patch = MirPatch::new(body);
2438
for (bb, data) in body.basic_blocks.iter_enumerated() {
2539
match data.terminator().kind {
@@ -33,11 +47,17 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
3347
_ => continue,
3448
};
3549

36-
if SimplifyToIf.simplify(tcx, body, &mut patch, bb, typing_env).is_some() {
50+
if SimplifyToIf
51+
.simplify(tcx, body, bbs.as_slice(), &mut patch, bb, typing_env)
52+
.is_some()
53+
{
3754
apply_patch = true;
3855
continue;
3956
}
40-
if SimplifyToExp::default().simplify(tcx, body, &mut patch, bb, typing_env).is_some() {
57+
if SimplifyToExp::default()
58+
.simplify(tcx, body, bbs.as_slice(), &mut patch, bb, typing_env)
59+
.is_some()
60+
{
4161
apply_patch = true;
4262
continue;
4363
}
@@ -62,11 +82,11 @@ trait SimplifyMatch<'tcx> {
6282
&mut self,
6383
tcx: TyCtxt<'tcx>,
6484
body: &Body<'tcx>,
85+
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
6586
patch: &mut MirPatch<'tcx>,
6687
switch_bb_idx: BasicBlock,
6788
typing_env: ty::TypingEnv<'tcx>,
6889
) -> Option<()> {
69-
let bbs = &body.basic_blocks;
7090
let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
7191
TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets),
7292
_ => unreachable!(),
@@ -83,7 +103,7 @@ trait SimplifyMatch<'tcx> {
83103
let discr_local = patch.new_temp(discr_ty, source_info.span);
84104

85105
let (_, first) = targets.iter().next().unwrap();
86-
let statement_index = bbs[switch_bb_idx].statements.len();
106+
let statement_index = body.basic_blocks[switch_bb_idx].statements.len();
87107
let parent_end = Location { block: switch_bb_idx, statement_index };
88108
patch.add_statement(parent_end, StatementKind::StorageLive(discr_local));
89109
patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr));
@@ -526,3 +546,43 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
526546
}
527547
}
528548
}
549+
550+
struct EliminateUnusedStorageMark {
551+
storage_live_locals: IndexVec<Local, Option<usize>>,
552+
}
553+
554+
impl<'tcx> Visitor<'tcx> for EliminateUnusedStorageMark {
555+
fn visit_local(&mut self, local: Local, _: visit::PlaceContext, _: Location) {
556+
self.storage_live_locals[local] = None;
557+
}
558+
}
559+
560+
fn eliminate_unused_storage_mark<'tcx>(
561+
body: &Body<'tcx>,
562+
basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
563+
) {
564+
for (bb, data) in basic_blocks.iter_enumerated_mut() {
565+
let mut unused_storage_mark = EliminateUnusedStorageMark {
566+
storage_live_locals: IndexVec::from_elem_n(None, body.local_decls.len()),
567+
};
568+
for stmt_index in 0..data.statements.len() {
569+
let loc = Location { block: bb, statement_index: stmt_index };
570+
match data.statements[stmt_index].kind {
571+
StatementKind::StorageLive(local) => {
572+
unused_storage_mark.storage_live_locals[local] = Some(stmt_index);
573+
}
574+
StatementKind::StorageDead(local)
575+
if let Some(live_stmt_index) =
576+
unused_storage_mark.storage_live_locals[local] =>
577+
{
578+
data.statements[live_stmt_index].make_nop();
579+
data.statements[stmt_index].make_nop();
580+
unused_storage_mark.storage_live_locals[local] = None;
581+
}
582+
_ => {
583+
unused_storage_mark.visit_statement(&data.statements[stmt_index], loc);
584+
}
585+
}
586+
}
587+
}
588+
}

compiler/rustc_mir_transform/src/simplify.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
116116
}
117117

118118
fn simplify(mut self) {
119-
self.strip_nops();
119+
strip_nops(self.basic_blocks);
120120

121121
// Vec of the blocks that should be merged. We store the indices here, instead of the
122122
// statements itself to avoid moving the (relatively) large statements twice.
@@ -276,11 +276,11 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
276276
terminator.kind = TerminatorKind::Goto { target: first_succ };
277277
true
278278
}
279+
}
279280

280-
fn strip_nops(&mut self) {
281-
for blk in self.basic_blocks.iter_mut() {
282-
blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop))
283-
}
281+
pub(super) fn strip_nops(basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'_>>) {
282+
for blk in basic_blocks.iter_mut() {
283+
blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop))
284284
}
285285
}
286286

tests/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
+ _3 = Eq(copy _11, const 7_i32);
4646
_4 = const false;
4747
_5 = const true;
48-
_6 = ();
48+
- _6 = ();
4949
- goto -> bb3;
5050
- }
5151
-

tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@
3333
- bb2: {
3434
- _2 = const -1_i8;
3535
- _3 = const -1_i8;
36-
+ StorageLive(_8);
37-
+ _8 = move _5;
38-
+ _2 = copy _8 as i8 (IntToInt);
39-
+ _3 = copy _8 as i8 (IntToInt);
40-
_4 = ();
36+
- _4 = ();
4137
- goto -> bb6;
4238
- }
4339
-
@@ -63,6 +59,10 @@
6359
- }
6460
-
6561
- bb6: {
62+
+ StorageLive(_8);
63+
+ _8 = move _5;
64+
+ _2 = copy _8 as i8 (IntToInt);
65+
+ _3 = copy _8 as i8 (IntToInt);
6666
+ StorageDead(_8);
6767
StorageDead(_4);
6868
StorageLive(_6);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
- // MIR for `match_u8_i8_dead_store` before MatchBranchSimplification
2+
+ // MIR for `match_u8_i8_dead_store` after MatchBranchSimplification
3+
4+
fn match_u8_i8_dead_store(_1: EnumAu8) -> i8 {
5+
let mut _0: i8;
6+
let mut _2: u8;
7+
+ let mut _3: u8;
8+
9+
bb0: {
10+
_2 = discriminant(_1);
11+
- switchInt(copy _2) -> [0: bb1, 127: bb2, 128: bb3, 255: bb4, otherwise: bb5];
12+
- }
13+
-
14+
- bb1: {
15+
- _0 = const 0_i8;
16+
- goto -> bb6;
17+
- }
18+
-
19+
- bb2: {
20+
- _0 = const 1_i8;
21+
- _0 = const i8::MAX;
22+
- goto -> bb6;
23+
- }
24+
-
25+
- bb3: {
26+
- _0 = const i8::MIN;
27+
- goto -> bb6;
28+
- }
29+
-
30+
- bb4: {
31+
- _0 = const -1_i8;
32+
- goto -> bb6;
33+
- }
34+
-
35+
- bb5: {
36+
- unreachable;
37+
- }
38+
-
39+
- bb6: {
40+
+ StorageLive(_3);
41+
+ _3 = copy _2;
42+
+ _0 = copy _3 as i8 (IntToInt);
43+
+ StorageDead(_3);
44+
return;
45+
}
46+
}
47+

tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
bb2: {
1919
_0 = const i8::MAX;
20-
_0 = const i8::MAX;
20+
_0 = Add(copy _0, const 0_i8);
2121
goto -> bb6;
2222
}
2323

tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
bb4: {
2929
_0 = const -1_i8;
30-
_0 = const -1_i8;
30+
_0 = Add(copy _0, const 0_i8);
3131
goto -> bb6;
3232
}
3333

tests/mir-opt/matches_reduce_branches.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ fn match_u8_i8_failed_len_1(i: EnumAu8) -> i8 {
237237
}
238238
bb2 = {
239239
RET = 127;
240-
RET = 127;
240+
RET = RET + 0;
241241
Goto(ret)
242242
}
243243
bb3 = {
@@ -289,6 +289,50 @@ fn match_u8_i8_failed_len_2(i: EnumAu8) -> i8 {
289289
}
290290
bb4 = {
291291
RET = -1;
292+
RET = RET + 0;
293+
Goto(ret)
294+
}
295+
unreachable_bb = {
296+
Unreachable()
297+
}
298+
ret = {
299+
Return()
300+
}
301+
}
302+
}
303+
304+
// EMIT_MIR matches_reduce_branches.match_u8_i8_dead_store.MatchBranchSimplification.diff
305+
#[custom_mir(dialect = "built")]
306+
fn match_u8_i8_dead_store(i: EnumAu8) -> i8 {
307+
// CHECK-LABEL: fn match_u8_i8_dead_store(
308+
// CHECK-NOT: switchInt
309+
// CHECK: IntToInt
310+
// CHECK: return
311+
mir! {
312+
{
313+
let a = Discriminant(i);
314+
match a {
315+
0 => bb1,
316+
127 => bb2,
317+
128 => bb3,
318+
255 => bb4,
319+
_ => unreachable_bb,
320+
}
321+
}
322+
bb1 = {
323+
RET = 0;
324+
Goto(ret)
325+
}
326+
bb2 = {
327+
RET = 1; // This a dead store statement.
328+
RET = 127;
329+
Goto(ret)
330+
}
331+
bb3 = {
332+
RET = -128;
333+
Goto(ret)
334+
}
335+
bb4 = {
292336
RET = -1;
293337
Goto(ret)
294338
}

0 commit comments

Comments
 (0)