From 580624a43ca101099445f8614a2b0d239c8e277f Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 11 Oct 2025 22:02:40 +0800 Subject: [PATCH 1/3] mir-opt: Simplify trivial constants in SimplifyConstCondition --- compiler/rustc_mir_transform/src/lib.rs | 10 + .../src/simplify_branches.rs | 60 ++++-- ..._simplification.hello.GVN.panic-abort.diff | 12 +- ...simplification.hello.GVN.panic-unwind.diff | 12 +- .../const_prop/control_flow_simplification.rs | 4 +- tests/mir-opt/const_prop/trivial_const.rs | 15 ++ ...ifyConstCondition-after-inst-simplify.diff | 58 ++++++ ...eset_cast_kind_without_updating_operand.rs | 8 +- ...ng_operand.test.GVN.32bit.panic-abort.diff | 180 ++++++++++-------- ...g_operand.test.GVN.32bit.panic-unwind.diff | 82 ++++---- ...ng_operand.test.GVN.64bit.panic-abort.diff | 180 ++++++++++-------- ...g_operand.test.GVN.64bit.panic-unwind.diff | 82 ++++---- .../pre-codegen/two_unwrap_unchecked.rs | 12 ++ ...ap_unchecked.two_unwrap_unchecked.GVN.diff | 96 ++++++++++ ....two_unwrap_unchecked.PreCodegen.after.mir | 69 +++++++ ...ondition-after-const-prop.panic-abort.diff | 21 -- ...ndition-after-const-prop.panic-unwind.diff | 21 -- ...ition-after-inst-simplify.panic-abort.diff | 25 +++ ...tion-after-inst-simplify.panic-unwind.diff | 25 +++ tests/mir-opt/simplify_if.rs | 2 +- 20 files changed, 671 insertions(+), 303 deletions(-) create mode 100644 tests/mir-opt/const_prop/trivial_const.rs create mode 100644 tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff create mode 100644 tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs create mode 100644 tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff create mode 100644 tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir delete mode 100644 tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff delete mode 100644 tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff create mode 100644 tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff create mode 100644 tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 3ffd263fab027..4625b20fd8900 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -189,6 +189,7 @@ declare_passes! { Final }; mod simplify_branches : SimplifyConstCondition { + AfterInstSimplify, AfterConstProp, Final }; @@ -708,6 +709,15 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' // optimizations. This invalidates CFG caches, so avoid putting between // `ReferencePropagation` and `GVN` which both use the dominator tree. &instsimplify::InstSimplify::AfterSimplifyCfg, + // After `InstSimplify-after-simplifycfg` with `-Zub_checks=false`, simplify + // ``` + // _13 = const false; + // assume(copy _13); + // Call(precondition_check); + // ``` + // to unreachable to eliminate the call to help later passes. + // This invalidates CFG caches also. + &o1(simplify_branches::SimplifyConstCondition::AfterInstSimplify), &ref_prop::ReferencePropagation, &sroa::ScalarReplacementOfAggregates, &simplify::SimplifyLocals::BeforeConstProp, diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index ed94a058ec6d9..ba2286fd40a76 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -5,6 +5,7 @@ use tracing::trace; use crate::patch::MirPatch; pub(super) enum SimplifyConstCondition { + AfterInstSimplify, AfterConstProp, Final, } @@ -13,6 +14,9 @@ pub(super) enum SimplifyConstCondition { impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { fn name(&self) -> &'static str { match self { + SimplifyConstCondition::AfterInstSimplify => { + "SimplifyConstCondition-after-inst-simplify" + } SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop", SimplifyConstCondition::Final => "SimplifyConstCondition-final", } @@ -23,12 +27,33 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { let typing_env = body.typing_env(tcx); let mut patch = MirPatch::new(body); + fn try_get_const<'tcx, 'a>( + operand: &'a Operand<'tcx>, + has_place_const: Option<(Place<'tcx>, &'a ConstOperand<'tcx>)>, + ) -> Option<&'a ConstOperand<'tcx>> { + match operand { + Operand::Constant(const_operand) => Some(const_operand), + // `has_place_const` must be the LHS of the previous statement. + // Soundness: There is nothing can modify the place, as there are no statements between the two statements. + Operand::Copy(place) | Operand::Move(place) + if let Some((place_const, const_operand)) = has_place_const + && place_const == *place => + { + Some(const_operand) + } + Operand::Copy(_) | Operand::Move(_) => None, + } + } + 'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() { + let mut pre_place_const: Option<(Place<'tcx>, &ConstOperand<'tcx>)> = None; + for (statement_index, stmt) in block.statements.iter().enumerate() { + let has_place_const = pre_place_const.take(); // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic - && let Operand::Constant(c) = discr + && let Some(c) = try_get_const(discr, has_place_const) && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { @@ -37,28 +62,29 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { patch.patch_terminator(bb, TerminatorKind::Unreachable); continue 'blocks; } + } else if let StatementKind::Assign(box (lhs, ref rvalue)) = stmt.kind + && let Rvalue::Use(Operand::Constant(c)) = rvalue + { + pre_place_const = Some((lhs, c)); } } let terminator = block.terminator(); let terminator = match terminator.kind { - TerminatorKind::SwitchInt { - discr: Operand::Constant(ref c), ref targets, .. - } => { - let constant = c.const_.try_eval_bits(tcx, typing_env); - if let Some(constant) = constant { - let target = targets.target_for_value(constant); - TerminatorKind::Goto { target } - } else { - continue; - } + TerminatorKind::SwitchInt { ref discr, ref targets, .. } + if let Some(c) = try_get_const(discr, pre_place_const.take()) + && let Some(constant) = c.const_.try_eval_bits(tcx, typing_env) => + { + let target = targets.target_for_value(constant); + TerminatorKind::Goto { target } + } + TerminatorKind::Assert { target, ref cond, expected, .. } + if let Some(c) = try_get_const(&cond, pre_place_const.take()) + && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) + && constant == expected => + { + TerminatorKind::Goto { target } } - TerminatorKind::Assert { - target, cond: Operand::Constant(ref c), expected, .. - } => match c.const_.try_eval_bool(tcx, typing_env) { - Some(v) if v == expected => TerminatorKind::Goto { target }, - _ => continue, - }, _ => continue, }; patch.patch_terminator(bb, terminator); diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff index 24b10217865bb..5df2232053fef 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff @@ -3,23 +3,17 @@ fn hello() -> () { let mut _0: (); - let mut _1: bool; - let mut _2: !; + let mut _1: !; bb0: { - StorageLive(_1); -- _1 = const ::NEEDS; -- switchInt(move _1) -> [0: bb2, otherwise: bb1]; -+ _1 = const false; -+ switchInt(const false) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - _2 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; + _1 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; } bb2: { - StorageDead(_1); return; } } diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff index a73485e7944df..788a4424943e9 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff @@ -3,23 +3,17 @@ fn hello() -> () { let mut _0: (); - let mut _1: bool; - let mut _2: !; + let mut _1: !; bb0: { - StorageLive(_1); -- _1 = const ::NEEDS; -- switchInt(move _1) -> [0: bb2, otherwise: bb1]; -+ _1 = const false; -+ switchInt(const false) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - _2 = begin_panic::<&str>(const "explicit panic") -> unwind continue; + _1 = begin_panic::<&str>(const "explicit panic") -> unwind continue; } bb2: { - StorageDead(_1); return; } } diff --git a/tests/mir-opt/const_prop/control_flow_simplification.rs b/tests/mir-opt/const_prop/control_flow_simplification.rs index 64605ca11c2cc..8ec630d6f48d0 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.rs +++ b/tests/mir-opt/const_prop/control_flow_simplification.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: GVN //@ compile-flags: -Zmir-opt-level=1 @@ -12,6 +11,9 @@ impl NeedsDrop for This {} // EMIT_MIR control_flow_simplification.hello.GVN.diff // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir fn hello() { + // CHECK-LABEL: fn hello( + // CHECK: bb0: + // CHECK-NEXT: return; if ::NEEDS { panic!() } diff --git a/tests/mir-opt/const_prop/trivial_const.rs b/tests/mir-opt/const_prop/trivial_const.rs new file mode 100644 index 0000000000000..e9134c1ebdeff --- /dev/null +++ b/tests/mir-opt/const_prop/trivial_const.rs @@ -0,0 +1,15 @@ +//@ test-mir-pass: SimplifyConstCondition-after-inst-simplify +//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg -Zub_checks=false -Zinline-mir + +#![crate_type = "lib"] + +// EMIT_MIR trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff +pub fn unwrap_unchecked(v: &Option) -> i32 { + // CHECK-LABEL: fn unwrap_unchecked( + // CHECK: bb0: { + // CHECK: switchInt({{.*}}) -> [0: [[AssumeFalseBB:bb.*]], 1: + // CHECK: [[AssumeFalseBB]]: { + // CHECK-NEXT: unreachable; + let v = unsafe { v.unwrap_unchecked() }; + v +} diff --git a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff new file mode 100644 index 0000000000000..d14c42a330eb7 --- /dev/null +++ b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff @@ -0,0 +1,58 @@ +- // MIR for `unwrap_unchecked` before SimplifyConstCondition-after-inst-simplify ++ // MIR for `unwrap_unchecked` after SimplifyConstCondition-after-inst-simplify + + fn unwrap_unchecked(_1: &Option) -> i32 { + debug v => _1; + let mut _0: i32; + let _2: i32; + let mut _3: std::option::Option; + scope 1 { + debug v => _2; + } + scope 2 (inlined #[track_caller] Option::::unwrap_unchecked) { + let mut _4: isize; + scope 3 { + } + scope 4 (inlined #[track_caller] unreachable_unchecked) { + let _5: (); + scope 5 (inlined core::ub_checks::check_language_ub) { + let mut _6: bool; + scope 6 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = copy (*_1); + StorageLive(_4); + StorageLive(_5); + _4 = discriminant(_3); + switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { +- StorageLive(_6); +- _6 = const false; +- assume(copy _6); +- _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; ++ unreachable; + } + + bb3: { + _2 = move ((_3 as Some).0: i32); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + _0 = copy _2; + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs index 4368933dc627f..5534a45f19d64 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs @@ -1,10 +1,14 @@ -// skip-filecheck -//@ compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib +//@ test-mir-pass: GVN +//@ compile-flags: -Zinline-mir --crate-type lib // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR dont_reset_cast_kind_without_updating_operand.test.GVN.diff fn test() { + // CHECK-LABEL: fn test( + // CHECK: debug slf => [[SLF:_.*]]; + // CHECK: debug _x => [[X:_.*]]; + // CHECK: [[X]] = copy [[SLF]] as *mut () (PtrToPtr); let vp_ctx: &Box<()> = &Box::new(()); let slf: *const () = &raw const **vp_ctx; let bytes = std::ptr::slice_from_raw_parts(slf, 1); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index bb10fc8ac642d..5d7343a15bbea 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -6,24 +6,26 @@ let _1: &std::boxed::Box<()>; let _2: &std::boxed::Box<()>; let _3: std::boxed::Box<()>; - let mut _6: *const (); - let mut _8: *const [()]; - let mut _9: *const (); - let mut _22: usize; - let mut _23: std::ptr::NonNull<()>; + let mut _4: (); + let mut _7: *const (); + let mut _9: *const [()]; + let mut _10: std::boxed::Box<()>; + let mut _11: *const (); + let mut _25: usize; scope 1 { debug vp_ctx => _1; - let _4: *const (); + let _5: *const (); scope 2 { - debug slf => _9; - let _5: *const [()]; + debug slf => _5; + let _6: *const [()]; scope 3 { - debug bytes => _5; - let _7: *mut (); + debug bytes => _6; + let _8: *mut (); scope 4 { - debug _x => _7; + debug _x => _8; } scope 18 (inlined foo) { + let mut _26: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -33,21 +35,22 @@ } } scope 5 (inlined Box::<()>::new) { - let mut _10: usize; - let mut _11: usize; - let mut _12: *mut u8; + let mut _12: usize; + let mut _13: usize; + let mut _14: *mut u8; + let mut _15: *const (); scope 6 (inlined alloc::alloc::exchange_malloc) { - let _13: std::alloc::Layout; - let mut _14: std::result::Result, std::alloc::AllocError>; - let mut _15: isize; - let mut _17: !; + let _16: std::alloc::Layout; + let mut _17: std::result::Result, std::alloc::AllocError>; + let mut _18: isize; + let mut _20: !; scope 7 { - let _16: std::ptr::NonNull<[u8]>; + let _19: std::ptr::NonNull<[u8]>; scope 8 { scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _21: *mut [u8]; + let mut _24: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -60,31 +63,37 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _18: bool; - let _19: (); - let mut _20: std::ptr::Alignment; + let mut _21: bool; + let _22: (); + let mut _23: std::ptr::Alignment; } } } bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - StorageLive(_10); - StorageLive(_11); + StorageLive(_4); +- _4 = (); ++ _4 = const (); StorageLive(_12); -- _10 = SizeOf(()); -- _11 = AlignOf(()); -+ _10 = const 0_usize; -+ _11 = const 1_usize; StorageLive(_13); + StorageLive(_14); StorageLive(_15); +- _12 = SizeOf(()); +- _13 = AlignOf(()); ++ _12 = const 0_usize; ++ _13 = const 1_usize; StorageLive(_16); StorageLive(_18); - _18 = const false; -- switchInt(move _18) -> [0: bb6, otherwise: bb5]; -+ switchInt(const false) -> [0: bb6, otherwise: bb5]; + StorageLive(_19); + StorageLive(_20); + StorageLive(_22); + StorageLive(_21); + _21 = UbChecks(); + switchInt(move _21) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -98,76 +107,91 @@ } bb3: { -- _17 = handle_alloc_error(move _13) -> unwind unreachable; -+ _17 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable; +- _20 = handle_alloc_error(move _16) -> unwind unreachable; ++ _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable; } bb4: { - _16 = copy ((_14 as Ok).0: std::ptr::NonNull<[u8]>); - StorageLive(_21); - _21 = copy _16 as *mut [u8] (Transmute); - _12 = copy _21 as *mut u8 (PtrToPtr); - StorageDead(_21); - StorageDead(_14); + _19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>); + StorageLive(_24); + _24 = copy _19 as *mut [u8] (Transmute); + _14 = copy _24 as *mut u8 (PtrToPtr); + StorageDead(_24); + StorageDead(_17); + StorageDead(_22); + StorageDead(_20); + StorageDead(_19); + StorageDead(_18); StorageDead(_16); + _3 = ShallowInitBox(copy _14, ()); + _15 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); +- (*_15) = move _4; ++ (*_15) = const (); StorageDead(_15); + StorageDead(_14); StorageDead(_13); - _3 = ShallowInitBox(copy _12, ()); StorageDead(_12); - StorageDead(_11); - StorageDead(_10); + StorageDead(_4); _2 = &_3; - _1 = copy _2; - StorageDead(_2); - StorageLive(_4); - _23 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>); - _9 = copy _23 as *const () (Transmute); - _4 = copy _9; + _1 = &(*_2); +- StorageDead(_2); - StorageLive(_5); +- _10 = copy (*_1); ++ nop; ++ nop; ++ _10 = copy (*_2); + _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); + _5 = &raw const (*_11); +- StorageLive(_6); + nop; - StorageLive(_6); -- _6 = copy _4; -+ _6 = copy _9; - StorageLive(_22); - _22 = const 1_usize; -- _5 = *const [()] from (copy _6, copy _22); -+ _5 = *const [()] from (copy _9, const 1_usize); - StorageDead(_22); - StorageDead(_6); StorageLive(_7); + _7 = copy _5; + StorageLive(_25); + _25 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _25); ++ _6 = *const [()] from (copy _5, const 1_usize); + StorageDead(_25); + StorageDead(_7); StorageLive(_8); - _8 = copy _5; -- _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _23 as *mut () (Transmute); + StorageLive(_9); + _9 = copy _6; + StorageLive(_26); +- _26 = copy _9; +- _8 = copy _9 as *mut () (PtrToPtr); ++ _26 = copy _6; ++ _8 = copy _5 as *mut () (PtrToPtr); + StorageDead(_26); + StorageDead(_9); + _0 = const (); StorageDead(_8); - StorageDead(_7); +- StorageDead(_6); - StorageDead(_5); + nop; - StorageDead(_4); ++ nop; drop(_3) -> [return: bb1, unwind unreachable]; } bb5: { -- _19 = Layout::from_size_align_unchecked::precondition_check(copy _10, copy _11) -> [return: bb6, unwind unreachable]; -+ _19 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _22 = Layout::from_size_align_unchecked::precondition_check(copy _12, copy _13) -> [return: bb6, unwind unreachable]; ++ _22 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_18); - StorageLive(_20); -- _20 = copy _11 as std::ptr::Alignment (Transmute); -- _13 = Layout { size: copy _10, align: move _20 }; -+ _20 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); -+ _13 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_20); - StorageLive(_14); -- _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _13, const false) -> [return: bb7, unwind unreachable]; -+ _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; + StorageDead(_21); + StorageLive(_23); +- _23 = copy _13 as std::ptr::Alignment (Transmute); +- _16 = Layout { size: copy _12, align: move _23 }; ++ _23 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); ++ _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; + StorageDead(_23); + StorageLive(_17); +- _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _16, const false) -> [return: bb7, unwind unreachable]; ++ _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb4, 1: bb3, otherwise: bb2]; + _18 = discriminant(_17); + switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2]; } + } + diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff index 88754cb02776c..82a14a8b6ec99 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff @@ -6,24 +6,26 @@ let _1: &std::boxed::Box<()>; let _2: &std::boxed::Box<()>; let _3: std::boxed::Box<()>; - let mut _6: *const (); - let mut _8: *const [()]; - let mut _9: *const (); - let mut _10: usize; - let mut _11: std::ptr::NonNull<()>; + let mut _4: (); + let mut _7: *const (); + let mut _9: *const [()]; + let mut _10: std::boxed::Box<()>; + let mut _11: *const (); + let mut _12: usize; scope 1 { debug vp_ctx => _1; - let _4: *const (); + let _5: *const (); scope 2 { - debug slf => _9; - let _5: *const [()]; + debug slf => _5; + let _6: *const [()]; scope 3 { - debug bytes => _5; - let _7: *mut (); + debug bytes => _6; + let _8: *mut (); scope 4 { - debug _x => _7; + debug _x => _8; } scope 7 (inlined foo) { + let mut _13: *const [()]; } } scope 5 (inlined slice_from_raw_parts::<()>) { @@ -35,40 +37,54 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; + StorageLive(_4); +- _4 = (); +- _3 = Box::<()>::new(move _4) -> [return: bb1, unwind continue]; ++ _4 = const (); ++ _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; } bb1: { + StorageDead(_4); _2 = &_3; - _1 = copy _2; - StorageDead(_2); - StorageLive(_4); - _11 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>); - _9 = copy _11 as *const () (Transmute); - _4 = copy _9; + _1 = &(*_2); +- StorageDead(_2); - StorageLive(_5); +- _10 = copy (*_1); ++ nop; ++ nop; ++ _10 = copy (*_2); + _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); + _5 = &raw const (*_11); +- StorageLive(_6); + nop; - StorageLive(_6); -- _6 = copy _4; -+ _6 = copy _9; - StorageLive(_10); - _10 = const 1_usize; -- _5 = *const [()] from (copy _6, copy _10); -+ _5 = *const [()] from (copy _9, const 1_usize); - StorageDead(_10); - StorageDead(_6); StorageLive(_7); + _7 = copy _5; + StorageLive(_12); + _12 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _12); ++ _6 = *const [()] from (copy _5, const 1_usize); + StorageDead(_12); + StorageDead(_7); StorageLive(_8); - _8 = copy _5; -- _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _11 as *mut () (Transmute); + StorageLive(_9); + _9 = copy _6; + StorageLive(_13); +- _13 = copy _9; +- _8 = copy _9 as *mut () (PtrToPtr); ++ _13 = copy _6; ++ _8 = copy _5 as *mut () (PtrToPtr); + StorageDead(_13); + StorageDead(_9); + _0 = const (); StorageDead(_8); - StorageDead(_7); +- StorageDead(_6); - StorageDead(_5); + nop; - StorageDead(_4); ++ nop; drop(_3) -> [return: bb2, unwind: bb3]; } diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 97b7c9a1d5584..ba5fe287b8e1c 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -6,24 +6,26 @@ let _1: &std::boxed::Box<()>; let _2: &std::boxed::Box<()>; let _3: std::boxed::Box<()>; - let mut _6: *const (); - let mut _8: *const [()]; - let mut _9: *const (); - let mut _22: usize; - let mut _23: std::ptr::NonNull<()>; + let mut _4: (); + let mut _7: *const (); + let mut _9: *const [()]; + let mut _10: std::boxed::Box<()>; + let mut _11: *const (); + let mut _25: usize; scope 1 { debug vp_ctx => _1; - let _4: *const (); + let _5: *const (); scope 2 { - debug slf => _9; - let _5: *const [()]; + debug slf => _5; + let _6: *const [()]; scope 3 { - debug bytes => _5; - let _7: *mut (); + debug bytes => _6; + let _8: *mut (); scope 4 { - debug _x => _7; + debug _x => _8; } scope 18 (inlined foo) { + let mut _26: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -33,21 +35,22 @@ } } scope 5 (inlined Box::<()>::new) { - let mut _10: usize; - let mut _11: usize; - let mut _12: *mut u8; + let mut _12: usize; + let mut _13: usize; + let mut _14: *mut u8; + let mut _15: *const (); scope 6 (inlined alloc::alloc::exchange_malloc) { - let _13: std::alloc::Layout; - let mut _14: std::result::Result, std::alloc::AllocError>; - let mut _15: isize; - let mut _17: !; + let _16: std::alloc::Layout; + let mut _17: std::result::Result, std::alloc::AllocError>; + let mut _18: isize; + let mut _20: !; scope 7 { - let _16: std::ptr::NonNull<[u8]>; + let _19: std::ptr::NonNull<[u8]>; scope 8 { scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _21: *mut [u8]; + let mut _24: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -60,31 +63,37 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _18: bool; - let _19: (); - let mut _20: std::ptr::Alignment; + let mut _21: bool; + let _22: (); + let mut _23: std::ptr::Alignment; } } } bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - StorageLive(_10); - StorageLive(_11); + StorageLive(_4); +- _4 = (); ++ _4 = const (); StorageLive(_12); -- _10 = SizeOf(()); -- _11 = AlignOf(()); -+ _10 = const 0_usize; -+ _11 = const 1_usize; StorageLive(_13); + StorageLive(_14); StorageLive(_15); +- _12 = SizeOf(()); +- _13 = AlignOf(()); ++ _12 = const 0_usize; ++ _13 = const 1_usize; StorageLive(_16); StorageLive(_18); - _18 = const false; -- switchInt(move _18) -> [0: bb6, otherwise: bb5]; -+ switchInt(const false) -> [0: bb6, otherwise: bb5]; + StorageLive(_19); + StorageLive(_20); + StorageLive(_22); + StorageLive(_21); + _21 = UbChecks(); + switchInt(move _21) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -98,76 +107,91 @@ } bb3: { -- _17 = handle_alloc_error(move _13) -> unwind unreachable; -+ _17 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable; +- _20 = handle_alloc_error(move _16) -> unwind unreachable; ++ _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable; } bb4: { - _16 = copy ((_14 as Ok).0: std::ptr::NonNull<[u8]>); - StorageLive(_21); - _21 = copy _16 as *mut [u8] (Transmute); - _12 = copy _21 as *mut u8 (PtrToPtr); - StorageDead(_21); - StorageDead(_14); + _19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>); + StorageLive(_24); + _24 = copy _19 as *mut [u8] (Transmute); + _14 = copy _24 as *mut u8 (PtrToPtr); + StorageDead(_24); + StorageDead(_17); + StorageDead(_22); + StorageDead(_20); + StorageDead(_19); + StorageDead(_18); StorageDead(_16); + _3 = ShallowInitBox(copy _14, ()); + _15 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); +- (*_15) = move _4; ++ (*_15) = const (); StorageDead(_15); + StorageDead(_14); StorageDead(_13); - _3 = ShallowInitBox(copy _12, ()); StorageDead(_12); - StorageDead(_11); - StorageDead(_10); + StorageDead(_4); _2 = &_3; - _1 = copy _2; - StorageDead(_2); - StorageLive(_4); - _23 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>); - _9 = copy _23 as *const () (Transmute); - _4 = copy _9; + _1 = &(*_2); +- StorageDead(_2); - StorageLive(_5); +- _10 = copy (*_1); ++ nop; ++ nop; ++ _10 = copy (*_2); + _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); + _5 = &raw const (*_11); +- StorageLive(_6); + nop; - StorageLive(_6); -- _6 = copy _4; -+ _6 = copy _9; - StorageLive(_22); - _22 = const 1_usize; -- _5 = *const [()] from (copy _6, copy _22); -+ _5 = *const [()] from (copy _9, const 1_usize); - StorageDead(_22); - StorageDead(_6); StorageLive(_7); + _7 = copy _5; + StorageLive(_25); + _25 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _25); ++ _6 = *const [()] from (copy _5, const 1_usize); + StorageDead(_25); + StorageDead(_7); StorageLive(_8); - _8 = copy _5; -- _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _23 as *mut () (Transmute); + StorageLive(_9); + _9 = copy _6; + StorageLive(_26); +- _26 = copy _9; +- _8 = copy _9 as *mut () (PtrToPtr); ++ _26 = copy _6; ++ _8 = copy _5 as *mut () (PtrToPtr); + StorageDead(_26); + StorageDead(_9); + _0 = const (); StorageDead(_8); - StorageDead(_7); +- StorageDead(_6); - StorageDead(_5); + nop; - StorageDead(_4); ++ nop; drop(_3) -> [return: bb1, unwind unreachable]; } bb5: { -- _19 = Layout::from_size_align_unchecked::precondition_check(copy _10, copy _11) -> [return: bb6, unwind unreachable]; -+ _19 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _22 = Layout::from_size_align_unchecked::precondition_check(copy _12, copy _13) -> [return: bb6, unwind unreachable]; ++ _22 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_18); - StorageLive(_20); -- _20 = copy _11 as std::ptr::Alignment (Transmute); -- _13 = Layout { size: copy _10, align: move _20 }; -+ _20 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); -+ _13 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_20); - StorageLive(_14); -- _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _13, const false) -> [return: bb7, unwind unreachable]; -+ _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; + StorageDead(_21); + StorageLive(_23); +- _23 = copy _13 as std::ptr::Alignment (Transmute); +- _16 = Layout { size: copy _12, align: move _23 }; ++ _23 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); ++ _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; + StorageDead(_23); + StorageLive(_17); +- _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _16, const false) -> [return: bb7, unwind unreachable]; ++ _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb4, 1: bb3, otherwise: bb2]; + _18 = discriminant(_17); + switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2]; } + } + diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff index 88754cb02776c..82a14a8b6ec99 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff @@ -6,24 +6,26 @@ let _1: &std::boxed::Box<()>; let _2: &std::boxed::Box<()>; let _3: std::boxed::Box<()>; - let mut _6: *const (); - let mut _8: *const [()]; - let mut _9: *const (); - let mut _10: usize; - let mut _11: std::ptr::NonNull<()>; + let mut _4: (); + let mut _7: *const (); + let mut _9: *const [()]; + let mut _10: std::boxed::Box<()>; + let mut _11: *const (); + let mut _12: usize; scope 1 { debug vp_ctx => _1; - let _4: *const (); + let _5: *const (); scope 2 { - debug slf => _9; - let _5: *const [()]; + debug slf => _5; + let _6: *const [()]; scope 3 { - debug bytes => _5; - let _7: *mut (); + debug bytes => _6; + let _8: *mut (); scope 4 { - debug _x => _7; + debug _x => _8; } scope 7 (inlined foo) { + let mut _13: *const [()]; } } scope 5 (inlined slice_from_raw_parts::<()>) { @@ -35,40 +37,54 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; + StorageLive(_4); +- _4 = (); +- _3 = Box::<()>::new(move _4) -> [return: bb1, unwind continue]; ++ _4 = const (); ++ _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue]; } bb1: { + StorageDead(_4); _2 = &_3; - _1 = copy _2; - StorageDead(_2); - StorageLive(_4); - _11 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>); - _9 = copy _11 as *const () (Transmute); - _4 = copy _9; + _1 = &(*_2); +- StorageDead(_2); - StorageLive(_5); +- _10 = copy (*_1); ++ nop; ++ nop; ++ _10 = copy (*_2); + _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute); + _5 = &raw const (*_11); +- StorageLive(_6); + nop; - StorageLive(_6); -- _6 = copy _4; -+ _6 = copy _9; - StorageLive(_10); - _10 = const 1_usize; -- _5 = *const [()] from (copy _6, copy _10); -+ _5 = *const [()] from (copy _9, const 1_usize); - StorageDead(_10); - StorageDead(_6); StorageLive(_7); + _7 = copy _5; + StorageLive(_12); + _12 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _12); ++ _6 = *const [()] from (copy _5, const 1_usize); + StorageDead(_12); + StorageDead(_7); StorageLive(_8); - _8 = copy _5; -- _7 = copy _8 as *mut () (PtrToPtr); -+ _7 = copy _11 as *mut () (Transmute); + StorageLive(_9); + _9 = copy _6; + StorageLive(_13); +- _13 = copy _9; +- _8 = copy _9 as *mut () (PtrToPtr); ++ _13 = copy _6; ++ _8 = copy _5 as *mut () (PtrToPtr); + StorageDead(_13); + StorageDead(_9); + _0 = const (); StorageDead(_8); - StorageDead(_7); +- StorageDead(_6); - StorageDead(_5); + nop; - StorageDead(_4); ++ nop; drop(_3) -> [return: bb2, unwind: bb3]; } diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs new file mode 100644 index 0000000000000..e82e7f2236f18 --- /dev/null +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs @@ -0,0 +1,12 @@ +// skip-filecheck +//@ compile-flags: -O + +#![crate_type = "lib"] + +// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff +// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir +pub fn two_unwrap_unchecked(v: &Option) -> i32 { + let v1 = unsafe { v.unwrap_unchecked() }; + let v2 = unsafe { v.unwrap_unchecked() }; + v1 + v2 +} diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff new file mode 100644 index 0000000000000..3b96b4ebc7913 --- /dev/null +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff @@ -0,0 +1,96 @@ +- // MIR for `two_unwrap_unchecked` before GVN ++ // MIR for `two_unwrap_unchecked` after GVN + + fn two_unwrap_unchecked(_1: &Option) -> i32 { + debug v => _1; + let mut _0: i32; + let _2: i32; + let mut _3: std::option::Option; + let mut _5: std::option::Option; + let mut _6: i32; + let mut _7: i32; + scope 1 { + debug v1 => _2; + let _4: i32; + scope 2 { + debug v2 => _4; + } + scope 8 (inlined #[track_caller] Option::::unwrap_unchecked) { + let mut _9: isize; + scope 9 { + } + scope 10 (inlined #[track_caller] unreachable_unchecked) { + scope 11 (inlined core::ub_checks::check_language_ub) { + scope 12 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + } + scope 3 (inlined #[track_caller] Option::::unwrap_unchecked) { + let mut _8: isize; + scope 4 { + } + scope 5 (inlined #[track_caller] unreachable_unchecked) { + scope 6 (inlined core::ub_checks::check_language_ub) { + scope 7 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = copy (*_1); + StorageLive(_8); + _8 = discriminant(_3); + switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + unreachable; + } + + bb3: { + _2 = move ((_3 as Some).0: i32); + StorageDead(_8); + StorageDead(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = copy (*_1); + StorageLive(_9); + _9 = discriminant(_5); + switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb1]; + } + + bb4: { + unreachable; + } + + bb5: { + _4 = move ((_5 as Some).0: i32); + StorageDead(_9); + StorageDead(_5); + StorageLive(_6); + _6 = copy _2; + StorageLive(_7); + _7 = copy _4; +- _0 = Add(move _6, move _7); ++ _0 = Add(copy _2, copy _4); + StorageDead(_7); + StorageDead(_6); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir new file mode 100644 index 0000000000000..67910b4f17841 --- /dev/null +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir @@ -0,0 +1,69 @@ +// MIR for `two_unwrap_unchecked` after PreCodegen + +fn two_unwrap_unchecked(_1: &Option) -> i32 { + debug v => _1; + let mut _0: i32; + let mut _2: std::option::Option; + let _4: i32; + let mut _5: std::option::Option; + scope 1 { + debug v1 => _4; + let _7: i32; + scope 2 { + debug v2 => _7; + } + scope 8 (inlined #[track_caller] Option::::unwrap_unchecked) { + let mut _6: isize; + scope 9 { + } + scope 10 (inlined #[track_caller] unreachable_unchecked) { + scope 11 (inlined core::ub_checks::check_language_ub) { + scope 12 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + } + scope 3 (inlined #[track_caller] Option::::unwrap_unchecked) { + let mut _3: isize; + scope 4 { + } + scope 5 (inlined #[track_caller] unreachable_unchecked) { + scope 6 (inlined core::ub_checks::check_language_ub) { + scope 7 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + + bb0: { + StorageLive(_2); + _2 = copy (*_1); + StorageLive(_3); + _3 = discriminant(_2); + switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb3]; + } + + bb1: { + _4 = move ((_2 as Some).0: i32); + StorageDead(_3); + StorageDead(_2); + StorageLive(_5); + _5 = copy (*_1); + StorageLive(_6); + _6 = discriminant(_5); + switchInt(move _6) -> [0: bb3, 1: bb2, otherwise: bb3]; + } + + bb2: { + _7 = move ((_5 as Some).0: i32); + StorageDead(_6); + StorageDead(_5); + _0 = Add(copy _4, copy _7); + return; + } + + bb3: { + unreachable; + } +} diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff deleted file mode 100644 index c3076fb67c231..0000000000000 --- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `main` before SimplifyConstCondition-after-const-prop -+ // MIR for `main` after SimplifyConstCondition-after-const-prop - - fn main() -> () { - let mut _0: (); - let _1: (); - - bb0: { -- switchInt(const false) -> [0: bb2, otherwise: bb1]; -+ goto -> bb2; - } - - bb1: { - _1 = noop() -> [return: bb2, unwind unreachable]; - } - - bb2: { - return; - } - } - diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff deleted file mode 100644 index 6c346e20e5893..0000000000000 --- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `main` before SimplifyConstCondition-after-const-prop -+ // MIR for `main` after SimplifyConstCondition-after-const-prop - - fn main() -> () { - let mut _0: (); - let _1: (); - - bb0: { -- switchInt(const false) -> [0: bb2, otherwise: bb1]; -+ goto -> bb2; - } - - bb1: { - _1 = noop() -> [return: bb2, unwind continue]; - } - - bb2: { - return; - } - } - diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff new file mode 100644 index 0000000000000..c67fd69235b47 --- /dev/null +++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff @@ -0,0 +1,25 @@ +- // MIR for `main` before SimplifyConstCondition-after-inst-simplify ++ // MIR for `main` after SimplifyConstCondition-after-inst-simplify + + fn main() -> () { + let mut _0: (); + let mut _1: bool; + let _2: (); + + bb0: { + StorageLive(_1); + _1 = const false; +- switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + _2 = noop() -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff new file mode 100644 index 0000000000000..07f179dfdd454 --- /dev/null +++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff @@ -0,0 +1,25 @@ +- // MIR for `main` before SimplifyConstCondition-after-inst-simplify ++ // MIR for `main` after SimplifyConstCondition-after-inst-simplify + + fn main() -> () { + let mut _0: (); + let mut _1: bool; + let _2: (); + + bb0: { + StorageLive(_1); + _1 = const false; +- switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + _2 = noop() -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/simplify_if.rs b/tests/mir-opt/simplify_if.rs index f600c05958198..6aca233655544 100644 --- a/tests/mir-opt/simplify_if.rs +++ b/tests/mir-opt/simplify_if.rs @@ -2,7 +2,7 @@ #[inline(never)] fn noop() {} -// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff +// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-inst-simplify.diff fn main() { // CHECK-LABEL: fn main( From 7eb1cf4137b70ec51452ce699e20fe029a385850 Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 14 Oct 2025 21:30:53 +0800 Subject: [PATCH 2/3] GVN: Preserve derefs at unreachable and return --- compiler/rustc_mir_transform/src/gvn.rs | 21 ++++++++-- .../pre-codegen/two_unwrap_unchecked.rs | 5 ++- ...ap_unchecked.two_unwrap_unchecked.GVN.diff | 39 ++++++++++++------- ....two_unwrap_unchecked.PreCodegen.after.mir | 28 +++---------- 4 files changed, 50 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2f857ea45ac72..e3db8096ce328 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1922,10 +1922,23 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> { } // Function calls and ASM may invalidate (nested) derefs. We must handle them carefully. // Currently, only preserving derefs for trivial terminators like SwitchInt and Goto. - let safe_to_preserve_derefs = matches!( - terminator.kind, - TerminatorKind::SwitchInt { .. } | TerminatorKind::Goto { .. } - ); + let safe_to_preserve_derefs = match terminator.kind { + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Return + | TerminatorKind::Unreachable => true, + TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Drop { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::TailCall { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::CoroutineDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => false, + }; if !safe_to_preserve_derefs { self.invalidate_derefs(); } diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs index e82e7f2236f18..7b742b956ae5c 100644 --- a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs @@ -1,4 +1,3 @@ -// skip-filecheck //@ compile-flags: -O #![crate_type = "lib"] @@ -6,6 +5,10 @@ // EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff // EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir pub fn two_unwrap_unchecked(v: &Option) -> i32 { + // CHECK-LABEL: fn two_unwrap_unchecked( + // CHECK: [[DEREF_V:_.*]] = copy (*_1); + // CHECK: [[V1V2:_.*]] = copy (([[DEREF_V]] as Some).0: i32); + // CHECK: _0 = Add(copy [[V1V2]], copy [[V1V2]]); let v1 = unsafe { v.unwrap_unchecked() }; let v2 = unsafe { v.unwrap_unchecked() }; v1 + v2 diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff index 3b96b4ebc7913..5b063e6762e07 100644 --- a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff @@ -41,12 +41,15 @@ bb0: { - StorageLive(_2); +- StorageLive(_3); ++ nop; + nop; - StorageLive(_3); _3 = copy (*_1); - StorageLive(_8); +- StorageLive(_8); ++ nop; _8 = discriminant(_3); - switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ switchInt(copy _8) -> [0: bb2, 1: bb3, otherwise: bb1]; } bb1: { @@ -58,16 +61,21 @@ } bb3: { - _2 = move ((_3 as Some).0: i32); - StorageDead(_8); - StorageDead(_3); -- StorageLive(_4); +- _2 = move ((_3 as Some).0: i32); +- StorageDead(_8); +- StorageDead(_3); ++ _2 = copy ((_3 as Some).0: i32); + nop; ++ nop; + StorageLive(_4); StorageLive(_5); - _5 = copy (*_1); +- _5 = copy (*_1); ++ _5 = copy _3; StorageLive(_9); - _9 = discriminant(_5); - switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb1]; +- _9 = discriminant(_5); +- switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb1]; ++ _9 = copy _8; ++ switchInt(copy _8) -> [0: bb4, 1: bb5, otherwise: bb1]; } bb4: { @@ -75,20 +83,21 @@ } bb5: { - _4 = move ((_5 as Some).0: i32); +- _4 = move ((_5 as Some).0: i32); ++ _4 = copy _2; StorageDead(_9); StorageDead(_5); StorageLive(_6); _6 = copy _2; StorageLive(_7); - _7 = copy _4; +- _7 = copy _4; - _0 = Add(move _6, move _7); -+ _0 = Add(copy _2, copy _4); ++ _7 = copy _2; ++ _0 = Add(copy _2, copy _2); StorageDead(_7); StorageDead(_6); -- StorageDead(_4); + StorageDead(_4); - StorageDead(_2); -+ nop; + nop; return; } diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir index 67910b4f17841..b2b7f88d8534b 100644 --- a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir @@ -5,15 +5,12 @@ fn two_unwrap_unchecked(_1: &Option) -> i32 { let mut _0: i32; let mut _2: std::option::Option; let _4: i32; - let mut _5: std::option::Option; scope 1 { debug v1 => _4; - let _7: i32; scope 2 { - debug v2 => _7; + debug v2 => _4; } scope 8 (inlined #[track_caller] Option::::unwrap_unchecked) { - let mut _6: isize; scope 9 { } scope 10 (inlined #[track_caller] unreachable_unchecked) { @@ -37,33 +34,18 @@ fn two_unwrap_unchecked(_1: &Option) -> i32 { } bb0: { - StorageLive(_2); _2 = copy (*_1); - StorageLive(_3); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb3]; + switchInt(copy _3) -> [0: bb2, 1: bb1, otherwise: bb2]; } bb1: { - _4 = move ((_2 as Some).0: i32); - StorageDead(_3); - StorageDead(_2); - StorageLive(_5); - _5 = copy (*_1); - StorageLive(_6); - _6 = discriminant(_5); - switchInt(move _6) -> [0: bb3, 1: bb2, otherwise: bb3]; - } - - bb2: { - _7 = move ((_5 as Some).0: i32); - StorageDead(_6); - StorageDead(_5); - _0 = Add(copy _4, copy _7); + _4 = copy ((_2 as Some).0: i32); + _0 = Add(copy _4, copy _4); return; } - bb3: { + bb2: { unreachable; } } From bdc9444df94af733018eb563f5ce96e2f311dae9 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 16 Oct 2025 08:10:05 +0800 Subject: [PATCH 3/3] Bless collect-in-promoted-const.rs --- .../collect-in-promoted-const.noopt.stderr | 6 ++--- .../collect-in-promoted-const.opt.stderr | 22 ++++--------------- .../collect-in-promoted-const.rs | 5 ----- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr index c1ae42b3939dc..9f65e4f91be95 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr @@ -1,17 +1,17 @@ error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:11:19 + --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:22:21 + --> $DIR/collect-in-promoted-const.rs:17:21 | LL | let _val = &Fail::::C; | ^^^^^^^^^^^^ note: the above error was encountered while instantiating `fn f::` - --> $DIR/collect-in-promoted-const.rs:27:5 + --> $DIR/collect-in-promoted-const.rs:22:5 | LL | f::(); | ^^^^^^^^^^ diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr index 0d7ac48172c8c..9f65e4f91be95 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr @@ -1,35 +1,21 @@ error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:11:19 - | -LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed here - -note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:22:21 - | -LL | let _val = &Fail::::C; - | ^^^^^^^^^^^^ - -error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:11:19 + --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:22:21 + --> $DIR/collect-in-promoted-const.rs:17:21 | LL | let _val = &Fail::::C; | ^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn f::` - --> $DIR/collect-in-promoted-const.rs:27:5 + --> $DIR/collect-in-promoted-const.rs:22:5 | LL | f::(); | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs index 498328abe2160..c475720938697 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.rs +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs @@ -1,17 +1,12 @@ //@revisions: noopt opt //@ build-fail //@[noopt] compile-flags: -Copt-level=0 -// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0 -//@[opt] compile-flags: -C debuginfo=0 //@[opt] compile-flags: -O //! Make sure we error on erroneous consts even if they get promoted. struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic - //[opt]~^ ERROR evaluation panicked: explicit panic - // (Not sure why optimizations lead to this being emitted twice, but as long as compilation - // fails either way it's fine.) } #[inline(never)]