Skip to content

Commit a6fe969

Browse files
committed
Auto merge of rust-lang#93387 - JakobDegen:improve_partialeq, r=tmiasko
Extend uninhabited enum variant branch elimination to also affect fallthrough The `uninhabited_enum_branching` mir opt eliminates branches on variants where the data is uninhabited. This change extends this pass to also ensure that the `otherwise` case points to a trivially unreachable bb if all inhabited variants are present in the non-otherwise branches. I believe it was `@scottmcm` who said that LLVM eliminates some of this information in its SimplifyCFG pass. This is unfortunate, but this change should still be at least a small improvement in principle (I don't think it will show up on any benchmarks)
2 parents 25ad89e + 0783009 commit a6fe969

7 files changed

+167
-20
lines changed

compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
use crate::MirPass;
44
use rustc_data_structures::stable_set::FxHashSet;
55
use rustc_middle::mir::{
6-
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind,
6+
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator,
7+
TerminatorKind,
78
};
89
use rustc_middle::ty::layout::TyAndLayout;
910
use rustc_middle::ty::{Ty, TyCtxt};
@@ -71,6 +72,28 @@ fn variant_discriminants<'tcx>(
7172
}
7273
}
7374

75+
/// Ensures that the `otherwise` branch leads to an unreachable bb, returning `None` if so and a new
76+
/// bb to use as the new target if not.
77+
fn ensure_otherwise_unreachable<'tcx>(
78+
body: &Body<'tcx>,
79+
targets: &SwitchTargets,
80+
) -> Option<BasicBlockData<'tcx>> {
81+
let otherwise = targets.otherwise();
82+
let bb = &body.basic_blocks()[otherwise];
83+
if bb.terminator().kind == TerminatorKind::Unreachable
84+
&& bb.statements.iter().all(|s| matches!(&s.kind, StatementKind::StorageDead(_)))
85+
{
86+
return None;
87+
}
88+
89+
let mut new_block = BasicBlockData::new(Some(Terminator {
90+
source_info: bb.terminator().source_info,
91+
kind: TerminatorKind::Unreachable,
92+
}));
93+
new_block.is_cleanup = bb.is_cleanup;
94+
Some(new_block)
95+
}
96+
7497
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
7598
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
7699
sess.mir_opt_level() > 0
@@ -99,12 +122,25 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
99122
if let TerminatorKind::SwitchInt { targets, .. } =
100123
&mut body.basic_blocks_mut()[bb].terminator_mut().kind
101124
{
102-
let new_targets = SwitchTargets::new(
125+
let mut new_targets = SwitchTargets::new(
103126
targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
104127
targets.otherwise(),
105128
);
106129

107-
*targets = new_targets;
130+
if new_targets.iter().count() == allowed_variants.len() {
131+
if let Some(updated) = ensure_otherwise_unreachable(body, &new_targets) {
132+
let new_otherwise = body.basic_blocks_mut().push(updated);
133+
*new_targets.all_targets_mut().last_mut().unwrap() = new_otherwise;
134+
}
135+
}
136+
137+
if let TerminatorKind::SwitchInt { targets, .. } =
138+
&mut body.basic_blocks_mut()[bb].terminator_mut().kind
139+
{
140+
*targets = new_targets;
141+
} else {
142+
unreachable!()
143+
}
108144
} else {
109145
unreachable!()
110146
}

src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff

+5-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
3232
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
3333
_8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
34-
- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
34+
- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb7]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
3535
+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
3636
+ _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
3737
+ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
@@ -81,8 +81,10 @@
8181
+ bb4: {
8282
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2
8383
return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2
84-
+ }
85-
+
84+
}
85+
86+
- bb7: {
87+
- unreachable; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15
8688
+ bb5: {
8789
+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
8890
+ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17

src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff

+14-11
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
8282
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
8383
_11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
84-
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
84+
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
8585
+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
8686
+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
8787
+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -217,14 +217,9 @@
217217
- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
218218
- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
219219
- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
220-
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
221-
+ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
222-
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
223-
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
224-
+ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
225-
}
226-
227-
bb7: {
220+
- }
221+
-
222+
- bb7: {
228223
- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
229224
- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
230225
- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
@@ -289,10 +284,18 @@
289284
-
290285
- bb10: {
291286
- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
292-
- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
287+
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
288+
discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
293289
- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
294290
- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
295-
- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
291+
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
292+
+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
293+
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
294+
}
295+
296+
- bb11: {
297+
- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
298+
+ bb7: {
296299
+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
297300
+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
298301
}

src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff

+5-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
6868
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
6969
_11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
70-
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
70+
- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
7171
+ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
7272
+ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
7373
+ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
@@ -206,8 +206,10 @@
206206
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
207207
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
208208
return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
209-
+ }
210-
+
209+
}
210+
211+
- bb11: {
212+
- unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
211213
+ bb7: {
212214
+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
213215
+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
- // MIR for `eliminate_fallthrough` before UninhabitedEnumBranching
2+
+ // MIR for `eliminate_fallthrough` after UninhabitedEnumBranching
3+
4+
fn eliminate_fallthrough(_1: S) -> u32 {
5+
debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:26: 21:27
6+
let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:35: 21:38
7+
let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:9: 23:10
8+
9+
bb0: {
10+
_2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:11: 22:12
11+
- switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
12+
+ switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
13+
}
14+
15+
bb1: {
16+
_0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15
17+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15
18+
}
19+
20+
bb2: {
21+
_0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:14: 23:15
22+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:23:14: 23:15
23+
}
24+
25+
bb3: {
26+
_0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:24:14: 24:15
27+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:24:14: 24:15
28+
}
29+
30+
bb4: {
31+
return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:27:2: 27:2
32+
+ }
33+
+
34+
+ bb5: {
35+
+ unreachable; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15
36+
}
37+
}
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
- // MIR for `keep_fallthrough` before UninhabitedEnumBranching
2+
+ // MIR for `keep_fallthrough` after UninhabitedEnumBranching
3+
4+
fn keep_fallthrough(_1: S) -> u32 {
5+
debug s => _1; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:21: 12:22
6+
let mut _0: u32; // return place in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:30: 12:33
7+
let mut _2: isize; // in scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:9: 14:13
8+
9+
bb0: {
10+
_2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:11: 13:12
11+
- switchInt(move _2) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:5: 13:12
12+
+ switchInt(move _2) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:13:5: 13:12
13+
}
14+
15+
bb1: {
16+
_0 = const 3_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:16:14: 16:15
17+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:16:14: 16:15
18+
}
19+
20+
bb2: {
21+
_0 = const 1_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:17: 14:18
22+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:14:17: 14:18
23+
}
24+
25+
bb3: {
26+
_0 = const 2_u32; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:15:14: 15:15
27+
goto -> bb4; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:15:14: 15:15
28+
}
29+
30+
bb4: {
31+
return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:18:2: 18:2
32+
}
33+
}
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
enum Empty {}
2+
3+
enum S {
4+
A(Empty),
5+
B,
6+
C,
7+
}
8+
9+
use S::*;
10+
11+
// EMIT_MIR uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
12+
fn keep_fallthrough(s: S) -> u32 {
13+
match s {
14+
A(_) => 1,
15+
B => 2,
16+
_ => 3,
17+
}
18+
}
19+
20+
// EMIT_MIR uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
21+
fn eliminate_fallthrough(s: S) -> u32 {
22+
match s {
23+
C => 1,
24+
B => 2,
25+
_ => 3,
26+
}
27+
}
28+
29+
fn main() {
30+
keep_fallthrough(B);
31+
eliminate_fallthrough(B);
32+
}

0 commit comments

Comments
 (0)