Skip to content

Commit 1cdddd6

Browse files
committed
Add MIR pre-codegen tests to track 138544
1 parent ecade53 commit 1cdddd6

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)