diff --git a/tests/mir-opt/pre-codegen/checked_ops.rs b/tests/mir-opt/pre-codegen/checked_ops.rs index 56f8e3f833845..8fd340503f548 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.rs +++ b/tests/mir-opt/pre-codegen/checked_ops.rs @@ -1,4 +1,3 @@ -// skip-filecheck //@ compile-flags: -O -Zmir-opt-level=2 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -8,10 +7,48 @@ // EMIT_MIR checked_ops.step_forward.PreCodegen.after.mir pub fn step_forward(x: u16, n: usize) -> u16 { // This uses `u16` so that the conversion to usize is always widening. + + // CHECK-LABEL: fn step_forward + // CHECK: inlined{{.+}}forward std::iter::Step::forward(x, n) } // EMIT_MIR checked_ops.checked_shl.PreCodegen.after.mir pub fn checked_shl(x: u32, rhs: u32) -> Option { + // CHECK-LABEL: fn checked_shl + // CHECK: [[TEMP:_[0-9]+]] = ShlUnchecked(copy _1, copy _2) + // CHECK: _0 = Option::::Some({{move|copy}} [[TEMP]]) x.checked_shl(rhs) } + +// EMIT_MIR checked_ops.use_checked_sub.PreCodegen.after.mir +pub fn use_checked_sub(x: u32, rhs: u32) { + // We want this to be equivalent to open-coding it, leaving no `Option`s around. + // FIXME(#138544): It's not yet. + + // CHECK-LABEL: fn use_checked_sub + // CHECK: inlined{{.+}}u32{{.+}}checked_sub + // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2) + // CHECK: [[TEMP1:_.+]] = Option::::Some(move [[DELTA]]); + // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32); + // CHECK: do_something({{move|copy}} [[TEMP2]]) + if let Some(delta) = x.checked_sub(rhs) { + do_something(delta); + } +} + +// EMIT_MIR checked_ops.saturating_sub_at_home.PreCodegen.after.mir +pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 { + // FIXME(#138544): Similarly here, the `Option` ought to optimize away + + // CHECK-LABEL: fn saturating_sub_at_home + // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2) + // CHECK: [[TEMP1:_.+]] = Option::::Some({{move|copy}} [[DELTA]]); + // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32); + // CHECK: _0 = {{move|copy}} [[TEMP2]]; + u32::checked_sub(lhs, rhs).unwrap_or(0) +} + +unsafe extern "Rust" { + safe fn do_something(_: u32); +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..5b4fdeda85731 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir @@ -0,0 +1,48 @@ +// MIR for `saturating_sub_at_home` after PreCodegen + +fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { + debug lhs => _1; + debug rhs => _2; + let mut _0: u32; + let mut _5: std::option::Option; + scope 1 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + scope 2 (inlined Option::::unwrap_or) { + let _6: u32; + scope 3 { + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_6); + _6 = move ((_5 as Some).0: u32); + _0 = move _6; + StorageDead(_6); + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..5b4fdeda85731 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,48 @@ +// MIR for `saturating_sub_at_home` after PreCodegen + +fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { + debug lhs => _1; + debug rhs => _2; + let mut _0: u32; + let mut _5: std::option::Option; + scope 1 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + scope 2 (inlined Option::::unwrap_or) { + let _6: u32; + scope 3 { + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + StorageLive(_6); + _6 = move ((_5 as Some).0: u32); + _0 = move _6; + StorageDead(_6); + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..3c475cd403091 --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-abort.mir @@ -0,0 +1,44 @@ +// MIR for `use_checked_sub` after PreCodegen + +fn use_checked_sub(_1: u32, _2: u32) -> () { + debug x => _1; + debug rhs => _2; + let mut _0: (); + let mut _5: std::option::Option; + let _7: (); + scope 1 { + debug delta => _6; + let _6: u32; + scope 2 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + _6 = copy ((_5 as Some).0: u32); + _7 = do_something(move _6) -> [return: bb3, unwind unreachable]; + } + + bb2: { + StorageDead(_3); + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..3ef09764b1c5b --- /dev/null +++ b/tests/mir-opt/pre-codegen/checked_ops.use_checked_sub.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,44 @@ +// MIR for `use_checked_sub` after PreCodegen + +fn use_checked_sub(_1: u32, _2: u32) -> () { + debug x => _1; + debug rhs => _2; + let mut _0: (); + let mut _5: std::option::Option; + let _7: (); + scope 1 { + debug delta => _6; + let _6: u32; + scope 2 (inlined core::num::::checked_sub) { + let mut _3: bool; + let mut _4: u32; + } + } + + bb0: { + StorageLive(_5); + StorageLive(_3); + _3 = Lt(copy _1, copy _2); + switchInt(move _3) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_4); + _4 = SubUnchecked(copy _1, copy _2); + _5 = Option::::Some(move _4); + StorageDead(_4); + StorageDead(_3); + _6 = copy ((_5 as Some).0: u32); + _7 = do_something(move _6) -> [return: bb3, unwind continue]; + } + + bb2: { + StorageDead(_3); + goto -> bb3; + } + + bb3: { + StorageDead(_5); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir index cbfc58194cc1f..7595ad88d9df4 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir @@ -3,7 +3,7 @@ fn ezmap(_1: Option) -> Option { debug x => _1; let mut _0: std::option::Option; - scope 1 (inlined map::) { + scope 1 (inlined map::) { let mut _2: isize; let _3: i32; let mut _4: i32; diff --git a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir new file mode 100644 index 0000000000000..b921b96966b29 --- /dev/null +++ b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir @@ -0,0 +1,70 @@ +// MIR for `map_via_question_mark` after PreCodegen + +fn map_via_question_mark(_1: Option) -> Option { + debug x => _1; + let mut _0: std::option::Option; + let mut _4: std::ops::ControlFlow, i32>; + let _5: i32; + let mut _6: i32; + scope 1 { + debug residual => const Option::::None; + scope 2 { + scope 7 (inlined as FromResidual>>::from_residual) { + } + } + } + scope 3 { + debug val => _5; + scope 4 { + } + } + scope 5 (inlined as Try>::branch) { + let mut _2: isize; + let _3: i32; + scope 6 { + } + } + + bb0: { + StorageLive(_6); + StorageLive(_4); + StorageLive(_2); + StorageLive(_3); + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); + _0 = const Option::::None; + StorageDead(_6); + StorageDead(_4); + goto -> bb3; + } + + bb2: { + _3 = copy ((_1 as Some).0: i32); + _4 = ControlFlow::, i32>::Continue(copy _3); + StorageDead(_3); + StorageDead(_2); + _5 = copy ((_4 as Continue).0: i32); + _6 = Add(copy _5, const 1_i32); + _0 = Option::::Some(move _6); + StorageDead(_6); + StorageDead(_4); + goto -> bb3; + } + + bb3: { + return; + } + + bb4: { + unreachable; + } +} + +ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ +} diff --git a/tests/mir-opt/pre-codegen/simple_option_map.rs b/tests/mir-opt/pre-codegen/simple_option_map.rs index 0c432be0419bc..f0d7b51a64397 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.rs +++ b/tests/mir-opt/pre-codegen/simple_option_map.rs @@ -1,7 +1,6 @@ -// skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -#[inline(always)] +#[inline] fn map(slf: Option, f: F) -> Option where F: FnOnce(T) -> U, @@ -14,9 +13,30 @@ where // EMIT_MIR simple_option_map.ezmap.PreCodegen.after.mir pub fn ezmap(x: Option) -> Option { + // We expect this to all be inlined, as though it was written without the + // combinator and without the closure, using just a plain match. + + // CHECK-LABEL: fn ezmap + // CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32); + // CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[INNER]], const 1_i32); + // CHECK: _0 = Option::::Some({{copy|move}} [[SUCC]]); map(x, |n| n + 1) } +// EMIT_MIR simple_option_map.map_via_question_mark.PreCodegen.after.mir +pub fn map_via_question_mark(x: Option) -> Option { + // FIXME(#138544): Ideally this would optimize out the `ControlFlow` local. + + // CHECK-LABEL: fn map_via_question_mark + // CHECK: [[INNER:_.+]] = copy ((_1 as Some).0: i32); + // CHECK: [[TEMP1:_.+]] = ControlFlow::, i32>::Continue(copy [[INNER]]); + // CHECK: [[TEMP2:_.+]] = copy (([[TEMP1]] as Continue).0: i32); + // CHECK: [[SUCC:_.+]] = Add({{copy|move}} [[TEMP2]], const 1_i32); + // CHECK: _0 = Option::::Some({{copy|move}} [[SUCC]]); + Some(x? + 1) +} + fn main() { assert_eq!(None, ezmap(None)); + assert_eq!(None, map_via_question_mark(None)); }