Skip to content

Commit 66edf31

Browse files
committed
MatchBranchSimplification: Consider empty-unreachable otherwise branch
1 parent c15c1ec commit 66edf31

File tree

6 files changed

+71
-40
lines changed

6 files changed

+71
-40
lines changed

compiler/rustc_data_structures/src/packed.rs

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ impl Pu128 {
1818
}
1919
}
2020

21+
impl From<Pu128> for u128 {
22+
#[inline]
23+
fn from(value: Pu128) -> Self {
24+
value.get()
25+
}
26+
}
27+
2128
impl From<u128> for Pu128 {
2229
#[inline]
2330
fn from(value: u128) -> Self {

compiler/rustc_middle/src/mir/terminator.rs

+11
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ impl SwitchTargets {
6767
&mut self.targets
6868
}
6969

70+
/// Returns a slice with all considered values (not including the fallback).
71+
#[inline]
72+
pub fn all_values(&self) -> &[Pu128] {
73+
&self.values
74+
}
75+
76+
#[inline]
77+
pub fn all_values_mut(&mut self) -> &mut [Pu128] {
78+
&mut self.values
79+
}
80+
7081
/// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
7182
/// specific value. This cannot fail, as it'll return the `otherwise`
7283
/// branch if there's not a specific match for the value.

compiler/rustc_mir_transform/src/match_branches.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
77
use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
88
use rustc_target::abi::Integer;
99
use rustc_type_ir::TyKind::*;
10+
use tracing::instrument;
1011

1112
use super::simplify::simplify_cfg;
1213

@@ -57,7 +58,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
5758
}
5859

5960
trait SimplifyMatch<'tcx> {
60-
/// Simplifies a match statement, returning true if the simplification succeeds, false
61+
/// Simplifies a match statement, returning `Some` if the simplification succeeds, `None`
6162
/// otherwise. Generic code is written here, and we generally don't need a custom
6263
/// implementation.
6364
fn simplify(
@@ -156,6 +157,7 @@ struct SimplifyToIf;
156157
/// }
157158
/// ```
158159
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
160+
#[instrument(level = "debug", skip(self, tcx), ret)]
159161
fn can_simplify(
160162
&mut self,
161163
tcx: TyCtxt<'tcx>,
@@ -164,12 +166,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
164166
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
165167
_discr_ty: Ty<'tcx>,
166168
) -> Option<()> {
167-
if targets.iter().len() != 1 {
168-
return None;
169-
}
169+
let (first, second) = match targets.all_targets() {
170+
&[first, otherwise] => (first, otherwise),
171+
&[first, second, otherwise] if bbs[otherwise].is_empty_unreachable() => (first, second),
172+
_ => {
173+
return None;
174+
}
175+
};
176+
170177
// We require that the possible target blocks all be distinct.
171-
let (_, first) = targets.iter().next().unwrap();
172-
let second = targets.otherwise();
173178
if first == second {
174179
return None;
175180
}
@@ -218,8 +223,14 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
218223
discr_local: Local,
219224
discr_ty: Ty<'tcx>,
220225
) {
221-
let (val, first) = targets.iter().next().unwrap();
222-
let second = targets.otherwise();
226+
let ((val, first), second) = match (targets.all_targets(), targets.all_values()) {
227+
(&[first, otherwise], &[val]) => ((val, first), otherwise),
228+
(&[first, second, otherwise], &[val, _]) if bbs[otherwise].is_empty_unreachable() => {
229+
((val, first), second)
230+
}
231+
_ => unreachable!(),
232+
};
233+
223234
// We already checked that first and second are different blocks,
224235
// and bb_idx has a different terminator from both of them.
225236
let first = &bbs[first];
@@ -294,7 +305,7 @@ struct SimplifyToExp {
294305
transform_kinds: Vec<TransformKind>,
295306
}
296307

297-
#[derive(Clone, Copy)]
308+
#[derive(Clone, Copy, Debug)]
298309
enum ExpectedTransformKind<'a, 'tcx> {
299310
/// Identical statements.
300311
Same(&'a StatementKind<'tcx>),
@@ -359,6 +370,7 @@ impl From<ExpectedTransformKind<'_, '_>> for TransformKind {
359370
/// }
360371
/// ```
361372
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
373+
#[instrument(level = "debug", skip(self, tcx), ret)]
362374
fn can_simplify(
363375
&mut self,
364376
tcx: TyCtxt<'tcx>,

tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir

+8-12
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,20 @@ fn num_to_digit(_1: char) -> u32 {
2323
}
2424

2525
bb1: {
26-
StorageLive(_3);
2726
_3 = discriminant(_2);
28-
switchInt(move _3) -> [1: bb2, 0: bb6, otherwise: bb8];
27+
StorageDead(_2);
28+
switchInt(move _3) -> [1: bb2, otherwise: bb7];
2929
}
3030

3131
bb2: {
32-
StorageDead(_3);
33-
StorageDead(_2);
3432
StorageLive(_4);
3533
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
3634
}
3735

3836
bb3: {
3937
StorageLive(_5);
4038
_5 = discriminant(_4);
41-
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb8];
39+
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
4240
}
4341

4442
bb4: {
@@ -49,21 +47,19 @@ fn num_to_digit(_1: char) -> u32 {
4947
_0 = move ((_4 as Some).0: u32);
5048
StorageDead(_5);
5149
StorageDead(_4);
52-
goto -> bb7;
50+
goto -> bb8;
5351
}
5452

5553
bb6: {
56-
StorageDead(_3);
57-
StorageDead(_2);
58-
_0 = const 0_u32;
59-
goto -> bb7;
54+
unreachable;
6055
}
6156

6257
bb7: {
63-
return;
58+
_0 = const 0_u32;
59+
goto -> bb8;
6460
}
6561

6662
bb8: {
67-
unreachable;
63+
return;
6864
}
6965
}

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

+23-18
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,32 @@
44
fn my_is_some(_1: Option<T>) -> bool {
55
let mut _0: bool;
66
let mut _2: isize;
7+
+ let mut _3: isize;
78

89
bb0: {
910
_2 = discriminant(_1);
10-
switchInt(copy _2) -> [0: bb1, 1: bb2, otherwise: bb3];
11-
}
12-
13-
bb1: {
14-
_0 = const false;
15-
goto -> bb4;
16-
}
17-
18-
bb2: {
19-
_0 = const true;
20-
goto -> bb4;
21-
}
22-
23-
bb3: {
24-
unreachable;
25-
}
26-
27-
bb4: {
11+
- switchInt(copy _2) -> [0: bb1, 1: bb2, otherwise: bb3];
12+
- }
13+
-
14+
- bb1: {
15+
- _0 = const false;
16+
- goto -> bb4;
17+
- }
18+
-
19+
- bb2: {
20+
- _0 = const true;
21+
- goto -> bb4;
22+
- }
23+
-
24+
- bb3: {
25+
- unreachable;
26+
- }
27+
-
28+
- bb4: {
29+
+ StorageLive(_3);
30+
+ _3 = copy _2;
31+
+ _0 = Ne(copy _3, const 0_isize);
32+
+ StorageDead(_3);
2833
return;
2934
}
3035
}

tests/mir-opt/matches_reduce_branches.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn foo(bar: Option<()>) {
2525
#[custom_mir(dialect = "built")]
2626
fn my_is_some<T>(bar: Option<T>) -> bool {
2727
// CHECK-LABEL: fn my_is_some(
28-
// CHECK: switchInt
28+
// CHECK: = Ne
2929
// CHECK: return
3030
mir! {
3131
{

0 commit comments

Comments
 (0)