Skip to content

Commit 30b690b

Browse files
committed
Apply EarlyOtherwiseBranch even if the types are different when the target values are the same
1 parent e73ae2f commit 30b690b

5 files changed

+307
-3
lines changed

compiler/rustc_mir_transform/src/early_otherwise_branch.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,6 @@ fn evaluate_candidate<'tcx>(
334334
return None;
335335
};
336336
let child_ty = child_discr.ty(body.local_decls(), tcx);
337-
if child_ty != parent_ty {
338-
return None;
339-
}
340337
if bbs[child].statements.len() > 1 {
341338
return None;
342339
}
@@ -424,6 +421,9 @@ fn evaluate_candidate<'tcx>(
424421
}
425422
}
426423
if same_target_value.is_none() {
424+
if child_ty != parent_ty {
425+
return None;
426+
}
427427
for (value, child) in targets.iter() {
428428
if !verify_candidate_branch(
429429
&bbs[child],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
- // MIR for `opt10` before EarlyOtherwiseBranch
2+
+ // MIR for `opt10` after EarlyOtherwiseBranch
3+
4+
fn opt10(_1: E8, _2: E16) -> u32 {
5+
debug x => _1;
6+
debug y => _2;
7+
let mut _0: u32;
8+
let mut _3: (E8, E16);
9+
let mut _4: E8;
10+
let mut _5: E16;
11+
let mut _6: u16;
12+
let mut _7: u16;
13+
let mut _8: u16;
14+
let mut _9: u8;
15+
+ let mut _10: u16;
16+
17+
bb0: {
18+
StorageLive(_3);
19+
StorageLive(_4);
20+
_4 = move _1;
21+
StorageLive(_5);
22+
_5 = move _2;
23+
_3 = (move _4, move _5);
24+
StorageDead(_5);
25+
StorageDead(_4);
26+
_9 = discriminant((_3.0: E8));
27+
- switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
28+
+ StorageLive(_10);
29+
+ _10 = discriminant((_3.1: E16));
30+
+ switchInt(move _10) -> [0: bb6, otherwise: bb1];
31+
}
32+
33+
bb1: {
34+
+ StorageDead(_10);
35+
_0 = const 0_u32;
36+
- goto -> bb8;
37+
+ goto -> bb5;
38+
}
39+
40+
bb2: {
41+
- _6 = discriminant((_3.1: E16));
42+
- switchInt(move _6) -> [0: bb5, otherwise: bb1];
43+
- }
44+
-
45+
- bb3: {
46+
- _7 = discriminant((_3.1: E16));
47+
- switchInt(move _7) -> [0: bb6, otherwise: bb1];
48+
- }
49+
-
50+
- bb4: {
51+
- _8 = discriminant((_3.1: E16));
52+
- switchInt(move _8) -> [0: bb7, otherwise: bb1];
53+
- }
54+
-
55+
- bb5: {
56+
_0 = const 1_u32;
57+
- goto -> bb8;
58+
+ goto -> bb5;
59+
}
60+
61+
- bb6: {
62+
+ bb3: {
63+
_0 = const 2_u32;
64+
- goto -> bb8;
65+
+ goto -> bb5;
66+
}
67+
68+
- bb7: {
69+
+ bb4: {
70+
_0 = const 3_u32;
71+
- goto -> bb8;
72+
+ goto -> bb5;
73+
}
74+
75+
- bb8: {
76+
+ bb5: {
77+
StorageDead(_3);
78+
return;
79+
}
80+
81+
- bb9: {
82+
- unreachable;
83+
+ bb6: {
84+
+ StorageDead(_10);
85+
+ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
86+
}
87+
}
88+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
- // MIR for `opt8` before EarlyOtherwiseBranch
2+
+ // MIR for `opt8` after EarlyOtherwiseBranch
3+
4+
fn opt8(_1: u32, _2: u64) -> u32 {
5+
debug x => _1;
6+
debug y => _2;
7+
let mut _0: u32;
8+
let mut _3: (u32, u64);
9+
let mut _4: u32;
10+
let mut _5: u64;
11+
12+
bb0: {
13+
StorageLive(_3);
14+
StorageLive(_4);
15+
_4 = _1;
16+
StorageLive(_5);
17+
_5 = _2;
18+
_3 = (move _4, move _5);
19+
StorageDead(_5);
20+
StorageDead(_4);
21+
- switchInt((_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
22+
+ switchInt((_3.1: u64)) -> [10: bb6, otherwise: bb1];
23+
}
24+
25+
bb1: {
26+
_0 = const 0_u32;
27+
- goto -> bb8;
28+
+ goto -> bb5;
29+
}
30+
31+
bb2: {
32+
- switchInt((_3.1: u64)) -> [10: bb5, otherwise: bb1];
33+
+ _0 = const 4_u32;
34+
+ goto -> bb5;
35+
}
36+
37+
bb3: {
38+
- switchInt((_3.1: u64)) -> [10: bb6, otherwise: bb1];
39+
+ _0 = const 5_u32;
40+
+ goto -> bb5;
41+
}
42+
43+
bb4: {
44+
- switchInt((_3.1: u64)) -> [10: bb7, otherwise: bb1];
45+
+ _0 = const 6_u32;
46+
+ goto -> bb5;
47+
}
48+
49+
bb5: {
50+
- _0 = const 4_u32;
51+
- goto -> bb8;
52+
+ StorageDead(_3);
53+
+ return;
54+
}
55+
56+
bb6: {
57+
- _0 = const 5_u32;
58+
- goto -> bb8;
59+
- }
60+
-
61+
- bb7: {
62+
- _0 = const 6_u32;
63+
- goto -> bb8;
64+
- }
65+
-
66+
- bb8: {
67+
- StorageDead(_3);
68+
- return;
69+
+ switchInt((_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
70+
}
71+
}
72+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
- // MIR for `opt9` before EarlyOtherwiseBranch
2+
+ // MIR for `opt9` after EarlyOtherwiseBranch
3+
4+
fn opt9(_1: E8, _2: E16) -> u32 {
5+
debug x => _1;
6+
debug y => _2;
7+
let mut _0: u32;
8+
let mut _3: (E8, E16);
9+
let mut _4: E8;
10+
let mut _5: E16;
11+
let mut _6: u16;
12+
let mut _7: u16;
13+
let mut _8: u16;
14+
let mut _9: u8;
15+
16+
bb0: {
17+
StorageLive(_3);
18+
StorageLive(_4);
19+
_4 = move _1;
20+
StorageLive(_5);
21+
_5 = move _2;
22+
_3 = (move _4, move _5);
23+
StorageDead(_5);
24+
StorageDead(_4);
25+
_9 = discriminant((_3.0: E8));
26+
switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
27+
}
28+
29+
bb1: {
30+
_0 = const 0_u32;
31+
goto -> bb8;
32+
}
33+
34+
bb2: {
35+
_6 = discriminant((_3.1: E16));
36+
switchInt(move _6) -> [0: bb5, otherwise: bb1];
37+
}
38+
39+
bb3: {
40+
_7 = discriminant((_3.1: E16));
41+
switchInt(move _7) -> [1: bb6, otherwise: bb1];
42+
}
43+
44+
bb4: {
45+
_8 = discriminant((_3.1: E16));
46+
switchInt(move _8) -> [2: bb7, otherwise: bb1];
47+
}
48+
49+
bb5: {
50+
_0 = const 1_u32;
51+
goto -> bb8;
52+
}
53+
54+
bb6: {
55+
_0 = const 2_u32;
56+
goto -> bb8;
57+
}
58+
59+
bb7: {
60+
_0 = const 3_u32;
61+
goto -> bb8;
62+
}
63+
64+
bb8: {
65+
StorageDead(_3);
66+
return;
67+
}
68+
69+
bb9: {
70+
unreachable;
71+
}
72+
}
73+

tests/mir-opt/early_otherwise_branch.rs

+71
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,74 @@ fn opt7(x: Option<u32>, y: Option<u32>) -> u32 {
115115
}
116116
}
117117

118+
// EMIT_MIR early_otherwise_branch.opt8.EarlyOtherwiseBranch.diff
119+
fn opt8(x: u32, y: u64) -> u32 {
120+
// CHECK-LABEL: fn opt8(
121+
// CHECK: bb0: {
122+
// CHECK: switchInt((_{{.*}}: u64)) -> [10: [[SWITCH_BB:bb.*]], otherwise: [[OTHERWISE:bb.*]]];
123+
// CHECK-NEXT: }
124+
// CHECK: [[SWITCH_BB]]:
125+
// CHECK: switchInt((_{{.*}}: u32)) -> [1: bb{{.*}}, 2: bb{{.*}}, 3: bb{{.*}}, otherwise: [[OTHERWISE]]];
126+
// CHECK-NEXT: }
127+
match (x, y) {
128+
(1, 10) => 4,
129+
(2, 10) => 5,
130+
(3, 10) => 6,
131+
_ => 0,
132+
}
133+
}
134+
135+
#[repr(u8)]
136+
enum E8 {
137+
A,
138+
B,
139+
C,
140+
}
141+
142+
#[repr(u16)]
143+
enum E16 {
144+
A,
145+
B,
146+
C,
147+
}
148+
149+
// Can we add a cast instruction for transformation?
150+
// EMIT_MIR early_otherwise_branch.opt9.EarlyOtherwiseBranch.diff
151+
fn opt9(x: E8, y: E16) -> u32 {
152+
// CHECK-LABEL: fn opt9(
153+
// CHECK: bb0: {
154+
// CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
155+
// CHECK-NOT: discriminant
156+
// CHECK: switchInt(move [[LOCAL1]]) -> [
157+
// CHECK-NEXT: }
158+
match (x, y) {
159+
(E8::A, E16::A) => 1,
160+
(E8::B, E16::B) => 2,
161+
(E8::C, E16::C) => 3,
162+
_ => 0,
163+
}
164+
}
165+
166+
// Since the target values are the same, we can optimize.
167+
// EMIT_MIR early_otherwise_branch.opt10.EarlyOtherwiseBranch.diff
168+
fn opt10(x: E8, y: E16) -> u32 {
169+
// CHECK-LABEL: fn opt10(
170+
// CHECK: bb0: {
171+
// CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
172+
// CHECK: [[LOCAL2:_.*]] = discriminant({{.*}});
173+
// CHECK: switchInt(move [[LOCAL2]]) -> [0: [[SWITCH_BB:bb.*]], otherwise: [[OTHERWISE:bb.*]]];
174+
// CHECK-NEXT: }
175+
// CHECK: [[SWITCH_BB]]:
176+
// CHECK: switchInt([[LOCAL1]]) -> [0: bb{{.*}}, 1: bb{{.*}}, 2: bb{{.*}}, otherwise: [[OTHERWISE]]];
177+
// CHECK-NEXT: }
178+
match (x, y) {
179+
(E8::A, E16::A) => 1,
180+
(E8::B, E16::A) => 2,
181+
(E8::C, E16::A) => 3,
182+
_ => 0,
183+
}
184+
}
185+
118186
fn main() {
119187
opt1(None, Some(0));
120188
opt2(None, Some(0));
@@ -123,4 +191,7 @@ fn main() {
123191
opt5(0, 0);
124192
opt6(0, 0);
125193
opt7(None, Some(0));
194+
opt8(0, 0);
195+
opt9(E8::A, E16::A);
196+
opt10(E8::A, E16::A);
126197
}

0 commit comments

Comments
 (0)