mir-opt: Simplify trivial constants in SimplifyConstCondition

This commit is contained in:
dianqk 2025-10-11 22:02:40 +08:00
parent f5242367f4
commit a673575b24
No known key found for this signature in database
20 changed files with 687 additions and 319 deletions

View file

@ -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,

View file

@ -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);

View file

@ -3,23 +3,17 @@
fn hello() -> () {
let mut _0: ();
let mut _1: bool;
let mut _2: !;
let mut _1: !;
bb0: {
StorageLive(_1);
- _1 = const <bool as NeedsDrop>::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;
}
}

View file

@ -3,23 +3,17 @@
fn hello() -> () {
let mut _0: ();
let mut _1: bool;
let mut _2: !;
let mut _1: !;
bb0: {
StorageLive(_1);
- _1 = const <bool as NeedsDrop>::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;
}
}

View file

@ -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<This> NeedsDrop for This {}
// EMIT_MIR control_flow_simplification.hello.GVN.diff
// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
fn hello<T>() {
// CHECK-LABEL: fn hello(
// CHECK: bb0:
// CHECK-NEXT: return;
if <bool>::NEEDS {
panic!()
}

View file

@ -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>) -> 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
}

View file

@ -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>) -> i32 {
debug v => _1;
let mut _0: i32;
let _2: i32;
let mut _3: std::option::Option<i32>;
scope 1 {
debug v => _2;
}
scope 2 (inlined #[track_caller] Option::<i32>::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;
}
}

View file

@ -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);

View file

@ -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::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _15: isize;
let mut _17: !;
let _16: std::alloc::Layout;
let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, 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::<u8>) {
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);
StorageDead(_16);
StorageDead(_15);
StorageDead(_13);
_3 = ShallowInitBox(copy _12, ());
StorageDead(_12);
StorageDead(_11);
StorageDead(_10);
_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;
- StorageLive(_5);
+ 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);
_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(_6);
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);
StorageDead(_12);
StorageDead(_4);
_2 = &_3;
_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(_7);
StorageLive(_8);
_8 = copy _5;
- _7 = copy _8 as *mut () (PtrToPtr);
+ _7 = copy _23 as *mut () (Transmute);
StorageDead(_8);
_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);
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(_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];
}
+ }
+

View file

@ -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);
StorageLive(_8);
_8 = copy _5;
- _7 = copy _8 as *mut () (PtrToPtr);
+ _7 = copy _11 as *mut () (Transmute);
StorageDead(_8);
_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);
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(_6);
- StorageDead(_5);
+ nop;
StorageDead(_4);
+ nop;
drop(_3) -> [return: bb2, unwind: bb3];
}

View file

@ -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::ptr::NonNull<[u8]>, std::alloc::AllocError>;
let mut _15: isize;
let mut _17: !;
let _16: std::alloc::Layout;
let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, 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::<u8>) {
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);
StorageDead(_16);
StorageDead(_15);
StorageDead(_13);
_3 = ShallowInitBox(copy _12, ());
StorageDead(_12);
StorageDead(_11);
StorageDead(_10);
_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;
- StorageLive(_5);
+ 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);
_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(_6);
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);
StorageDead(_12);
StorageDead(_4);
_2 = &_3;
_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(_7);
StorageLive(_8);
_8 = copy _5;
- _7 = copy _8 as *mut () (PtrToPtr);
+ _7 = copy _23 as *mut () (Transmute);
StorageDead(_8);
_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);
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(_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];
}
+ }
+

View file

@ -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);
StorageLive(_8);
_8 = copy _5;
- _7 = copy _8 as *mut () (PtrToPtr);
+ _7 = copy _11 as *mut () (Transmute);
StorageDead(_8);
_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);
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(_6);
- StorageDead(_5);
+ nop;
StorageDead(_4);
+ nop;
drop(_3) -> [return: bb2, unwind: bb3];
}

View file

@ -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>) -> i32 {
let v1 = unsafe { v.unwrap_unchecked() };
let v2 = unsafe { v.unwrap_unchecked() };
v1 + v2
}

View file

@ -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>) -> i32 {
debug v => _1;
let mut _0: i32;
let _2: i32;
let mut _3: std::option::Option<i32>;
let mut _5: std::option::Option<i32>;
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::<i32>::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::<i32>::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;
}
}

View file

@ -0,0 +1,69 @@
// MIR for `two_unwrap_unchecked` after PreCodegen
fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
debug v => _1;
let mut _0: i32;
let mut _2: std::option::Option<i32>;
let _4: i32;
let mut _5: std::option::Option<i32>;
scope 1 {
debug v1 => _4;
let _7: i32;
scope 2 {
debug v2 => _7;
}
scope 8 (inlined #[track_caller] Option::<i32>::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::<i32>::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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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(