Skip to content

Commit e31d3e3

Browse files
Rollup merge of rust-lang#138545 - scottmcm:more-option-tests, r=Mark-Simulacrum
Add MIR pre-codegen tests to track rust-lang#138544 I don't know how best to fix the problem yet, but wanted to check in some tests to demonstrate it and make sure that they get updated to keep it fixed if anyone does fix it 🙂 No code changes; just the tests for rust-lang#138544.
2 parents 6756e3d + 1cdddd6 commit e31d3e3

8 files changed

+315
-4
lines changed

tests/mir-opt/pre-codegen/checked_ops.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// skip-filecheck
21
//@ compile-flags: -O -Zmir-opt-level=2
32
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
43

@@ -8,10 +7,48 @@
87
// EMIT_MIR checked_ops.step_forward.PreCodegen.after.mir
98
pub fn step_forward(x: u16, n: usize) -> u16 {
109
// This uses `u16` so that the conversion to usize is always widening.
10+
11+
// CHECK-LABEL: fn step_forward
12+
// CHECK: inlined{{.+}}forward
1113
std::iter::Step::forward(x, n)
1214
}
1315

1416
// EMIT_MIR checked_ops.checked_shl.PreCodegen.after.mir
1517
pub fn checked_shl(x: u32, rhs: u32) -> Option<u32> {
18+
// CHECK-LABEL: fn checked_shl
19+
// CHECK: [[TEMP:_[0-9]+]] = ShlUnchecked(copy _1, copy _2)
20+
// CHECK: _0 = Option::<u32>::Some({{move|copy}} [[TEMP]])
1621
x.checked_shl(rhs)
1722
}
23+
24+
// EMIT_MIR checked_ops.use_checked_sub.PreCodegen.after.mir
25+
pub fn use_checked_sub(x: u32, rhs: u32) {
26+
// We want this to be equivalent to open-coding it, leaving no `Option`s around.
27+
// FIXME(#138544): It's not yet.
28+
29+
// CHECK-LABEL: fn use_checked_sub
30+
// CHECK: inlined{{.+}}u32{{.+}}checked_sub
31+
// CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2)
32+
// CHECK: [[TEMP1:_.+]] = Option::<u32>::Some(move [[DELTA]]);
33+
// CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32);
34+
// CHECK: do_something({{move|copy}} [[TEMP2]])
35+
if let Some(delta) = x.checked_sub(rhs) {
36+
do_something(delta);
37+
}
38+
}
39+
40+
// EMIT_MIR checked_ops.saturating_sub_at_home.PreCodegen.after.mir
41+
pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 {
42+
// FIXME(#138544): Similarly here, the `Option` ought to optimize away
43+
44+
// CHECK-LABEL: fn saturating_sub_at_home
45+
// CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2)
46+
// CHECK: [[TEMP1:_.+]] = Option::<u32>::Some({{move|copy}} [[DELTA]]);
47+
// CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32);
48+
// CHECK: _0 = {{move|copy}} [[TEMP2]];
49+
u32::checked_sub(lhs, rhs).unwrap_or(0)
50+
}
51+
52+
unsafe extern "Rust" {
53+
safe fn do_something(_: u32);
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// MIR for `saturating_sub_at_home` after PreCodegen
2+
3+
fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
4+
debug lhs => _1;
5+
debug rhs => _2;
6+
let mut _0: u32;
7+
let mut _5: std::option::Option<u32>;
8+
scope 1 (inlined core::num::<impl u32>::checked_sub) {
9+
let mut _3: bool;
10+
let mut _4: u32;
11+
}
12+
scope 2 (inlined Option::<u32>::unwrap_or) {
13+
let _6: u32;
14+
scope 3 {
15+
}
16+
}
17+
18+
bb0: {
19+
StorageLive(_5);
20+
StorageLive(_3);
21+
_3 = Lt(copy _1, copy _2);
22+
switchInt(move _3) -> [0: bb1, otherwise: bb2];
23+
}
24+
25+
bb1: {
26+
StorageLive(_4);
27+
_4 = SubUnchecked(copy _1, copy _2);
28+
_5 = Option::<u32>::Some(move _4);
29+
StorageDead(_4);
30+
StorageDead(_3);
31+
StorageLive(_6);
32+
_6 = move ((_5 as Some).0: u32);
33+
_0 = move _6;
34+
StorageDead(_6);
35+
goto -> bb3;
36+
}
37+
38+
bb2: {
39+
StorageDead(_3);
40+
_0 = const 0_u32;
41+
goto -> bb3;
42+
}
43+
44+
bb3: {
45+
StorageDead(_5);
46+
return;
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// MIR for `saturating_sub_at_home` after PreCodegen
2+
3+
fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
4+
debug lhs => _1;
5+
debug rhs => _2;
6+
let mut _0: u32;
7+
let mut _5: std::option::Option<u32>;
8+
scope 1 (inlined core::num::<impl u32>::checked_sub) {
9+
let mut _3: bool;
10+
let mut _4: u32;
11+
}
12+
scope 2 (inlined Option::<u32>::unwrap_or) {
13+
let _6: u32;
14+
scope 3 {
15+
}
16+
}
17+
18+
bb0: {
19+
StorageLive(_5);
20+
StorageLive(_3);
21+
_3 = Lt(copy _1, copy _2);
22+
switchInt(move _3) -> [0: bb1, otherwise: bb2];
23+
}
24+
25+
bb1: {
26+
StorageLive(_4);
27+
_4 = SubUnchecked(copy _1, copy _2);
28+
_5 = Option::<u32>::Some(move _4);
29+
StorageDead(_4);
30+
StorageDead(_3);
31+
StorageLive(_6);
32+
_6 = move ((_5 as Some).0: u32);
33+
_0 = move _6;
34+
StorageDead(_6);
35+
goto -> bb3;
36+
}
37+
38+
bb2: {
39+
StorageDead(_3);
40+
_0 = const 0_u32;
41+
goto -> bb3;
42+
}
43+
44+
bb3: {
45+
StorageDead(_5);
46+
return;
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// MIR for `use_checked_sub` after PreCodegen
2+
3+
fn use_checked_sub(_1: u32, _2: u32) -> () {
4+
debug x => _1;
5+
debug rhs => _2;
6+
let mut _0: ();
7+
let mut _5: std::option::Option<u32>;
8+
let _7: ();
9+
scope 1 {
10+
debug delta => _6;
11+
let _6: u32;
12+
scope 2 (inlined core::num::<impl u32>::checked_sub) {
13+
let mut _3: bool;
14+
let mut _4: u32;
15+
}
16+
}
17+
18+
bb0: {
19+
StorageLive(_5);
20+
StorageLive(_3);
21+
_3 = Lt(copy _1, copy _2);
22+
switchInt(move _3) -> [0: bb1, otherwise: bb2];
23+
}
24+
25+
bb1: {
26+
StorageLive(_4);
27+
_4 = SubUnchecked(copy _1, copy _2);
28+
_5 = Option::<u32>::Some(move _4);
29+
StorageDead(_4);
30+
StorageDead(_3);
31+
_6 = copy ((_5 as Some).0: u32);
32+
_7 = do_something(move _6) -> [return: bb3, unwind unreachable];
33+
}
34+
35+
bb2: {
36+
StorageDead(_3);
37+
goto -> bb3;
38+
}
39+
40+
bb3: {
41+
StorageDead(_5);
42+
return;
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// MIR for `use_checked_sub` after PreCodegen
2+
3+
fn use_checked_sub(_1: u32, _2: u32) -> () {
4+
debug x => _1;
5+
debug rhs => _2;
6+
let mut _0: ();
7+
let mut _5: std::option::Option<u32>;
8+
let _7: ();
9+
scope 1 {
10+
debug delta => _6;
11+
let _6: u32;
12+
scope 2 (inlined core::num::<impl u32>::checked_sub) {
13+
let mut _3: bool;
14+
let mut _4: u32;
15+
}
16+
}
17+
18+
bb0: {
19+
StorageLive(_5);
20+
StorageLive(_3);
21+
_3 = Lt(copy _1, copy _2);
22+
switchInt(move _3) -> [0: bb1, otherwise: bb2];
23+
}
24+
25+
bb1: {
26+
StorageLive(_4);
27+
_4 = SubUnchecked(copy _1, copy _2);
28+
_5 = Option::<u32>::Some(move _4);
29+
StorageDead(_4);
30+
StorageDead(_3);
31+
_6 = copy ((_5 as Some).0: u32);
32+
_7 = do_something(move _6) -> [return: bb3, unwind continue];
33+
}
34+
35+
bb2: {
36+
StorageDead(_3);
37+
goto -> bb3;
38+
}
39+
40+
bb3: {
41+
StorageDead(_5);
42+
return;
43+
}
44+
}

tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
fn ezmap(_1: Option<i32>) -> Option<i32> {
44
debug x => _1;
55
let mut _0: std::option::Option<i32>;
6-
scope 1 (inlined map::<i32, i32, {closure@$DIR/simple_option_map.rs:17:12: 17:15}>) {
6+
scope 1 (inlined map::<i32, i32, {closure@$DIR/simple_option_map.rs:23:12: 23:15}>) {
77
let mut _2: isize;
88
let _3: i32;
99
let mut _4: i32;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// MIR for `map_via_question_mark` after PreCodegen
2+
3+
fn map_via_question_mark(_1: Option<i32>) -> Option<i32> {
4+
debug x => _1;
5+
let mut _0: std::option::Option<i32>;
6+
let mut _4: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, i32>;
7+
let _5: i32;
8+
let mut _6: i32;
9+
scope 1 {
10+
debug residual => const Option::<Infallible>::None;
11+
scope 2 {
12+
scope 7 (inlined <Option<i32> as FromResidual<Option<Infallible>>>::from_residual) {
13+
}
14+
}
15+
}
16+
scope 3 {
17+
debug val => _5;
18+
scope 4 {
19+
}
20+
}
21+
scope 5 (inlined <Option<i32> as Try>::branch) {
22+
let mut _2: isize;
23+
let _3: i32;
24+
scope 6 {
25+
}
26+
}
27+
28+
bb0: {
29+
StorageLive(_6);
30+
StorageLive(_4);
31+
StorageLive(_2);
32+
StorageLive(_3);
33+
_2 = discriminant(_1);
34+
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4];
35+
}
36+
37+
bb1: {
38+
StorageDead(_3);
39+
StorageDead(_2);
40+
_0 = const Option::<i32>::None;
41+
StorageDead(_6);
42+
StorageDead(_4);
43+
goto -> bb3;
44+
}
45+
46+
bb2: {
47+
_3 = copy ((_1 as Some).0: i32);
48+
_4 = ControlFlow::<Option<Infallible>, i32>::Continue(copy _3);
49+
StorageDead(_3);
50+
StorageDead(_2);
51+
_5 = copy ((_4 as Continue).0: i32);
52+
_6 = Add(copy _5, const 1_i32);
53+
_0 = Option::<i32>::Some(move _6);
54+
StorageDead(_6);
55+
StorageDead(_4);
56+
goto -> bb3;
57+
}
58+
59+
bb3: {
60+
return;
61+
}
62+
63+
bb4: {
64+
unreachable;
65+
}
66+
}
67+
68+
ALLOC0 (size: 8, align: 4) {
69+
00 00 00 00 __ __ __ __ │ ....░░░░
70+
}

tests/mir-opt/pre-codegen/simple_option_map.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
// skip-filecheck
21
//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
32

4-
#[inline(always)]
3+
#[inline]
54
fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
65
where
76
F: FnOnce(T) -> U,
@@ -14,9 +13,30 @@ where
1413

1514
// EMIT_MIR simple_option_map.ezmap.PreCodegen.after.mir
1615
pub fn ezmap(x: Option<i32>) -> Option<i32> {
16+
// We expect this to all be inlined, as though it was written without the
17+
// combinator and without the closure, using just a plain match.
18+
19+
// CHECK-LABEL: fn ezmap
20+
// CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32);
21+
// CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[INNER]], const 1_i32);
22+
// CHECK: _0 = Option::<i32>::Some({{copy|move}} [[SUCC]]);
1723
map(x, |n| n + 1)
1824
}
1925

26+
// EMIT_MIR simple_option_map.map_via_question_mark.PreCodegen.after.mir
27+
pub fn map_via_question_mark(x: Option<i32>) -> Option<i32> {
28+
// FIXME(#138544): Ideally this would optimize out the `ControlFlow` local.
29+
30+
// CHECK-LABEL: fn map_via_question_mark
31+
// CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32);
32+
// CHECK: [[TEMP1:_.+]] = ControlFlow::<Option<Infallible>, i32>::Continue(copy [[INNER]]);
33+
// CHECK: [[TEMP2:_.+]] = copy (([[TEMP1]] as Continue).0: i32);
34+
// CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[TEMP2]], const 1_i32);
35+
// CHECK: _0 = Option::<i32>::Some({{copy|move}} [[SUCC]]);
36+
Some(x? + 1)
37+
}
38+
2039
fn main() {
2140
assert_eq!(None, ezmap(None));
41+
assert_eq!(None, map_via_question_mark(None));
2242
}

0 commit comments

Comments
 (0)