Skip to content

Commit 081074b

Browse files
committed
Make the EarlyOtherwiseBranch optimization less conservative
It is not important that the types match in this optimization. Instead, we can apply the optimization more liberally if the layouts match. Locally when compiling stage 1 std, stage2 and stage 2 std this increases the times the optimization fires from 543 to 573. A ~5% increase.
1 parent 8fe73e8 commit 081074b

File tree

4 files changed

+109
-10
lines changed

4 files changed

+109
-10
lines changed

compiler/rustc_mir/src/transform/early_otherwise_branch.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::{
22
transform::{MirPass, MirSource},
33
util::patch::MirPatch,
44
};
5-
use rustc_middle::mir::*;
65
use rustc_middle::ty::{Ty, TyCtxt};
6+
use rustc_middle::{mir::*, ty::ParamEnv};
77
use std::{borrow::Cow, fmt::Debug};
88

99
use super::simplify::simplify_cfg;
@@ -40,7 +40,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
4040
let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
4141
.flat_map(|(bb_idx, bb)| {
4242
let switch = bb.terminator();
43-
let helper = Helper { body, tcx };
43+
let helper = Helper { body, tcx, param_env: tcx.param_env(source.def_id()) };
4444
let infos = helper.go(bb, switch)?;
4545
Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
4646
})
@@ -170,6 +170,7 @@ fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
170170
struct Helper<'a, 'tcx> {
171171
body: &'a Body<'tcx>,
172172
tcx: TyCtxt<'tcx>,
173+
param_env: ParamEnv<'tcx>,
173174
}
174175

175176
#[derive(Debug, Clone)]
@@ -239,13 +240,13 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
239240
if is_switch(terminator) {
240241
let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;
241242

242-
// the types of the two adts matched on have to be equalfor this optimization to apply
243-
if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
244-
trace!(
245-
"NO: types do not match. LHS: {:?}, RHS: {:?}",
246-
discr_info.type_adt_matched_on,
247-
this_bb_discr_info.type_adt_matched_on
248-
);
243+
// The layouts of the two ADTs have to be equal for this optimization to apply
244+
let layout_of_adt =
245+
|ty: Ty<'tcx>| self.tcx.layout_of(self.param_env.and(ty)).ok().map(|x| x.layout);
246+
let layout_lhs = layout_of_adt(discr_info.type_adt_matched_on);
247+
let layout_rhs = layout_of_adt(this_bb_discr_info.type_adt_matched_on);
248+
if layout_lhs != layout_rhs {
249+
trace!("NO: Layouts do not match. LHS: {:?}, RHS: {:?}", layout_lhs, layout_rhs);
249250
return None;
250251
}
251252

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
- // MIR for `opt3` before EarlyOtherwiseBranch
2+
+ // MIR for `opt3` after EarlyOtherwiseBranch
3+
4+
fn opt3(_1: MyOption1<u32>, _2: MyOption2<u32>) -> u32 {
5+
debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:31:9: 31:10
6+
debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:31:28: 31:29
7+
let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:31:50: 31:53
8+
let mut _3: (MyOption1<u32>, MyOption2<u32>); // in scope 0 at $DIR/early_otherwise_branch.rs:32:11: 32:17
9+
let mut _4: MyOption1<u32>; // in scope 0 at $DIR/early_otherwise_branch.rs:32:12: 32:13
10+
let mut _5: MyOption2<u32>; // in scope 0 at $DIR/early_otherwise_branch.rs:32:15: 32:16
11+
let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
12+
let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
13+
let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:33:26: 33:27
14+
let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:33:46: 33:47
15+
+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
16+
+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
17+
scope 1 {
18+
debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:33:26: 33:27
19+
debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:33:46: 33:47
20+
}
21+
22+
bb0: {
23+
StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:32:11: 32:17
24+
StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:32:12: 32:13
25+
_4 = move _1; // scope 0 at $DIR/early_otherwise_branch.rs:32:12: 32:13
26+
StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:32:15: 32:16
27+
_5 = move _2; // scope 0 at $DIR/early_otherwise_branch.rs:32:15: 32:16
28+
(_3.0: MyOption1<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:32:11: 32:17
29+
(_3.1: MyOption2<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:32:11: 32:17
30+
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:32:16: 32:17
31+
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:32:16: 32:17
32+
_7 = discriminant((_3.0: MyOption1<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
33+
- switchInt(move _7) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
34+
+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
35+
+ _10 = discriminant((_3.1: MyOption2<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
36+
+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
37+
+ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
38+
+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
39+
+ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:33:10: 33:28
40+
}
41+
42+
bb1: {
43+
- _6 = discriminant((_3.1: MyOption2<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
44+
- switchInt(move _6) -> [0_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
45+
- }
46+
-
47+
- bb2: {
48+
+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:34:14: 34:15
49+
_0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:34:14: 34:15
50+
- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:32:5: 35:6
51+
+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:32:5: 35:6
52+
}
53+
54+
- bb3: {
55+
+ bb2: {
56+
StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:33:26: 33:27
57+
_8 = (((_3.0: MyOption1<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:33:26: 33:27
58+
StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:33:46: 33:47
59+
_9 = (((_3.1: MyOption2<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:33:46: 33:47
60+
_0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:33:53: 33:54
61+
StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:33:53: 33:54
62+
StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:33:53: 33:54
63+
- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:32:5: 35:6
64+
+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:32:5: 35:6
65+
}
66+
67+
- bb4: {
68+
+ bb3: {
69+
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:36:1: 36:2
70+
return; // scope 0 at $DIR/early_otherwise_branch.rs:36:2: 36:2
71+
+ }
72+
+
73+
+ bb4: {
74+
+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
75+
+ switchInt(_7) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:33:30: 33:48
76+
}
77+
}
78+

src/test/mir-opt/early_otherwise_branch.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,27 @@ fn opt2(x: Option<u32>, y: Option<u32>) -> u32 {
1616
}
1717
}
1818

19+
enum MyOption1<T> {
20+
Some(T),
21+
None,
22+
}
23+
24+
enum MyOption2<T> {
25+
Some(T),
26+
None,
27+
}
28+
29+
// must optimize as the tag encoding of the discriminant are the same
30+
// EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
31+
fn opt3(x: MyOption1<u32>, y: MyOption2<u32>) -> u32 {
32+
match (x, y) {
33+
(MyOption1::Some(a), MyOption2::Some(b)) => 0,
34+
_ => 1,
35+
}
36+
}
37+
1938
fn main() {
2039
opt1(None, Some(0));
2140
opt2(None, Some(0));
41+
opt3(MyOption1::None, MyOption2::Some(0));
2242
}

src/test/mir-opt/early_otherwise_branch_noopt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 {
1313
}
1414
}
1515

16-
// must not optimize as the types being matched on are not identical
16+
// must not optimize as the tag encodings of the discriminant are not the same
1717
// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff
1818
fn noopt2(x: Option<u32>, y: Option<bool>) -> u32 {
1919
match (x, y) {

0 commit comments

Comments
 (0)