From 666030c51b87509a065867f99bf7317a5486470a Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Mon, 20 Mar 2023 21:37:36 +0000
Subject: [PATCH 1/6] Simplify binary ops.

---
 compiler/rustc_mir_transform/src/gvn.rs       | 111 ++++-
 .../mir-opt/const_prop/boolean_identities.rs  |   7 +-
 .../boolean_identities.test.GVN.diff          |  12 +-
 .../boxes.main.GVN.panic-abort.diff           |   9 +-
 .../boxes.main.GVN.panic-unwind.diff          |   9 +-
 tests/mir-opt/const_prop/boxes.rs             |   2 +-
 tests/mir-opt/const_prop/mult_by_zero.rs      |   3 +-
 .../const_prop/mult_by_zero.test.GVN.diff     |   2 +-
 .../gvn.arithmetic.GVN.panic-abort.diff       | 385 +++++++++++-------
 .../gvn.arithmetic.GVN.panic-unwind.diff      | 385 +++++++++++-------
 ...vn.arithmetic_checked.GVN.panic-abort.diff | 101 +++--
 ...n.arithmetic_checked.GVN.panic-unwind.diff | 101 +++--
 .../gvn.comparison.GVN.panic-abort.diff       |  10 +-
 .../gvn.comparison.GVN.panic-unwind.diff      |  10 +-
 .../gvn.fn_pointers.GVN.panic-abort.diff      |  18 +-
 .../gvn.fn_pointers.GVN.panic-unwind.diff     |  18 +-
 tests/mir-opt/gvn.rs                          |  78 ++--
 .../issue_101973.inner.GVN.panic-abort.diff   |  17 +-
 .../issue_101973.inner.GVN.panic-unwind.diff  |  17 +-
 19 files changed, 836 insertions(+), 459 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index dc3af038d80..3052369c3ca 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         Some(self.insert(Value::Constant { value, disambiguator }))
     }
 
+    fn insert_bool(&mut self, flag: bool) -> VnIndex {
+        // Booleans are deterministic.
+        self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 })
+    }
+
     fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
         self.insert_constant(Const::from_scalar(self.tcx, scalar, ty))
             .expect("scalars are deterministic")
     }
 
+    fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
+        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values))
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
@@ -785,14 +794,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 Value::Cast { kind, value, from, to }
             }
             Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::BinaryOp(op, lhs?, rhs?)
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::BinaryOp(op, lhs, rhs)
             }
             Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::CheckedBinaryOp(op, lhs?, rhs?)
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::CheckedBinaryOp(op, lhs, rhs)
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
@@ -894,6 +915,92 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
     }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_binary(
+        &mut self,
+        op: BinOp,
+        checked: bool,
+        lhs_ty: Ty<'tcx>,
+        lhs: VnIndex,
+        rhs: VnIndex,
+    ) -> Option<VnIndex> {
+        // Floats are weird enough that none of the logic below applies.
+        let reasonable_ty =
+            lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char() || lhs_ty.is_any_ptr();
+        if !reasonable_ty {
+            return None;
+        }
+
+        let layout = self.ecx.layout_of(lhs_ty).ok()?;
+
+        let as_bits = |value| {
+            let constant = self.evaluated[value].as_ref()?;
+            let scalar = self.ecx.read_scalar(constant).ok()?;
+            scalar.to_bits(constant.layout.size).ok()
+        };
+
+        // Represent the values as `Ok(bits)` or `Err(VnIndex)`.
+        let a = as_bits(lhs).ok_or(lhs);
+        let b = as_bits(rhs).ok_or(rhs);
+        let result = match (op, a, b) {
+            // Neutral elements.
+            (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Ok(0), Err(p))
+            | (
+                BinOp::Add
+                | BinOp::BitOr
+                | BinOp::BitXor
+                | BinOp::Sub
+                | BinOp::Offset
+                | BinOp::Shl
+                | BinOp::Shr,
+                Err(p),
+                Ok(0),
+            )
+            | (BinOp::Mul, Ok(1), Err(p))
+            | (BinOp::Mul | BinOp::Div, Err(p), Ok(1)) => p,
+            // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
+            (BinOp::BitAnd, Err(p), Ok(ones)) | (BinOp::BitAnd, Ok(ones), Err(p))
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                p
+            }
+            // Absorbing elements.
+            (BinOp::Mul | BinOp::BitAnd, _, Ok(0))
+            | (BinOp::Rem, _, Ok(1))
+            | (
+                BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr,
+                Ok(0),
+                _,
+            ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
+            // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
+            (BinOp::BitOr, _, Ok(ones)) | (BinOp::BitOr, Ok(ones), _)
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
+            }
+            // Sub/Xor with itself.
+            (BinOp::Sub | BinOp::BitXor, a, b) if a == b => {
+                self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
+            }
+            // Comparison:
+            // - if both operands can be computed as bits, just compare the bits;
+            // - if we proved that both operands have the same value, we can insert true/false;
+            // - otherwise, do nothing, as we do not try to prove inequality.
+            (BinOp::Eq, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a == b),
+            (BinOp::Ne, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a != b),
+            _ => return None,
+        };
+
+        if checked {
+            let false_val = self.insert_bool(false);
+            Some(self.insert_tuple(vec![result, false_val]))
+        } else {
+            Some(result)
+        }
+    }
 }
 
 fn op_to_prop_const<'tcx>(
diff --git a/tests/mir-opt/const_prop/boolean_identities.rs b/tests/mir-opt/const_prop/boolean_identities.rs
index f6575ac8e54..3b7ea25ad46 100644
--- a/tests/mir-opt/const_prop/boolean_identities.rs
+++ b/tests/mir-opt/const_prop/boolean_identities.rs
@@ -5,10 +5,9 @@ pub fn test(x: bool, y: bool) -> bool {
     // CHECK-LABEL: fn test(
     // CHECK: debug a => [[a:_.*]];
     // CHECK: debug b => [[b:_.*]];
-    // FIXME(cjgillot) simplify algebraic identity
-    // CHECK-NOT: [[a]] = const true;
-    // CHECK-NOT: [[b]] = const false;
-    // CHECK-NOT: _0 = const false;
+    // CHECK: [[a]] = const true;
+    // CHECK: [[b]] = const false;
+    // CHECK: _0 = const false;
     let a = (y | true);
     let b = (x & false);
     a & b
diff --git a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
index eca87af7527..0bd8413289e 100644
--- a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
+++ b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
@@ -24,21 +24,23 @@
           StorageLive(_4);
           _4 = _2;
 -         _3 = BitOr(move _4, const true);
-+         _3 = BitOr(_2, const true);
++         _3 = const true;
           StorageDead(_4);
 -         StorageLive(_5);
 +         nop;
           StorageLive(_6);
           _6 = _1;
 -         _5 = BitAnd(move _6, const false);
-+         _5 = BitAnd(_1, const false);
++         _5 = const false;
           StorageDead(_6);
           StorageLive(_7);
-          _7 = _3;
+-         _7 = _3;
++         _7 = const true;
           StorageLive(_8);
-          _8 = _5;
+-         _8 = _5;
 -         _0 = BitAnd(move _7, move _8);
-+         _0 = BitAnd(_3, _5);
++         _8 = const false;
++         _0 = const false;
           StorageDead(_8);
           StorageDead(_7);
 -         StorageDead(_5);
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index b3fdaa5ee82..59ee38f5a2b 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -20,7 +20,8 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
 -         _4 = SizeOf(i32);
 -         _5 = AlignOf(i32);
@@ -39,8 +40,10 @@
           StorageDead(_7);
           _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
           _2 = (*_9);
-          _1 = Add(move _2, const 0_i32);
-          StorageDead(_2);
+-         _1 = Add(move _2, const 0_i32);
+-         StorageDead(_2);
++         _1 = _2;
++         nop;
           drop(_3) -> [return: bb2, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index d0350c97253..9d87bd809d1 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -20,7 +20,8 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
 -         _4 = SizeOf(i32);
 -         _5 = AlignOf(i32);
@@ -39,8 +40,10 @@
           StorageDead(_7);
           _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
           _2 = (*_9);
-          _1 = Add(move _2, const 0_i32);
-          StorageDead(_2);
+-         _1 = Add(move _2, const 0_i32);
+-         StorageDead(_2);
++         _1 = _2;
++         nop;
           drop(_3) -> [return: bb2, unwind: bb3];
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs
index 5227d7b8b8b..d2d61f86d5e 100644
--- a/tests/mir-opt/const_prop/boxes.rs
+++ b/tests/mir-opt/const_prop/boxes.rs
@@ -12,7 +12,7 @@ fn main() {
     // CHECK: debug x => [[x:_.*]];
     // CHECK: (*{{_.*}}) = const 42_i32;
     // CHECK: [[tmp:_.*]] = (*{{_.*}});
-    // CHECK: [[x]] = Add(move [[tmp]], const 0_i32);
+    // CHECK: [[x]] = [[tmp]];
     let x = *(#[rustc_box]
     Box::new(42))
         + 0;
diff --git a/tests/mir-opt/const_prop/mult_by_zero.rs b/tests/mir-opt/const_prop/mult_by_zero.rs
index 2fdb75c3100..b8afaeef43f 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.rs
+++ b/tests/mir-opt/const_prop/mult_by_zero.rs
@@ -3,8 +3,7 @@
 // EMIT_MIR mult_by_zero.test.GVN.diff
 fn test(x: i32) -> i32 {
     // CHECK: fn test(
-    // FIXME(cjgillot) simplify algebraic identity
-    // CHECK-NOT: _0 = const 0_i32;
+    // CHECK: _0 = const 0_i32;
     x * 0
 }
 
diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
index e9fb34749c1..6c2aab45d48 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
+++ b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
@@ -10,7 +10,7 @@
           StorageLive(_2);
           _2 = _1;
 -         _0 = Mul(move _2, const 0_i32);
-+         _0 = Mul(_1, const 0_i32);
++         _0 = const 0_i32;
           StorageDead(_2);
           return;
       }
diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
index d524ad242fe..84eb6c5cfe8 100644
--- a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
@@ -13,13 +13,13 @@
       let _8: ();
       let mut _9: u64;
       let mut _10: u64;
-      let _11: ();
-      let mut _12: u64;
+      let mut _11: u64;
+      let _12: ();
       let mut _13: u64;
-      let _14: ();
-      let mut _15: u64;
+      let mut _14: u64;
+      let _15: ();
       let mut _16: u64;
-      let mut _17: bool;
+      let mut _17: u64;
       let _18: ();
       let mut _19: u64;
       let mut _20: u64;
@@ -51,18 +51,32 @@
       let _46: ();
       let mut _47: u64;
       let mut _48: u64;
-      let _49: ();
-      let mut _50: u64;
+      let mut _49: bool;
+      let _50: ();
       let mut _51: u64;
-      let _52: ();
-      let mut _53: u64;
+      let mut _52: u64;
+      let _53: ();
       let mut _54: u64;
-      let _55: ();
-      let mut _56: u64;
+      let mut _55: u64;
+      let _56: ();
       let mut _57: u64;
-      let _58: ();
-      let mut _59: u64;
+      let mut _58: u64;
+      let _59: ();
       let mut _60: u64;
+      let mut _61: u64;
+      let _62: ();
+      let mut _63: u64;
+      let mut _64: u64;
+      let _65: ();
+      let mut _66: u64;
+      let mut _67: u64;
+      let mut _68: u64;
+      let _69: ();
+      let mut _70: u64;
+      let mut _71: u64;
+      let _72: ();
+      let mut _73: u64;
+      let mut _74: u64;
   
       bb0: {
           StorageLive(_2);
@@ -70,9 +84,10 @@
           StorageLive(_4);
           _4 = _1;
 -         _3 = Add(move _4, const 0_u64);
-+         _3 = Add(_1, const 0_u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable];
+-         _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable];
++         _2 = opaque::<u64>(_1) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -83,98 +98,101 @@
           StorageLive(_7);
           _7 = _1;
 -         _6 = Sub(move _7, const 0_u64);
-+         _6 = Sub(_1, const 0_u64);
++         _6 = _1;
           StorageDead(_7);
-          _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable];
+-         _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable];
++         _5 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
           StorageDead(_6);
           StorageDead(_5);
           StorageLive(_8);
-          StorageLive(_9);
+-         StorageLive(_9);
++         nop;
           StorageLive(_10);
           _10 = _1;
--         _9 = Mul(move _10, const 0_u64);
-+         _9 = Mul(_1, const 0_u64);
+          StorageLive(_11);
+          _11 = _1;
+-         _9 = Sub(move _10, move _11);
++         _9 = const 0_u64;
+          StorageDead(_11);
           StorageDead(_10);
-          _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable];
+-         _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable];
++         _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
-          StorageDead(_9);
+-         StorageDead(_9);
++         nop;
           StorageDead(_8);
-          StorageLive(_11);
           StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
--         _12 = Mul(move _13, const 1_u64);
-+         _12 = Mul(_1, const 1_u64);
-          StorageDead(_13);
-          _11 = opaque::<u64>(move _12) -> [return: bb4, unwind unreachable];
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Mul(move _14, const 0_u64);
++         _13 = const 0_u64;
+          StorageDead(_14);
+-         _12 = opaque::<u64>(move _13) -> [return: bb4, unwind unreachable];
++         _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
+          StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_11);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = Eq(const 0_u64, const 0_u64);
--         assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind unreachable];
-+         _17 = const true;
-+         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind unreachable];
+          StorageLive(_17);
+          _17 = _1;
+-         _16 = Mul(move _17, const 1_u64);
++         _16 = _1;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb5, unwind unreachable];
++         _15 = opaque::<u64>(_1) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
--         _15 = Div(move _16, const 0_u64);
-+         _15 = Div(_1, const 0_u64);
           StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb6, unwind unreachable];
-      }
-  
-      bb6: {
           StorageDead(_15);
-          StorageDead(_14);
           StorageLive(_18);
           StorageLive(_19);
           StorageLive(_20);
           _20 = _1;
--         _21 = Eq(const 1_u64, const 0_u64);
--         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind unreachable];
-+         _21 = const false;
-+         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind unreachable];
+-         _21 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind unreachable];
++         _21 = const true;
++         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+-         _19 = Div(move _20, const 0_u64);
++         _19 = Div(_1, const 0_u64);
+          StorageDead(_20);
+          _18 = opaque::<u64>(move _19) -> [return: bb7, unwind unreachable];
       }
   
       bb7: {
--         _19 = Div(move _20, const 1_u64);
-+         _19 = Div(_1, const 1_u64);
-          StorageDead(_20);
-          _18 = opaque::<u64>(move _19) -> [return: bb8, unwind unreachable];
-      }
-  
-      bb8: {
           StorageDead(_19);
           StorageDead(_18);
           StorageLive(_22);
           StorageLive(_23);
           StorageLive(_24);
           _24 = _1;
--         _25 = Eq(_24, const 0_u64);
--         assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable];
-+         _25 = Eq(_1, const 0_u64);
-+         assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable];
+-         _25 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind unreachable];
++         _25 = const false;
++         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind unreachable];
+      }
+  
+      bb8: {
+-         _23 = Div(move _24, const 1_u64);
++         _23 = _1;
+          StorageDead(_24);
+-         _22 = opaque::<u64>(move _23) -> [return: bb9, unwind unreachable];
++         _22 = opaque::<u64>(_1) -> [return: bb9, unwind unreachable];
       }
   
       bb9: {
--         _23 = Div(const 0_u64, move _24);
-+         _23 = Div(const 0_u64, _1);
-          StorageDead(_24);
-          _22 = opaque::<u64>(move _23) -> [return: bb10, unwind unreachable];
-      }
-  
-      bb10: {
           StorageDead(_23);
           StorageDead(_22);
           StorageLive(_26);
@@ -182,79 +200,81 @@
           StorageLive(_28);
           _28 = _1;
 -         _29 = Eq(_28, const 0_u64);
--         assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable];
-+         _29 = _25;
-+         assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable];
+-         assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable];
++         _29 = Eq(_1, const 0_u64);
++         assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable];
+      }
+  
+      bb10: {
+-         _27 = Div(const 0_u64, move _28);
++         _27 = const 0_u64;
+          StorageDead(_28);
+-         _26 = opaque::<u64>(move _27) -> [return: bb11, unwind unreachable];
++         _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind unreachable];
       }
   
       bb11: {
--         _27 = Div(const 1_u64, move _28);
-+         _27 = Div(const 1_u64, _1);
-          StorageDead(_28);
-          _26 = opaque::<u64>(move _27) -> [return: bb12, unwind unreachable];
-      }
-  
-      bb12: {
           StorageDead(_27);
           StorageDead(_26);
           StorageLive(_30);
           StorageLive(_31);
           StorageLive(_32);
           _32 = _1;
--         _33 = Eq(const 0_u64, const 0_u64);
--         assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind unreachable];
-+         _33 = const true;
-+         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind unreachable];
+-         _33 = Eq(_32, const 0_u64);
+-         assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable];
++         _33 = _29;
++         assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable];
+      }
+  
+      bb12: {
+-         _31 = Div(const 1_u64, move _32);
++         _31 = Div(const 1_u64, _1);
+          StorageDead(_32);
+          _30 = opaque::<u64>(move _31) -> [return: bb13, unwind unreachable];
       }
   
       bb13: {
--         _31 = Rem(move _32, const 0_u64);
-+         _31 = Rem(_1, const 0_u64);
-          StorageDead(_32);
-          _30 = opaque::<u64>(move _31) -> [return: bb14, unwind unreachable];
-      }
-  
-      bb14: {
           StorageDead(_31);
           StorageDead(_30);
           StorageLive(_34);
           StorageLive(_35);
           StorageLive(_36);
           _36 = _1;
--         _37 = Eq(const 1_u64, const 0_u64);
--         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind unreachable];
-+         _37 = const false;
-+         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind unreachable];
+-         _37 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind unreachable];
++         _37 = const true;
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind unreachable];
+      }
+  
+      bb14: {
+-         _35 = Rem(move _36, const 0_u64);
++         _35 = Rem(_1, const 0_u64);
+          StorageDead(_36);
+          _34 = opaque::<u64>(move _35) -> [return: bb15, unwind unreachable];
       }
   
       bb15: {
--         _35 = Rem(move _36, const 1_u64);
-+         _35 = Rem(_1, const 1_u64);
-          StorageDead(_36);
-          _34 = opaque::<u64>(move _35) -> [return: bb16, unwind unreachable];
-      }
-  
-      bb16: {
           StorageDead(_35);
           StorageDead(_34);
           StorageLive(_38);
           StorageLive(_39);
           StorageLive(_40);
           _40 = _1;
--         _41 = Eq(_40, const 0_u64);
--         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable];
-+         _41 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable];
+-         _41 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind unreachable];
++         _41 = const false;
++         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind unreachable];
+      }
+  
+      bb16: {
+-         _39 = Rem(move _40, const 1_u64);
++         _39 = const 0_u64;
+          StorageDead(_40);
+-         _38 = opaque::<u64>(move _39) -> [return: bb17, unwind unreachable];
++         _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind unreachable];
       }
   
       bb17: {
--         _39 = Rem(const 0_u64, move _40);
-+         _39 = Rem(const 0_u64, _1);
-          StorageDead(_40);
-          _38 = opaque::<u64>(move _39) -> [return: bb18, unwind unreachable];
-      }
-  
-      bb18: {
           StorageDead(_39);
           StorageDead(_38);
           StorageLive(_42);
@@ -262,27 +282,35 @@
           StorageLive(_44);
           _44 = _1;
 -         _45 = Eq(_44, const 0_u64);
--         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable];
-+         _45 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable];
+-         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable];
++         _45 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable];
+      }
+  
+      bb18: {
+-         _43 = Rem(const 0_u64, move _44);
++         _43 = const 0_u64;
+          StorageDead(_44);
+-         _42 = opaque::<u64>(move _43) -> [return: bb19, unwind unreachable];
++         _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind unreachable];
       }
   
       bb19: {
--         _43 = Rem(const 1_u64, move _44);
-+         _43 = Rem(const 1_u64, _1);
-          StorageDead(_44);
-          _42 = opaque::<u64>(move _43) -> [return: bb20, unwind unreachable];
-      }
-  
-      bb20: {
           StorageDead(_43);
           StorageDead(_42);
           StorageLive(_46);
           StorageLive(_47);
           StorageLive(_48);
           _48 = _1;
--         _47 = BitAnd(move _48, const 0_u64);
-+         _47 = BitAnd(_1, const 0_u64);
+-         _49 = Eq(_48, const 0_u64);
+-         assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable];
++         _49 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable];
+      }
+  
+      bb20: {
+-         _47 = Rem(const 1_u64, move _48);
++         _47 = Rem(const 1_u64, _1);
           StorageDead(_48);
           _46 = opaque::<u64>(move _47) -> [return: bb21, unwind unreachable];
       }
@@ -290,58 +318,121 @@
       bb21: {
           StorageDead(_47);
           StorageDead(_46);
-          StorageLive(_49);
           StorageLive(_50);
           StorageLive(_51);
-          _51 = _1;
--         _50 = BitOr(move _51, const 0_u64);
-+         _50 = BitOr(_1, const 0_u64);
-          StorageDead(_51);
-          _49 = opaque::<u64>(move _50) -> [return: bb22, unwind unreachable];
+          StorageLive(_52);
+          _52 = _1;
+-         _51 = BitAnd(move _52, const 0_u64);
++         _51 = const 0_u64;
+          StorageDead(_52);
+-         _50 = opaque::<u64>(move _51) -> [return: bb22, unwind unreachable];
++         _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind unreachable];
       }
   
       bb22: {
+          StorageDead(_51);
           StorageDead(_50);
-          StorageDead(_49);
-          StorageLive(_52);
           StorageLive(_53);
           StorageLive(_54);
-          _54 = _1;
--         _53 = BitXor(move _54, const 0_u64);
-+         _53 = BitXor(_1, const 0_u64);
-          StorageDead(_54);
-          _52 = opaque::<u64>(move _53) -> [return: bb23, unwind unreachable];
+          StorageLive(_55);
+          _55 = _1;
+-         _54 = BitAnd(move _55, const _);
++         _54 = _1;
+          StorageDead(_55);
+-         _53 = opaque::<u64>(move _54) -> [return: bb23, unwind unreachable];
++         _53 = opaque::<u64>(_1) -> [return: bb23, unwind unreachable];
       }
   
       bb23: {
+          StorageDead(_54);
           StorageDead(_53);
-          StorageDead(_52);
-          StorageLive(_55);
           StorageLive(_56);
           StorageLive(_57);
-          _57 = _1;
--         _56 = Shr(move _57, const 0_i32);
-+         _56 = Shr(_1, const 0_i32);
-          StorageDead(_57);
-          _55 = opaque::<u64>(move _56) -> [return: bb24, unwind unreachable];
+          StorageLive(_58);
+          _58 = _1;
+-         _57 = BitOr(move _58, const 0_u64);
++         _57 = _1;
+          StorageDead(_58);
+-         _56 = opaque::<u64>(move _57) -> [return: bb24, unwind unreachable];
++         _56 = opaque::<u64>(_1) -> [return: bb24, unwind unreachable];
       }
   
       bb24: {
+          StorageDead(_57);
           StorageDead(_56);
-          StorageDead(_55);
-          StorageLive(_58);
           StorageLive(_59);
           StorageLive(_60);
-          _60 = _1;
--         _59 = Shl(move _60, const 0_i32);
-+         _59 = Shl(_1, const 0_i32);
-          StorageDead(_60);
-          _58 = opaque::<u64>(move _59) -> [return: bb25, unwind unreachable];
+          StorageLive(_61);
+          _61 = _1;
+-         _60 = BitOr(move _61, const _);
++         _60 = const u64::MAX;
+          StorageDead(_61);
+-         _59 = opaque::<u64>(move _60) -> [return: bb25, unwind unreachable];
++         _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind unreachable];
       }
   
       bb25: {
+          StorageDead(_60);
           StorageDead(_59);
-          StorageDead(_58);
+          StorageLive(_62);
+          StorageLive(_63);
+          StorageLive(_64);
+          _64 = _1;
+-         _63 = BitXor(move _64, const 0_u64);
++         _63 = _1;
+          StorageDead(_64);
+-         _62 = opaque::<u64>(move _63) -> [return: bb26, unwind unreachable];
++         _62 = opaque::<u64>(_1) -> [return: bb26, unwind unreachable];
+      }
+  
+      bb26: {
+          StorageDead(_63);
+          StorageDead(_62);
+          StorageLive(_65);
+          StorageLive(_66);
+          StorageLive(_67);
+          _67 = _1;
+          StorageLive(_68);
+          _68 = _1;
+-         _66 = BitXor(move _67, move _68);
++         _66 = const 0_u64;
+          StorageDead(_68);
+          StorageDead(_67);
+-         _65 = opaque::<u64>(move _66) -> [return: bb27, unwind unreachable];
++         _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind unreachable];
+      }
+  
+      bb27: {
+          StorageDead(_66);
+          StorageDead(_65);
+          StorageLive(_69);
+          StorageLive(_70);
+          StorageLive(_71);
+          _71 = _1;
+-         _70 = Shr(move _71, const 0_i32);
++         _70 = _1;
+          StorageDead(_71);
+-         _69 = opaque::<u64>(move _70) -> [return: bb28, unwind unreachable];
++         _69 = opaque::<u64>(_1) -> [return: bb28, unwind unreachable];
+      }
+  
+      bb28: {
+          StorageDead(_70);
+          StorageDead(_69);
+          StorageLive(_72);
+          StorageLive(_73);
+          StorageLive(_74);
+          _74 = _1;
+-         _73 = Shl(move _74, const 0_i32);
++         _73 = _1;
+          StorageDead(_74);
+-         _72 = opaque::<u64>(move _73) -> [return: bb29, unwind unreachable];
++         _72 = opaque::<u64>(_1) -> [return: bb29, unwind unreachable];
+      }
+  
+      bb29: {
+          StorageDead(_73);
+          StorageDead(_72);
           _0 = const ();
           return;
       }
diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
index 9d69353934c..98e92d2a310 100644
--- a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
@@ -13,13 +13,13 @@
       let _8: ();
       let mut _9: u64;
       let mut _10: u64;
-      let _11: ();
-      let mut _12: u64;
+      let mut _11: u64;
+      let _12: ();
       let mut _13: u64;
-      let _14: ();
-      let mut _15: u64;
+      let mut _14: u64;
+      let _15: ();
       let mut _16: u64;
-      let mut _17: bool;
+      let mut _17: u64;
       let _18: ();
       let mut _19: u64;
       let mut _20: u64;
@@ -51,18 +51,32 @@
       let _46: ();
       let mut _47: u64;
       let mut _48: u64;
-      let _49: ();
-      let mut _50: u64;
+      let mut _49: bool;
+      let _50: ();
       let mut _51: u64;
-      let _52: ();
-      let mut _53: u64;
+      let mut _52: u64;
+      let _53: ();
       let mut _54: u64;
-      let _55: ();
-      let mut _56: u64;
+      let mut _55: u64;
+      let _56: ();
       let mut _57: u64;
-      let _58: ();
-      let mut _59: u64;
+      let mut _58: u64;
+      let _59: ();
       let mut _60: u64;
+      let mut _61: u64;
+      let _62: ();
+      let mut _63: u64;
+      let mut _64: u64;
+      let _65: ();
+      let mut _66: u64;
+      let mut _67: u64;
+      let mut _68: u64;
+      let _69: ();
+      let mut _70: u64;
+      let mut _71: u64;
+      let _72: ();
+      let mut _73: u64;
+      let mut _74: u64;
   
       bb0: {
           StorageLive(_2);
@@ -70,9 +84,10 @@
           StorageLive(_4);
           _4 = _1;
 -         _3 = Add(move _4, const 0_u64);
-+         _3 = Add(_1, const 0_u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue];
+-         _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue];
++         _2 = opaque::<u64>(_1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -83,98 +98,101 @@
           StorageLive(_7);
           _7 = _1;
 -         _6 = Sub(move _7, const 0_u64);
-+         _6 = Sub(_1, const 0_u64);
++         _6 = _1;
           StorageDead(_7);
-          _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue];
+-         _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue];
++         _5 = opaque::<u64>(_1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
           StorageDead(_6);
           StorageDead(_5);
           StorageLive(_8);
-          StorageLive(_9);
+-         StorageLive(_9);
++         nop;
           StorageLive(_10);
           _10 = _1;
--         _9 = Mul(move _10, const 0_u64);
-+         _9 = Mul(_1, const 0_u64);
+          StorageLive(_11);
+          _11 = _1;
+-         _9 = Sub(move _10, move _11);
++         _9 = const 0_u64;
+          StorageDead(_11);
           StorageDead(_10);
-          _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue];
+-         _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue];
++         _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind continue];
       }
   
       bb3: {
-          StorageDead(_9);
+-         StorageDead(_9);
++         nop;
           StorageDead(_8);
-          StorageLive(_11);
           StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
--         _12 = Mul(move _13, const 1_u64);
-+         _12 = Mul(_1, const 1_u64);
-          StorageDead(_13);
-          _11 = opaque::<u64>(move _12) -> [return: bb4, unwind continue];
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Mul(move _14, const 0_u64);
++         _13 = const 0_u64;
+          StorageDead(_14);
+-         _12 = opaque::<u64>(move _13) -> [return: bb4, unwind continue];
++         _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind continue];
       }
   
       bb4: {
+          StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_11);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = Eq(const 0_u64, const 0_u64);
--         assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind continue];
-+         _17 = const true;
-+         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind continue];
+          StorageLive(_17);
+          _17 = _1;
+-         _16 = Mul(move _17, const 1_u64);
++         _16 = _1;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb5, unwind continue];
++         _15 = opaque::<u64>(_1) -> [return: bb5, unwind continue];
       }
   
       bb5: {
--         _15 = Div(move _16, const 0_u64);
-+         _15 = Div(_1, const 0_u64);
           StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb6, unwind continue];
-      }
-  
-      bb6: {
           StorageDead(_15);
-          StorageDead(_14);
           StorageLive(_18);
           StorageLive(_19);
           StorageLive(_20);
           _20 = _1;
--         _21 = Eq(const 1_u64, const 0_u64);
--         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind continue];
-+         _21 = const false;
-+         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind continue];
+-         _21 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind continue];
++         _21 = const true;
++         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind continue];
+      }
+  
+      bb6: {
+-         _19 = Div(move _20, const 0_u64);
++         _19 = Div(_1, const 0_u64);
+          StorageDead(_20);
+          _18 = opaque::<u64>(move _19) -> [return: bb7, unwind continue];
       }
   
       bb7: {
--         _19 = Div(move _20, const 1_u64);
-+         _19 = Div(_1, const 1_u64);
-          StorageDead(_20);
-          _18 = opaque::<u64>(move _19) -> [return: bb8, unwind continue];
-      }
-  
-      bb8: {
           StorageDead(_19);
           StorageDead(_18);
           StorageLive(_22);
           StorageLive(_23);
           StorageLive(_24);
           _24 = _1;
--         _25 = Eq(_24, const 0_u64);
--         assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue];
-+         _25 = Eq(_1, const 0_u64);
-+         assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue];
+-         _25 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind continue];
++         _25 = const false;
++         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind continue];
+      }
+  
+      bb8: {
+-         _23 = Div(move _24, const 1_u64);
++         _23 = _1;
+          StorageDead(_24);
+-         _22 = opaque::<u64>(move _23) -> [return: bb9, unwind continue];
++         _22 = opaque::<u64>(_1) -> [return: bb9, unwind continue];
       }
   
       bb9: {
--         _23 = Div(const 0_u64, move _24);
-+         _23 = Div(const 0_u64, _1);
-          StorageDead(_24);
-          _22 = opaque::<u64>(move _23) -> [return: bb10, unwind continue];
-      }
-  
-      bb10: {
           StorageDead(_23);
           StorageDead(_22);
           StorageLive(_26);
@@ -182,79 +200,81 @@
           StorageLive(_28);
           _28 = _1;
 -         _29 = Eq(_28, const 0_u64);
--         assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue];
-+         _29 = _25;
-+         assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue];
+-         assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue];
++         _29 = Eq(_1, const 0_u64);
++         assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue];
+      }
+  
+      bb10: {
+-         _27 = Div(const 0_u64, move _28);
++         _27 = const 0_u64;
+          StorageDead(_28);
+-         _26 = opaque::<u64>(move _27) -> [return: bb11, unwind continue];
++         _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind continue];
       }
   
       bb11: {
--         _27 = Div(const 1_u64, move _28);
-+         _27 = Div(const 1_u64, _1);
-          StorageDead(_28);
-          _26 = opaque::<u64>(move _27) -> [return: bb12, unwind continue];
-      }
-  
-      bb12: {
           StorageDead(_27);
           StorageDead(_26);
           StorageLive(_30);
           StorageLive(_31);
           StorageLive(_32);
           _32 = _1;
--         _33 = Eq(const 0_u64, const 0_u64);
--         assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind continue];
-+         _33 = const true;
-+         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind continue];
+-         _33 = Eq(_32, const 0_u64);
+-         assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue];
++         _33 = _29;
++         assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue];
+      }
+  
+      bb12: {
+-         _31 = Div(const 1_u64, move _32);
++         _31 = Div(const 1_u64, _1);
+          StorageDead(_32);
+          _30 = opaque::<u64>(move _31) -> [return: bb13, unwind continue];
       }
   
       bb13: {
--         _31 = Rem(move _32, const 0_u64);
-+         _31 = Rem(_1, const 0_u64);
-          StorageDead(_32);
-          _30 = opaque::<u64>(move _31) -> [return: bb14, unwind continue];
-      }
-  
-      bb14: {
           StorageDead(_31);
           StorageDead(_30);
           StorageLive(_34);
           StorageLive(_35);
           StorageLive(_36);
           _36 = _1;
--         _37 = Eq(const 1_u64, const 0_u64);
--         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind continue];
-+         _37 = const false;
-+         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind continue];
+-         _37 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind continue];
++         _37 = const true;
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind continue];
+      }
+  
+      bb14: {
+-         _35 = Rem(move _36, const 0_u64);
++         _35 = Rem(_1, const 0_u64);
+          StorageDead(_36);
+          _34 = opaque::<u64>(move _35) -> [return: bb15, unwind continue];
       }
   
       bb15: {
--         _35 = Rem(move _36, const 1_u64);
-+         _35 = Rem(_1, const 1_u64);
-          StorageDead(_36);
-          _34 = opaque::<u64>(move _35) -> [return: bb16, unwind continue];
-      }
-  
-      bb16: {
           StorageDead(_35);
           StorageDead(_34);
           StorageLive(_38);
           StorageLive(_39);
           StorageLive(_40);
           _40 = _1;
--         _41 = Eq(_40, const 0_u64);
--         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue];
-+         _41 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue];
+-         _41 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind continue];
++         _41 = const false;
++         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind continue];
+      }
+  
+      bb16: {
+-         _39 = Rem(move _40, const 1_u64);
++         _39 = const 0_u64;
+          StorageDead(_40);
+-         _38 = opaque::<u64>(move _39) -> [return: bb17, unwind continue];
++         _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind continue];
       }
   
       bb17: {
--         _39 = Rem(const 0_u64, move _40);
-+         _39 = Rem(const 0_u64, _1);
-          StorageDead(_40);
-          _38 = opaque::<u64>(move _39) -> [return: bb18, unwind continue];
-      }
-  
-      bb18: {
           StorageDead(_39);
           StorageDead(_38);
           StorageLive(_42);
@@ -262,27 +282,35 @@
           StorageLive(_44);
           _44 = _1;
 -         _45 = Eq(_44, const 0_u64);
--         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue];
-+         _45 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue];
+-         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue];
++         _45 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue];
+      }
+  
+      bb18: {
+-         _43 = Rem(const 0_u64, move _44);
++         _43 = const 0_u64;
+          StorageDead(_44);
+-         _42 = opaque::<u64>(move _43) -> [return: bb19, unwind continue];
++         _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind continue];
       }
   
       bb19: {
--         _43 = Rem(const 1_u64, move _44);
-+         _43 = Rem(const 1_u64, _1);
-          StorageDead(_44);
-          _42 = opaque::<u64>(move _43) -> [return: bb20, unwind continue];
-      }
-  
-      bb20: {
           StorageDead(_43);
           StorageDead(_42);
           StorageLive(_46);
           StorageLive(_47);
           StorageLive(_48);
           _48 = _1;
--         _47 = BitAnd(move _48, const 0_u64);
-+         _47 = BitAnd(_1, const 0_u64);
+-         _49 = Eq(_48, const 0_u64);
+-         assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue];
++         _49 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue];
+      }
+  
+      bb20: {
+-         _47 = Rem(const 1_u64, move _48);
++         _47 = Rem(const 1_u64, _1);
           StorageDead(_48);
           _46 = opaque::<u64>(move _47) -> [return: bb21, unwind continue];
       }
@@ -290,58 +318,121 @@
       bb21: {
           StorageDead(_47);
           StorageDead(_46);
-          StorageLive(_49);
           StorageLive(_50);
           StorageLive(_51);
-          _51 = _1;
--         _50 = BitOr(move _51, const 0_u64);
-+         _50 = BitOr(_1, const 0_u64);
-          StorageDead(_51);
-          _49 = opaque::<u64>(move _50) -> [return: bb22, unwind continue];
+          StorageLive(_52);
+          _52 = _1;
+-         _51 = BitAnd(move _52, const 0_u64);
++         _51 = const 0_u64;
+          StorageDead(_52);
+-         _50 = opaque::<u64>(move _51) -> [return: bb22, unwind continue];
++         _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind continue];
       }
   
       bb22: {
+          StorageDead(_51);
           StorageDead(_50);
-          StorageDead(_49);
-          StorageLive(_52);
           StorageLive(_53);
           StorageLive(_54);
-          _54 = _1;
--         _53 = BitXor(move _54, const 0_u64);
-+         _53 = BitXor(_1, const 0_u64);
-          StorageDead(_54);
-          _52 = opaque::<u64>(move _53) -> [return: bb23, unwind continue];
+          StorageLive(_55);
+          _55 = _1;
+-         _54 = BitAnd(move _55, const _);
++         _54 = _1;
+          StorageDead(_55);
+-         _53 = opaque::<u64>(move _54) -> [return: bb23, unwind continue];
++         _53 = opaque::<u64>(_1) -> [return: bb23, unwind continue];
       }
   
       bb23: {
+          StorageDead(_54);
           StorageDead(_53);
-          StorageDead(_52);
-          StorageLive(_55);
           StorageLive(_56);
           StorageLive(_57);
-          _57 = _1;
--         _56 = Shr(move _57, const 0_i32);
-+         _56 = Shr(_1, const 0_i32);
-          StorageDead(_57);
-          _55 = opaque::<u64>(move _56) -> [return: bb24, unwind continue];
+          StorageLive(_58);
+          _58 = _1;
+-         _57 = BitOr(move _58, const 0_u64);
++         _57 = _1;
+          StorageDead(_58);
+-         _56 = opaque::<u64>(move _57) -> [return: bb24, unwind continue];
++         _56 = opaque::<u64>(_1) -> [return: bb24, unwind continue];
       }
   
       bb24: {
+          StorageDead(_57);
           StorageDead(_56);
-          StorageDead(_55);
-          StorageLive(_58);
           StorageLive(_59);
           StorageLive(_60);
-          _60 = _1;
--         _59 = Shl(move _60, const 0_i32);
-+         _59 = Shl(_1, const 0_i32);
-          StorageDead(_60);
-          _58 = opaque::<u64>(move _59) -> [return: bb25, unwind continue];
+          StorageLive(_61);
+          _61 = _1;
+-         _60 = BitOr(move _61, const _);
++         _60 = const u64::MAX;
+          StorageDead(_61);
+-         _59 = opaque::<u64>(move _60) -> [return: bb25, unwind continue];
++         _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind continue];
       }
   
       bb25: {
+          StorageDead(_60);
           StorageDead(_59);
-          StorageDead(_58);
+          StorageLive(_62);
+          StorageLive(_63);
+          StorageLive(_64);
+          _64 = _1;
+-         _63 = BitXor(move _64, const 0_u64);
++         _63 = _1;
+          StorageDead(_64);
+-         _62 = opaque::<u64>(move _63) -> [return: bb26, unwind continue];
++         _62 = opaque::<u64>(_1) -> [return: bb26, unwind continue];
+      }
+  
+      bb26: {
+          StorageDead(_63);
+          StorageDead(_62);
+          StorageLive(_65);
+          StorageLive(_66);
+          StorageLive(_67);
+          _67 = _1;
+          StorageLive(_68);
+          _68 = _1;
+-         _66 = BitXor(move _67, move _68);
++         _66 = const 0_u64;
+          StorageDead(_68);
+          StorageDead(_67);
+-         _65 = opaque::<u64>(move _66) -> [return: bb27, unwind continue];
++         _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind continue];
+      }
+  
+      bb27: {
+          StorageDead(_66);
+          StorageDead(_65);
+          StorageLive(_69);
+          StorageLive(_70);
+          StorageLive(_71);
+          _71 = _1;
+-         _70 = Shr(move _71, const 0_i32);
++         _70 = _1;
+          StorageDead(_71);
+-         _69 = opaque::<u64>(move _70) -> [return: bb28, unwind continue];
++         _69 = opaque::<u64>(_1) -> [return: bb28, unwind continue];
+      }
+  
+      bb28: {
+          StorageDead(_70);
+          StorageDead(_69);
+          StorageLive(_72);
+          StorageLive(_73);
+          StorageLive(_74);
+          _74 = _1;
+-         _73 = Shl(move _74, const 0_i32);
++         _73 = _1;
+          StorageDead(_74);
+-         _72 = opaque::<u64>(move _73) -> [return: bb29, unwind continue];
++         _72 = opaque::<u64>(_1) -> [return: bb29, unwind continue];
+      }
+  
+      bb29: {
+          StorageDead(_73);
+          StorageDead(_72);
           _0 = const ();
           return;
       }
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
index 6633df3ae70..a45d9920a68 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
@@ -15,11 +15,16 @@
       let _10: ();
       let mut _11: u64;
       let mut _12: u64;
-      let mut _13: (u64, bool);
-      let _14: ();
-      let mut _15: u64;
+      let mut _13: u64;
+      let mut _14: (u64, bool);
+      let _15: ();
       let mut _16: u64;
-      let mut _17: (u64, bool);
+      let mut _17: u64;
+      let mut _18: (u64, bool);
+      let _19: ();
+      let mut _20: u64;
+      let mut _21: u64;
+      let mut _22: (u64, bool);
   
       bb0: {
           StorageLive(_2);
@@ -29,13 +34,15 @@
 -         _5 = CheckedAdd(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable];
 +         _5 = CheckedAdd(_1, const 0_u64);
-+         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
-          _3 = move (_5.0: u64);
+-         _3 = move (_5.0: u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable];
+-         _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable];
++         _2 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
@@ -47,59 +54,95 @@
           _8 = _1;
 -         _9 = CheckedSub(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable];
-+         _9 = CheckedSub(_1, const 0_u64);
-+         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
++         _9 = _5;
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
-          _7 = move (_9.0: u64);
+-         _7 = move (_9.0: u64);
++         _7 = _1;
           StorageDead(_8);
-          _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable];
+-         _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable];
++         _6 = opaque::<u64>(_1) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
           StorageDead(_7);
           StorageDead(_6);
           StorageLive(_10);
-          StorageLive(_11);
+-         StorageLive(_11);
++         nop;
           StorageLive(_12);
           _12 = _1;
--         _13 = CheckedMul(_12, const 0_u64);
--         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind unreachable];
-+         _13 = CheckedMul(_1, const 0_u64);
-+         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind unreachable];
+          StorageLive(_13);
+          _13 = _1;
+-         _14 = CheckedSub(_12, _13);
+-         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable];
++         _14 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable];
       }
   
       bb5: {
-          _11 = move (_13.0: u64);
+-         _11 = move (_14.0: u64);
++         _11 = const 0_u64;
+          StorageDead(_13);
           StorageDead(_12);
-          _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable];
+-         _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable];
++         _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
-          StorageDead(_11);
+-         StorageDead(_11);
++         nop;
           StorageDead(_10);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = CheckedMul(_16, const 1_u64);
--         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind unreachable];
-+         _17 = CheckedMul(_1, const 1_u64);
-+         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind unreachable];
+          StorageLive(_17);
+          _17 = _1;
+-         _18 = CheckedMul(_17, const 0_u64);
+-         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable];
++         _18 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable];
       }
   
       bb7: {
-          _15 = move (_17.0: u64);
-          StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb8, unwind unreachable];
+-         _16 = move (_18.0: u64);
++         _16 = const 0_u64;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb8, unwind unreachable];
++         _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind unreachable];
       }
   
       bb8: {
+          StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_14);
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_21);
+          _21 = _1;
+-         _22 = CheckedMul(_21, const 1_u64);
+-         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable];
++         _22 = _5;
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable];
+      }
+  
+      bb9: {
+-         _20 = move (_22.0: u64);
++         _20 = _1;
+          StorageDead(_21);
+-         _19 = opaque::<u64>(move _20) -> [return: bb10, unwind unreachable];
++         _19 = opaque::<u64>(_1) -> [return: bb10, unwind unreachable];
+      }
+  
+      bb10: {
+          StorageDead(_20);
+          StorageDead(_19);
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
   
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
index d100a77fee5..9033b392bd4 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
@@ -15,11 +15,16 @@
       let _10: ();
       let mut _11: u64;
       let mut _12: u64;
-      let mut _13: (u64, bool);
-      let _14: ();
-      let mut _15: u64;
+      let mut _13: u64;
+      let mut _14: (u64, bool);
+      let _15: ();
       let mut _16: u64;
-      let mut _17: (u64, bool);
+      let mut _17: u64;
+      let mut _18: (u64, bool);
+      let _19: ();
+      let mut _20: u64;
+      let mut _21: u64;
+      let mut _22: (u64, bool);
   
       bb0: {
           StorageLive(_2);
@@ -29,13 +34,15 @@
 -         _5 = CheckedAdd(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue];
 +         _5 = CheckedAdd(_1, const 0_u64);
-+         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
       }
   
       bb1: {
-          _3 = move (_5.0: u64);
+-         _3 = move (_5.0: u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue];
+-         _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue];
++         _2 = opaque::<u64>(_1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -47,59 +54,95 @@
           _8 = _1;
 -         _9 = CheckedSub(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue];
-+         _9 = CheckedSub(_1, const 0_u64);
-+         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
++         _9 = _5;
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
       }
   
       bb3: {
-          _7 = move (_9.0: u64);
+-         _7 = move (_9.0: u64);
++         _7 = _1;
           StorageDead(_8);
-          _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue];
+-         _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue];
++         _6 = opaque::<u64>(_1) -> [return: bb4, unwind continue];
       }
   
       bb4: {
           StorageDead(_7);
           StorageDead(_6);
           StorageLive(_10);
-          StorageLive(_11);
+-         StorageLive(_11);
++         nop;
           StorageLive(_12);
           _12 = _1;
--         _13 = CheckedMul(_12, const 0_u64);
--         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind continue];
-+         _13 = CheckedMul(_1, const 0_u64);
-+         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind continue];
+          StorageLive(_13);
+          _13 = _1;
+-         _14 = CheckedSub(_12, _13);
+-         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue];
++         _14 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue];
       }
   
       bb5: {
-          _11 = move (_13.0: u64);
+-         _11 = move (_14.0: u64);
++         _11 = const 0_u64;
+          StorageDead(_13);
           StorageDead(_12);
-          _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue];
+-         _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue];
++         _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind continue];
       }
   
       bb6: {
-          StorageDead(_11);
+-         StorageDead(_11);
++         nop;
           StorageDead(_10);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = CheckedMul(_16, const 1_u64);
--         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind continue];
-+         _17 = CheckedMul(_1, const 1_u64);
-+         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind continue];
+          StorageLive(_17);
+          _17 = _1;
+-         _18 = CheckedMul(_17, const 0_u64);
+-         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue];
++         _18 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue];
       }
   
       bb7: {
-          _15 = move (_17.0: u64);
-          StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb8, unwind continue];
+-         _16 = move (_18.0: u64);
++         _16 = const 0_u64;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb8, unwind continue];
++         _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind continue];
       }
   
       bb8: {
+          StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_14);
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_21);
+          _21 = _1;
+-         _22 = CheckedMul(_21, const 1_u64);
+-         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue];
++         _22 = _5;
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue];
+      }
+  
+      bb9: {
+-         _20 = move (_22.0: u64);
++         _20 = _1;
+          StorageDead(_21);
+-         _19 = opaque::<u64>(move _20) -> [return: bb10, unwind continue];
++         _19 = opaque::<u64>(_1) -> [return: bb10, unwind continue];
+      }
+  
+      bb10: {
+          StorageDead(_20);
+          StorageDead(_19);
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
   
diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
index ee3b9da2122..fefdf14bddc 100644
--- a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
@@ -30,10 +30,11 @@
           StorageLive(_6);
           _6 = _1;
 -         _4 = Eq(move _5, move _6);
-+         _4 = Eq(_1, _1);
++         _4 = const true;
           StorageDead(_6);
           StorageDead(_5);
-          _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable];
+-         _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable];
++         _3 = opaque::<bool>(const true) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -46,10 +47,11 @@
           StorageLive(_10);
           _10 = _1;
 -         _8 = Ne(move _9, move _10);
-+         _8 = Ne(_1, _1);
++         _8 = const false;
           StorageDead(_10);
           StorageDead(_9);
-          _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable];
+-         _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable];
++         _7 = opaque::<bool>(const false) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
index a1408fe3434..9f19b2b59fa 100644
--- a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
@@ -30,10 +30,11 @@
           StorageLive(_6);
           _6 = _1;
 -         _4 = Eq(move _5, move _6);
-+         _4 = Eq(_1, _1);
++         _4 = const true;
           StorageDead(_6);
           StorageDead(_5);
-          _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue];
+-         _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue];
++         _3 = opaque::<bool>(const true) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -46,10 +47,11 @@
           StorageLive(_10);
           _10 = _1;
 -         _8 = Ne(move _9, move _10);
-+         _8 = Ne(_1, _1);
++         _8 = const false;
           StorageDead(_10);
           StorageDead(_9);
-          _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue];
+-         _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue];
++         _7 = opaque::<bool>(const false) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index d8248d22d38..0901896af53 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
+              let _7: {closure@$DIR/gvn.rs:585:19: 585:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
+-         _7 = {closure@$DIR/gvn.rs:585:19: 585:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index e38a3d85209..4b95191ba82 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
+              let _7: {closure@$DIR/gvn.rs:585:19: 585:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
+-         _7 = {closure@$DIR/gvn.rs:585:19: 585:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 23e33a0fa49..8c06e3a6385 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -169,66 +169,61 @@ fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
 /// Verify symbolic integer arithmetic simplifications.
 fn arithmetic(x: u64) {
     // CHECK-LABEL: fn arithmetic(
-    // CHECK: [[add:_.*]] = Add(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[add]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x + 0);
-    // CHECK: [[sub:_.*]] = Sub(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[sub]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x - 0);
-    // CHECK: [[mul0:_.*]] = Mul(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[mul0]])
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x - x);
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x * 0);
-    // CHECK: [[mul1:_.*]] = Mul(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[mul1]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x * 1);
+    // CHECK: assert(!const true, "attempt to divide `{}` by zero",
     // CHECK: [[div0:_.*]] = Div(_1, const 0_u64);
     // CHECK: opaque::<u64>(move [[div0]])
     opaque(x / 0);
-    // CHECK: [[div1:_.*]] = Div(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[div1]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x / 1);
-    // CHECK: [[zdiv:_.*]] = Div(const 0_u64, _1);
-    // CHECK: opaque::<u64>(move [[zdiv]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(0 / x);
     // CHECK: [[odiv:_.*]] = Div(const 1_u64, _1);
     // CHECK: opaque::<u64>(move [[odiv]])
     opaque(1 / x);
+    // CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero"
     // CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64);
     // CHECK: opaque::<u64>(move [[rem0]])
     opaque(x % 0);
-    // CHECK: [[rem1:_.*]] = Rem(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[rem1]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x % 1);
-    // CHECK: [[zrem:_.*]] = Rem(const 0_u64, _1);
-    // CHECK: opaque::<u64>(move [[zrem]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(0 % x);
     // CHECK: [[orem:_.*]] = Rem(const 1_u64, _1);
     // CHECK: opaque::<u64>(move [[orem]])
     opaque(1 % x);
-    // CHECK: [[and:_.*]] = BitAnd(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[and]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x & 0);
-    // CHECK: [[or:_.*]] = BitOr(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[or]])
+    // CHECK: opaque::<u64>(_1)
+    opaque(x & u64::MAX);
+    // CHECK: opaque::<u64>(_1)
     opaque(x | 0);
-    // CHECK: [[xor:_.*]] = BitXor(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[xor]])
+    // CHECK: opaque::<u64>(const u64::MAX)
+    opaque(x | u64::MAX);
+    // CHECK: opaque::<u64>(_1)
     opaque(x ^ 0);
-    // CHECK: [[shr:_.*]] = Shr(_1, const 0_i32);
-    // CHECK: opaque::<u64>(move [[shr]])
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x ^ x);
+    // CHECK: opaque::<u64>(_1)
     opaque(x >> 0);
-    // CHECK: [[shl:_.*]] = Shl(_1, const 0_i32);
-    // CHECK: opaque::<u64>(move [[shl]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x << 0);
 }
 
 fn comparison(x: u64, y: u64) {
     // CHECK-LABEL: fn comparison(
-    // CHECK: [[eqxx:_.*]] = Eq(_1, _1);
-    // CHECK: opaque::<bool>(move [[eqxx]])
+    // CHECK: opaque::<bool>(const true)
     opaque(x == x);
-    // CHECK: [[nexx:_.*]] = Ne(_1, _1);
-    // CHECK: opaque::<bool>(move [[nexx]])
+    // CHECK: opaque::<bool>(const false)
     opaque(x != x);
     // CHECK: [[eqxy:_.*]] = Eq(_1, _2);
     // CHECK: opaque::<bool>(move [[eqxy]])
@@ -242,21 +237,20 @@ fn comparison(x: u64, y: u64) {
 #[rustc_inherit_overflow_checks]
 fn arithmetic_checked(x: u64) {
     // CHECK-LABEL: fn arithmetic_checked(
-    // CHECK: [[cadd:_.*]] = CheckedAdd(_1, const 0_u64);
-    // CHECK: [[add:_.*]] = move ([[cadd]].0: u64);
-    // CHECK: opaque::<u64>(move [[add]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x + 0);
-    // CHECK: [[csub:_.*]] = CheckedSub(_1, const 0_u64);
-    // CHECK: [[sub:_.*]] = move ([[csub]].0: u64);
-    // CHECK: opaque::<u64>(move [[sub]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x - 0);
-    // CHECK: [[cmul0:_.*]] = CheckedMul(_1, const 0_u64);
-    // CHECK: [[mul0:_.*]] = move ([[cmul0]].0: u64);
-    // CHECK: opaque::<u64>(move [[mul0]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x - x);
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x * 0);
-    // CHECK: [[cmul1:_.*]] = CheckedMul(_1, const 1_u64);
-    // CHECK: [[mul1:_.*]] = move ([[cmul1]].0: u64);
-    // CHECK: opaque::<u64>(move [[mul1]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x * 1);
 }
 
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
index b04728a9b0f..187290785c0 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
@@ -19,7 +19,6 @@
       scope 1 (inlined imm8) {
           debug x => _5;
           let mut _14: u32;
-          let mut _15: u32;
           scope 2 {
               debug out => _4;
           }
@@ -36,14 +35,14 @@
           StorageLive(_5);
           _5 = _1;
           _4 = const 0_u32;
-          StorageLive(_15);
-          StorageLive(_14);
--         _14 = Shr(_5, const 0_i32);
-+         _14 = Shr(_1, const 0_i32);
-          _15 = BitAnd(move _14, const 255_u32);
-          StorageDead(_14);
-          _4 = BitOr(const 0_u32, move _15);
-          StorageDead(_15);
+-         StorageLive(_14);
+-         _14 = BitAnd(_5, const 255_u32);
+-         _4 = BitOr(const 0_u32, move _14);
+-         StorageDead(_14);
++         nop;
++         _14 = BitAnd(_1, const 255_u32);
++         _4 = _14;
++         nop;
           StorageDead(_5);
           StorageLive(_6);
           StorageLive(_7);
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
index fcf99ac6918..99350bac478 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
@@ -19,7 +19,6 @@
       scope 1 (inlined imm8) {
           debug x => _5;
           let mut _14: u32;
-          let mut _15: u32;
           scope 2 {
               debug out => _4;
           }
@@ -36,14 +35,14 @@
           StorageLive(_5);
           _5 = _1;
           _4 = const 0_u32;
-          StorageLive(_15);
-          StorageLive(_14);
--         _14 = Shr(_5, const 0_i32);
-+         _14 = Shr(_1, const 0_i32);
-          _15 = BitAnd(move _14, const 255_u32);
-          StorageDead(_14);
-          _4 = BitOr(const 0_u32, move _15);
-          StorageDead(_15);
+-         StorageLive(_14);
+-         _14 = BitAnd(_5, const 255_u32);
+-         _4 = BitOr(const 0_u32, move _14);
+-         StorageDead(_14);
++         nop;
++         _14 = BitAnd(_1, const 255_u32);
++         _4 = _14;
++         nop;
           StorageDead(_5);
           StorageLive(_6);
           StorageLive(_7);

From 5fc23ad8e6b7a5ef0b5a6936cb043bd85f8bed59 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sat, 25 Mar 2023 22:33:35 +0000
Subject: [PATCH 2/6] Simplify unary operations.

---
 compiler/rustc_mir_transform/src/gvn.rs       |  20 +++
 .../gvn.fn_pointers.GVN.panic-abort.diff      |  18 +--
 .../gvn.fn_pointers.GVN.panic-unwind.diff     |  18 +--
 tests/mir-opt/gvn.rs                          |  27 ++++
 tests/mir-opt/gvn.unary.GVN.panic-abort.diff  | 153 ++++++++++++++++++
 tests/mir-opt/gvn.unary.GVN.panic-unwind.diff | 153 ++++++++++++++++++
 6 files changed, 371 insertions(+), 18 deletions(-)
 create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-abort.diff
 create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-unwind.diff

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 3052369c3ca..699b218d46d 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -817,6 +817,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
+                if let Some(value) = self.simplify_unary(op, arg) {
+                    return Some(value);
+                }
                 Value::UnaryOp(op, arg)
             }
             Rvalue::Discriminant(ref mut place) => {
@@ -916,6 +919,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
     }
 
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> {
+        let value = match (op, self.get(value)) {
+            (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner),
+            (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner),
+            (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Ne, *lhs, *rhs)
+            }
+            (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
+            }
+            _ => return None,
+        };
+
+        Some(self.insert(value))
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn simplify_binary(
         &mut self,
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 0901896af53..02bf95840da 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21};
+      let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21};
+      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:585:19: 585:21};
+              let _7: {closure@$DIR/gvn.rs:610:19: 610:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:585:19: 585:21};
+-         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index 4b95191ba82..c5dcc8a8ec9 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21};
+      let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21};
+      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:585:19: 585:21};
+              let _7: {closure@$DIR/gvn.rs:610:19: 610:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:585:19: 585:21};
+-         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 8c06e3a6385..f8f4fdcd732 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -166,6 +166,31 @@ fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
     opaque(a[idx]);
 }
 
+fn unary(x: i64) {
+    // CHECK-LABEL: fn unary(
+    // CHECK: opaque::<i64>(_1)
+    opaque(--x); // This is `x`.
+
+    // CHECK: [[b:_.*]] = Lt(_1, const 13_i64);
+    // CHECK: opaque::<bool>([[b]])
+    let b = x < 13;
+    opaque(!!b); // This is `b`.
+
+    // Both lines should test the same thing.
+    // CHECK: [[c:_.*]] = Ne(_1, const 15_i64);
+    // CHECK: opaque::<bool>([[c]])
+    // CHECK: opaque::<bool>([[c]])
+    opaque(x != 15);
+    opaque(!(x == 15));
+
+    // Both lines should test the same thing.
+    // CHECK: [[d:_.*]] = Eq(_1, const 35_i64);
+    // CHECK: opaque::<bool>([[d]])
+    // CHECK: opaque::<bool>([[d]])
+    opaque(x == 35);
+    opaque(!(x != 35));
+}
+
 /// Verify symbolic integer arithmetic simplifications.
 fn arithmetic(x: u64) {
     // CHECK-LABEL: fn arithmetic(
@@ -623,6 +648,7 @@ fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
     repeated_index::<u32, 7>(5, 3);
+    unary(i64::MIN);
     arithmetic(5);
     comparison(5, 6);
     arithmetic_checked(5);
@@ -651,6 +677,7 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.subexpression_elimination.GVN.diff
 // EMIT_MIR gvn.wrap_unwrap.GVN.diff
 // EMIT_MIR gvn.repeated_index.GVN.diff
+// EMIT_MIR gvn.unary.GVN.diff
 // EMIT_MIR gvn.arithmetic.GVN.diff
 // EMIT_MIR gvn.comparison.GVN.diff
 // EMIT_MIR gvn.arithmetic_checked.GVN.diff
diff --git a/tests/mir-opt/gvn.unary.GVN.panic-abort.diff b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff
new file mode 100644
index 00000000000..9469032f294
--- /dev/null
+++ b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff
@@ -0,0 +1,153 @@
+- // MIR for `unary` before GVN
++ // MIR for `unary` after GVN
+  
+  fn unary(_1: i64) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: i64;
+      let mut _4: i64;
+      let mut _5: i64;
+      let _6: bool;
+      let mut _7: i64;
+      let _8: ();
+      let mut _9: bool;
+      let mut _10: bool;
+      let mut _11: bool;
+      let _12: ();
+      let mut _13: bool;
+      let mut _14: i64;
+      let _15: ();
+      let mut _16: bool;
+      let mut _17: bool;
+      let mut _18: i64;
+      let _19: ();
+      let mut _20: bool;
+      let mut _21: i64;
+      let _22: ();
+      let mut _23: bool;
+      let mut _24: bool;
+      let mut _25: i64;
+      scope 1 {
+          debug b => _6;
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = Neg(move _5);
++         _4 = Neg(_1);
+          StorageDead(_5);
+-         _3 = Neg(move _4);
++         _3 = _1;
+          StorageDead(_4);
+-         _2 = opaque::<i64>(move _3) -> [return: bb1, unwind unreachable];
++         _2 = opaque::<i64>(_1) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          StorageDead(_2);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _1;
+-         _6 = Lt(move _7, const 13_i64);
++         _6 = Lt(_1, const 13_i64);
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = _6;
+-         _10 = Not(move _11);
++         _10 = Not(_6);
+          StorageDead(_11);
+-         _9 = Not(move _10);
++         _9 = _6;
+          StorageDead(_10);
+-         _8 = opaque::<bool>(move _9) -> [return: bb2, unwind unreachable];
++         _8 = opaque::<bool>(_6) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_12);
+-         StorageLive(_13);
++         nop;
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Ne(move _14, const 15_i64);
++         _13 = Ne(_1, const 15_i64);
+          StorageDead(_14);
+-         _12 = opaque::<bool>(move _13) -> [return: bb3, unwind unreachable];
++         _12 = opaque::<bool>(_13) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+-         StorageDead(_13);
++         nop;
+          StorageDead(_12);
+          StorageLive(_15);
+          StorageLive(_16);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+-         _17 = Eq(move _18, const 15_i64);
++         _17 = Eq(_1, const 15_i64);
+          StorageDead(_18);
+-         _16 = Not(move _17);
++         _16 = _13;
+          StorageDead(_17);
+-         _15 = opaque::<bool>(move _16) -> [return: bb4, unwind unreachable];
++         _15 = opaque::<bool>(_13) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_16);
+          StorageDead(_15);
+          StorageLive(_19);
+-         StorageLive(_20);
++         nop;
+          StorageLive(_21);
+          _21 = _1;
+-         _20 = Eq(move _21, const 35_i64);
++         _20 = Eq(_1, const 35_i64);
+          StorageDead(_21);
+-         _19 = opaque::<bool>(move _20) -> [return: bb5, unwind unreachable];
++         _19 = opaque::<bool>(_20) -> [return: bb5, unwind unreachable];
+      }
+  
+      bb5: {
+-         StorageDead(_20);
++         nop;
+          StorageDead(_19);
+          StorageLive(_22);
+          StorageLive(_23);
+          StorageLive(_24);
+          StorageLive(_25);
+          _25 = _1;
+-         _24 = Ne(move _25, const 35_i64);
++         _24 = Ne(_1, const 35_i64);
+          StorageDead(_25);
+-         _23 = Not(move _24);
++         _23 = _20;
+          StorageDead(_24);
+-         _22 = opaque::<bool>(move _23) -> [return: bb6, unwind unreachable];
++         _22 = opaque::<bool>(_20) -> [return: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+-         StorageDead(_6);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..e672f6fb6ba
--- /dev/null
+++ b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff
@@ -0,0 +1,153 @@
+- // MIR for `unary` before GVN
++ // MIR for `unary` after GVN
+  
+  fn unary(_1: i64) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: i64;
+      let mut _4: i64;
+      let mut _5: i64;
+      let _6: bool;
+      let mut _7: i64;
+      let _8: ();
+      let mut _9: bool;
+      let mut _10: bool;
+      let mut _11: bool;
+      let _12: ();
+      let mut _13: bool;
+      let mut _14: i64;
+      let _15: ();
+      let mut _16: bool;
+      let mut _17: bool;
+      let mut _18: i64;
+      let _19: ();
+      let mut _20: bool;
+      let mut _21: i64;
+      let _22: ();
+      let mut _23: bool;
+      let mut _24: bool;
+      let mut _25: i64;
+      scope 1 {
+          debug b => _6;
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = Neg(move _5);
++         _4 = Neg(_1);
+          StorageDead(_5);
+-         _3 = Neg(move _4);
++         _3 = _1;
+          StorageDead(_4);
+-         _2 = opaque::<i64>(move _3) -> [return: bb1, unwind continue];
++         _2 = opaque::<i64>(_1) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          StorageDead(_2);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _1;
+-         _6 = Lt(move _7, const 13_i64);
++         _6 = Lt(_1, const 13_i64);
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = _6;
+-         _10 = Not(move _11);
++         _10 = Not(_6);
+          StorageDead(_11);
+-         _9 = Not(move _10);
++         _9 = _6;
+          StorageDead(_10);
+-         _8 = opaque::<bool>(move _9) -> [return: bb2, unwind continue];
++         _8 = opaque::<bool>(_6) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_12);
+-         StorageLive(_13);
++         nop;
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Ne(move _14, const 15_i64);
++         _13 = Ne(_1, const 15_i64);
+          StorageDead(_14);
+-         _12 = opaque::<bool>(move _13) -> [return: bb3, unwind continue];
++         _12 = opaque::<bool>(_13) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+-         StorageDead(_13);
++         nop;
+          StorageDead(_12);
+          StorageLive(_15);
+          StorageLive(_16);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+-         _17 = Eq(move _18, const 15_i64);
++         _17 = Eq(_1, const 15_i64);
+          StorageDead(_18);
+-         _16 = Not(move _17);
++         _16 = _13;
+          StorageDead(_17);
+-         _15 = opaque::<bool>(move _16) -> [return: bb4, unwind continue];
++         _15 = opaque::<bool>(_13) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_16);
+          StorageDead(_15);
+          StorageLive(_19);
+-         StorageLive(_20);
++         nop;
+          StorageLive(_21);
+          _21 = _1;
+-         _20 = Eq(move _21, const 35_i64);
++         _20 = Eq(_1, const 35_i64);
+          StorageDead(_21);
+-         _19 = opaque::<bool>(move _20) -> [return: bb5, unwind continue];
++         _19 = opaque::<bool>(_20) -> [return: bb5, unwind continue];
+      }
+  
+      bb5: {
+-         StorageDead(_20);
++         nop;
+          StorageDead(_19);
+          StorageLive(_22);
+          StorageLive(_23);
+          StorageLive(_24);
+          StorageLive(_25);
+          _25 = _1;
+-         _24 = Ne(move _25, const 35_i64);
++         _24 = Ne(_1, const 35_i64);
+          StorageDead(_25);
+-         _23 = Not(move _24);
++         _23 = _20;
+          StorageDead(_24);
+-         _22 = opaque::<bool>(move _23) -> [return: bb6, unwind continue];
++         _22 = opaque::<bool>(_20) -> [return: bb6, unwind continue];
+      }
+  
+      bb6: {
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+-         StorageDead(_6);
++         nop;
+          return;
+      }
+  }
+  

From 3c48243b6fd28aeb27c856f8d23433e9f3ebaa0d Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Mon, 20 Mar 2023 20:15:59 +0000
Subject: [PATCH 3/6] Simplify Len.

---
 compiler/rustc_mir_transform/src/gvn.rs       | 38 +++++++++++++++++--
 ...rray_index.main.GVN.32bit.panic-abort.diff |  7 ++--
 ...ray_index.main.GVN.32bit.panic-unwind.diff |  7 ++--
 ...rray_index.main.GVN.64bit.panic-abort.diff |  7 ++--
 ...ray_index.main.GVN.64bit.panic-unwind.diff |  7 ++--
 ...rray_index.main.GVN.32bit.panic-abort.diff |  7 ++--
 ...ray_index.main.GVN.32bit.panic-unwind.diff |  7 ++--
 ...rray_index.main.GVN.64bit.panic-abort.diff |  7 ++--
 ...ray_index.main.GVN.64bit.panic-unwind.diff |  7 ++--
 .../repeat.main.GVN.32bit.panic-abort.diff    |  7 ++--
 .../repeat.main.GVN.32bit.panic-unwind.diff   |  7 ++--
 .../repeat.main.GVN.64bit.panic-abort.diff    |  7 ++--
 .../repeat.main.GVN.64bit.panic-unwind.diff   |  7 ++--
 .../gvn.repeated_index.GVN.panic-abort.diff   | 13 ++++---
 .../gvn.repeated_index.GVN.panic-unwind.diff  | 13 ++++---
 15 files changed, 96 insertions(+), 52 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 699b218d46d..afc75ff1313 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -776,10 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
 
             // Operations.
-            Rvalue::Len(ref mut place) => {
-                let place = self.simplify_place_value(place, location)?;
-                Value::Len(place)
-            }
+            Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
             Rvalue::Cast(kind, ref mut value, to) => {
                 let from = value.ty(self.local_decls, self.tcx);
                 let value = self.simplify_operand(value, location)?;
@@ -1021,6 +1018,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             Some(result)
         }
     }
+
+    fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
+        // Trivial case: we are fetching a statically known length.
+        let place_ty = place.ty(self.local_decls, self.tcx).ty;
+        if let ty::Array(_, len) = place_ty.kind() {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        let mut inner = self.simplify_place_value(place, location)?;
+
+        // The length information is stored in the fat pointer.
+        // Reborrowing copies length information from one pointer to the other.
+        while let Value::Address { place: borrowed, .. } = self.get(inner)
+            && let [PlaceElem::Deref] = borrowed.projection[..]
+            && let Some(borrowed) = self.locals[borrowed.local]
+        {
+            inner = borrowed;
+        }
+
+        // We have an unsizing cast, which assigns the length to fat pointer metadata.
+        if let Value::Cast { kind, from, to, .. } = self.get(inner)
+            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
+            && let Some(from) = from.builtin_deref(true)
+            && let ty::Array(_, len) = from.ty.kind()
+            && let Some(to) = to.builtin_deref(true)
+            && let ty::Slice(..) = to.ty.kind()
+        {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        // Fallback: a symbolic `Len`.
+        Some(self.insert(Value::Len(inner)))
+    }
 }
 
 fn op_to_prop_const<'tcx>(
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
index f9537661e8c..6d00dd5b212 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
index 07886779fea..7e2f72ab31b 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
index f9537661e8c..6d00dd5b212 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
index 07886779fea..7e2f72ab31b 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
index cf36109fdcb..bd987c01ab1 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
index 40ed9697180..e9ebef84ae0 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
index cf36109fdcb..bd987c01ab1 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
index 40ed9697180..e9ebef84ae0 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
index a52e6e35483..71635b8e9c3 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
index fe0acee71eb..84205028d6d 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
index a52e6e35483..71635b8e9c3 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
index fe0acee71eb..84205028d6d 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
index d937902e891..8ce05c9b340 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
@@ -32,11 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
-          _8 = Len(_3);
+-         _8 = Len(_3);
 -         _9 = Lt(_7, _8);
 -         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind unreachable];
-+         _9 = Lt(const 0_usize, _8);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind unreachable];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -57,9 +58,9 @@
 -         _13 = Len(_3);
 -         _14 = Lt(_12, _13);
 -         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind unreachable];
-+         _13 = _8;
-+         _14 = Lt(_2, _8);
-+         assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind unreachable];
++         _13 = const N;
++         _14 = Lt(_2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
index dd4d24b12ea..7ed547eeb4a 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
@@ -32,11 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
-          _8 = Len(_3);
+-         _8 = Len(_3);
 -         _9 = Lt(_7, _8);
 -         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind continue];
-+         _9 = Lt(const 0_usize, _8);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind continue];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -57,9 +58,9 @@
 -         _13 = Len(_3);
 -         _14 = Lt(_12, _13);
 -         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind continue];
-+         _13 = _8;
-+         _14 = Lt(_2, _8);
-+         assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind continue];
++         _13 = const N;
++         _14 = Lt(_2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind continue];
       }
   
       bb3: {

From 22ed51e136c8ad3a07d181b90e7610501ea69816 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Tue, 31 Oct 2023 19:29:08 +0000
Subject: [PATCH 4/6] Do not read a scalar on a non-scalar layout.

---
 compiler/rustc_mir_transform/src/gvn.rs       |   9 +-
 tests/mir-opt/gvn.rs                          |  23 ++
 .../gvn.wide_ptr_ops.GVN.panic-abort.diff     | 386 ++++++++++++++++++
 .../gvn.wide_ptr_ops.GVN.panic-unwind.diff    | 386 ++++++++++++++++++
 4 files changed, 802 insertions(+), 2 deletions(-)
 create mode 100644 tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
 create mode 100644 tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index afc75ff1313..fc14ea2696f 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -953,8 +953,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let as_bits = |value| {
             let constant = self.evaluated[value].as_ref()?;
-            let scalar = self.ecx.read_scalar(constant).ok()?;
-            scalar.to_bits(constant.layout.size).ok()
+            if layout.abi.is_scalar() {
+                let scalar = self.ecx.read_scalar(constant).ok()?;
+                scalar.to_bits(constant.layout.size).ok()
+            } else {
+                // `constant` is a wide pointer. Do not evaluate to bits.
+                None
+            }
         };
 
         // Represent the values as `Ok(bits)` or `Err(VnIndex)`.
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index f8f4fdcd732..31ea237cbec 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -644,6 +644,27 @@ fn constant_index_overflow<T: Copy>(x: &[T]) {
     opaque(b)
 }
 
+fn wide_ptr_ops() {
+    let a: *const dyn Send = &1 as &dyn Send;
+    let b: *const dyn Send = &1 as &dyn Send;
+    let _val = a == b;
+    let _val = a != b;
+    let _val = a < b;
+    let _val = a <= b;
+    let _val = a > b;
+    let _val = a >= b;
+
+    let a: *const [u8] = unsafe { transmute((1usize, 1usize)) };
+    let b: *const [u8] = unsafe { transmute((1usize, 2usize)) };
+
+    opaque(!(a == b));
+    opaque(a != b);
+    opaque(a <= b);
+    opaque(a < b);
+    opaque(!(a >= b));
+    opaque(!(a > b));
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
@@ -664,6 +685,7 @@ fn main() {
     fn_pointers();
     indirect_static();
     constant_index_overflow(&[5, 3]);
+    wide_ptr_ops();
 }
 
 #[inline(never)]
@@ -692,3 +714,4 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.fn_pointers.GVN.diff
 // EMIT_MIR gvn.indirect_static.GVN.diff
 // EMIT_MIR gvn.constant_index_overflow.GVN.diff
+// EMIT_MIR gvn.wide_ptr_ops.GVN.diff
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
new file mode 100644
index 00000000000..e49d759b8fc
--- /dev/null
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
@@ -0,0 +1,386 @@
+- // MIR for `wide_ptr_ops` before GVN
++ // MIR for `wide_ptr_ops` after GVN
+  
+  fn wide_ptr_ops() -> () {
+      let mut _0: ();
+      let _1: *const dyn std::marker::Send;
+      let mut _2: *const dyn std::marker::Send;
+      let _3: &dyn std::marker::Send;
+      let mut _4: &i32;
+      let _5: &i32;
+      let _6: i32;
+      let mut _8: *const dyn std::marker::Send;
+      let _9: &dyn std::marker::Send;
+      let mut _10: &i32;
+      let _11: &i32;
+      let _12: i32;
+      let mut _14: *const dyn std::marker::Send;
+      let mut _15: *const dyn std::marker::Send;
+      let mut _16: *const dyn std::marker::Send;
+      let mut _18: *const dyn std::marker::Send;
+      let mut _19: *const dyn std::marker::Send;
+      let mut _20: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let mut _24: *const dyn std::marker::Send;
+      let mut _26: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let mut _30: *const dyn std::marker::Send;
+      let mut _31: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _34: *const dyn std::marker::Send;
+      let mut _35: *const dyn std::marker::Send;
+      let mut _36: *const dyn std::marker::Send;
+      let mut _38: (usize, usize);
+      let mut _40: (usize, usize);
+      let _41: ();
+      let mut _42: bool;
+      let mut _43: bool;
+      let mut _44: *const [u8];
+      let mut _45: *const [u8];
+      let _46: ();
+      let mut _47: bool;
+      let mut _48: *const [u8];
+      let mut _49: *const [u8];
+      let _50: ();
+      let mut _51: bool;
+      let mut _52: *const [u8];
+      let mut _53: *const [u8];
+      let _54: ();
+      let mut _55: bool;
+      let mut _56: *const [u8];
+      let mut _57: *const [u8];
+      let _58: ();
+      let mut _59: bool;
+      let mut _60: bool;
+      let mut _61: *const [u8];
+      let mut _62: *const [u8];
+      let _63: ();
+      let mut _64: bool;
+      let mut _65: bool;
+      let mut _66: *const [u8];
+      let mut _67: *const [u8];
+      let mut _69: &i32;
+      scope 1 {
+          debug a => _1;
+          let _7: *const dyn std::marker::Send;
+          let mut _68: &i32;
+          scope 2 {
+              debug b => _7;
+              let _13: bool;
+              scope 3 {
+                  debug _val => _13;
+                  let _17: bool;
+                  scope 4 {
+                      debug _val => _17;
+                      let _21: bool;
+                      scope 5 {
+                          debug _val => _21;
+                          let _25: bool;
+                          scope 6 {
+                              debug _val => _25;
+                              let _29: bool;
+                              scope 7 {
+                                  debug _val => _29;
+                                  let _33: bool;
+                                  scope 8 {
+                                      debug _val => _33;
+                                      let _37: *const [u8];
+                                      scope 9 {
+                                          debug a => _37;
+                                          let _39: *const [u8];
+                                          scope 11 {
+                                              debug b => _39;
+                                          }
+                                          scope 12 {
+                                          }
+                                      }
+                                      scope 10 {
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);
++         nop;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _69 = const _;
+          _5 = &(*_69);
+          _4 = &(*_5);
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_4);
+          _2 = &raw const (*_3);
+          _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_2);
+          StorageDead(_5);
+          StorageDead(_3);
+-         StorageLive(_7);
++         nop;
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _68 = const _;
+          _11 = &(*_68);
+          _10 = &(*_11);
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_10);
+          _8 = &raw const (*_9);
+          _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_8);
+          StorageDead(_11);
+          StorageDead(_9);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = _1;
+-         StorageLive(_15);
++         nop;
+          StorageLive(_16);
+          _16 = _7;
+-         _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_16);
+-         _13 = Eq(move _14, move _15);
+-         StorageDead(_15);
++         _13 = Eq(_1, _15);
++         nop;
+          StorageDead(_14);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+          StorageLive(_19);
+          StorageLive(_20);
+          _20 = _7;
+-         _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _19 = _15;
+          StorageDead(_20);
+-         _17 = Ne(move _18, move _19);
++         _17 = Ne(_1, _15);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageLive(_21);
+          StorageLive(_22);
+          _22 = _1;
+          StorageLive(_23);
+          StorageLive(_24);
+          _24 = _7;
+-         _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _23 = _15;
+          StorageDead(_24);
+-         _21 = Lt(move _22, move _23);
++         _21 = Lt(_1, _15);
+          StorageDead(_23);
+          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          StorageLive(_28);
+          _28 = _7;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _27 = _15;
+          StorageDead(_28);
+-         _25 = Le(move _26, move _27);
++         _25 = Le(_1, _15);
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_29);
+          StorageLive(_30);
+          _30 = _1;
+          StorageLive(_31);
+          StorageLive(_32);
+          _32 = _7;
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _31 = _15;
+          StorageDead(_32);
+-         _29 = Gt(move _30, move _31);
++         _29 = Gt(_1, _15);
+          StorageDead(_31);
+          StorageDead(_30);
+          StorageLive(_33);
+          StorageLive(_34);
+          _34 = _1;
+          StorageLive(_35);
+          StorageLive(_36);
+          _36 = _7;
+-         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _35 = _15;
+          StorageDead(_36);
+-         _33 = Ge(move _34, move _35);
++         _33 = Ge(_1, _15);
+          StorageDead(_35);
+          StorageDead(_34);
+-         StorageLive(_37);
++         nop;
+          StorageLive(_38);
+-         _38 = (const 1_usize, const 1_usize);
+-         _37 = move _38 as *const [u8] (Transmute);
++         _38 = const (1_usize, 1_usize);
++         _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_38);
+-         StorageLive(_39);
++         nop;
+          StorageLive(_40);
+-         _40 = (const 1_usize, const 2_usize);
+-         _39 = move _40 as *const [u8] (Transmute);
++         _40 = const (1_usize, 2_usize);
++         _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_40);
+          StorageLive(_41);
+-         StorageLive(_42);
++         nop;
+          StorageLive(_43);
+          StorageLive(_44);
+-         _44 = _37;
++         _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_45);
+-         _45 = _39;
+-         _43 = Eq(move _44, move _45);
++         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_45);
+          StorageDead(_44);
+          _42 = Not(move _43);
+          StorageDead(_43);
+-         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind unreachable];
++         _41 = opaque::<bool>(_42) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         StorageDead(_42);
++         nop;
+          StorageDead(_41);
+          StorageLive(_46);
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = _37;
++         _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_49);
+-         _49 = _39;
+-         _47 = Ne(move _48, move _49);
++         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _47 = _42;
+          StorageDead(_49);
+          StorageDead(_48);
+-         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind unreachable];
++         _46 = opaque::<bool>(_42) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_47);
+          StorageDead(_46);
+          StorageLive(_50);
+          StorageLive(_51);
+          StorageLive(_52);
+-         _52 = _37;
++         _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_53);
+-         _53 = _39;
+-         _51 = Le(move _52, move _53);
++         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_53);
+          StorageDead(_52);
+          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_51);
+          StorageDead(_50);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+-         _56 = _37;
++         _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_57);
+-         _57 = _39;
+-         _55 = Lt(move _56, move _57);
++         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_57);
+          StorageDead(_56);
+          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_55);
+          StorageDead(_54);
+          StorageLive(_58);
+          StorageLive(_59);
+          StorageLive(_60);
+          StorageLive(_61);
+-         _61 = _37;
++         _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_62);
+-         _62 = _39;
+-         _60 = Ge(move _61, move _62);
++         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_62);
+          StorageDead(_61);
+          _59 = Not(move _60);
+          StorageDead(_60);
+          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
+      }
+  
+      bb5: {
+          StorageDead(_59);
+          StorageDead(_58);
+          StorageLive(_63);
+          StorageLive(_64);
+          StorageLive(_65);
+          StorageLive(_66);
+-         _66 = _37;
++         _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_67);
+-         _67 = _39;
+-         _65 = Gt(move _66, move _67);
++         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_67);
+          StorageDead(_66);
+          _64 = Not(move _65);
+          StorageDead(_65);
+          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+          StorageDead(_64);
+          StorageDead(_63);
+          _0 = const ();
+-         StorageDead(_39);
+-         StorageDead(_37);
++         nop;
++         nop;
+          StorageDead(_33);
+          StorageDead(_29);
+          StorageDead(_25);
+          StorageDead(_21);
+          StorageDead(_17);
+          StorageDead(_13);
+-         StorageDead(_7);
+-         StorageDead(_1);
++         nop;
++         nop;
+          return;
+      }
++ }
++ 
++ ALLOC1 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+  }
+  
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..4e5608a4425
--- /dev/null
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
@@ -0,0 +1,386 @@
+- // MIR for `wide_ptr_ops` before GVN
++ // MIR for `wide_ptr_ops` after GVN
+  
+  fn wide_ptr_ops() -> () {
+      let mut _0: ();
+      let _1: *const dyn std::marker::Send;
+      let mut _2: *const dyn std::marker::Send;
+      let _3: &dyn std::marker::Send;
+      let mut _4: &i32;
+      let _5: &i32;
+      let _6: i32;
+      let mut _8: *const dyn std::marker::Send;
+      let _9: &dyn std::marker::Send;
+      let mut _10: &i32;
+      let _11: &i32;
+      let _12: i32;
+      let mut _14: *const dyn std::marker::Send;
+      let mut _15: *const dyn std::marker::Send;
+      let mut _16: *const dyn std::marker::Send;
+      let mut _18: *const dyn std::marker::Send;
+      let mut _19: *const dyn std::marker::Send;
+      let mut _20: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let mut _24: *const dyn std::marker::Send;
+      let mut _26: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let mut _30: *const dyn std::marker::Send;
+      let mut _31: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _34: *const dyn std::marker::Send;
+      let mut _35: *const dyn std::marker::Send;
+      let mut _36: *const dyn std::marker::Send;
+      let mut _38: (usize, usize);
+      let mut _40: (usize, usize);
+      let _41: ();
+      let mut _42: bool;
+      let mut _43: bool;
+      let mut _44: *const [u8];
+      let mut _45: *const [u8];
+      let _46: ();
+      let mut _47: bool;
+      let mut _48: *const [u8];
+      let mut _49: *const [u8];
+      let _50: ();
+      let mut _51: bool;
+      let mut _52: *const [u8];
+      let mut _53: *const [u8];
+      let _54: ();
+      let mut _55: bool;
+      let mut _56: *const [u8];
+      let mut _57: *const [u8];
+      let _58: ();
+      let mut _59: bool;
+      let mut _60: bool;
+      let mut _61: *const [u8];
+      let mut _62: *const [u8];
+      let _63: ();
+      let mut _64: bool;
+      let mut _65: bool;
+      let mut _66: *const [u8];
+      let mut _67: *const [u8];
+      let mut _69: &i32;
+      scope 1 {
+          debug a => _1;
+          let _7: *const dyn std::marker::Send;
+          let mut _68: &i32;
+          scope 2 {
+              debug b => _7;
+              let _13: bool;
+              scope 3 {
+                  debug _val => _13;
+                  let _17: bool;
+                  scope 4 {
+                      debug _val => _17;
+                      let _21: bool;
+                      scope 5 {
+                          debug _val => _21;
+                          let _25: bool;
+                          scope 6 {
+                              debug _val => _25;
+                              let _29: bool;
+                              scope 7 {
+                                  debug _val => _29;
+                                  let _33: bool;
+                                  scope 8 {
+                                      debug _val => _33;
+                                      let _37: *const [u8];
+                                      scope 9 {
+                                          debug a => _37;
+                                          let _39: *const [u8];
+                                          scope 11 {
+                                              debug b => _39;
+                                          }
+                                          scope 12 {
+                                          }
+                                      }
+                                      scope 10 {
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);
++         nop;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _69 = const _;
+          _5 = &(*_69);
+          _4 = &(*_5);
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_4);
+          _2 = &raw const (*_3);
+          _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_2);
+          StorageDead(_5);
+          StorageDead(_3);
+-         StorageLive(_7);
++         nop;
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _68 = const _;
+          _11 = &(*_68);
+          _10 = &(*_11);
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_10);
+          _8 = &raw const (*_9);
+          _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_8);
+          StorageDead(_11);
+          StorageDead(_9);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = _1;
+-         StorageLive(_15);
++         nop;
+          StorageLive(_16);
+          _16 = _7;
+-         _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_16);
+-         _13 = Eq(move _14, move _15);
+-         StorageDead(_15);
++         _13 = Eq(_1, _15);
++         nop;
+          StorageDead(_14);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+          StorageLive(_19);
+          StorageLive(_20);
+          _20 = _7;
+-         _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _19 = _15;
+          StorageDead(_20);
+-         _17 = Ne(move _18, move _19);
++         _17 = Ne(_1, _15);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageLive(_21);
+          StorageLive(_22);
+          _22 = _1;
+          StorageLive(_23);
+          StorageLive(_24);
+          _24 = _7;
+-         _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _23 = _15;
+          StorageDead(_24);
+-         _21 = Lt(move _22, move _23);
++         _21 = Lt(_1, _15);
+          StorageDead(_23);
+          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          StorageLive(_28);
+          _28 = _7;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _27 = _15;
+          StorageDead(_28);
+-         _25 = Le(move _26, move _27);
++         _25 = Le(_1, _15);
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_29);
+          StorageLive(_30);
+          _30 = _1;
+          StorageLive(_31);
+          StorageLive(_32);
+          _32 = _7;
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _31 = _15;
+          StorageDead(_32);
+-         _29 = Gt(move _30, move _31);
++         _29 = Gt(_1, _15);
+          StorageDead(_31);
+          StorageDead(_30);
+          StorageLive(_33);
+          StorageLive(_34);
+          _34 = _1;
+          StorageLive(_35);
+          StorageLive(_36);
+          _36 = _7;
+-         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _35 = _15;
+          StorageDead(_36);
+-         _33 = Ge(move _34, move _35);
++         _33 = Ge(_1, _15);
+          StorageDead(_35);
+          StorageDead(_34);
+-         StorageLive(_37);
++         nop;
+          StorageLive(_38);
+-         _38 = (const 1_usize, const 1_usize);
+-         _37 = move _38 as *const [u8] (Transmute);
++         _38 = const (1_usize, 1_usize);
++         _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_38);
+-         StorageLive(_39);
++         nop;
+          StorageLive(_40);
+-         _40 = (const 1_usize, const 2_usize);
+-         _39 = move _40 as *const [u8] (Transmute);
++         _40 = const (1_usize, 2_usize);
++         _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_40);
+          StorageLive(_41);
+-         StorageLive(_42);
++         nop;
+          StorageLive(_43);
+          StorageLive(_44);
+-         _44 = _37;
++         _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_45);
+-         _45 = _39;
+-         _43 = Eq(move _44, move _45);
++         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_45);
+          StorageDead(_44);
+          _42 = Not(move _43);
+          StorageDead(_43);
+-         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind continue];
++         _41 = opaque::<bool>(_42) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         StorageDead(_42);
++         nop;
+          StorageDead(_41);
+          StorageLive(_46);
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = _37;
++         _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_49);
+-         _49 = _39;
+-         _47 = Ne(move _48, move _49);
++         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _47 = _42;
+          StorageDead(_49);
+          StorageDead(_48);
+-         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind continue];
++         _46 = opaque::<bool>(_42) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_47);
+          StorageDead(_46);
+          StorageLive(_50);
+          StorageLive(_51);
+          StorageLive(_52);
+-         _52 = _37;
++         _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_53);
+-         _53 = _39;
+-         _51 = Le(move _52, move _53);
++         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_53);
+          StorageDead(_52);
+          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_51);
+          StorageDead(_50);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+-         _56 = _37;
++         _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_57);
+-         _57 = _39;
+-         _55 = Lt(move _56, move _57);
++         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_57);
+          StorageDead(_56);
+          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_55);
+          StorageDead(_54);
+          StorageLive(_58);
+          StorageLive(_59);
+          StorageLive(_60);
+          StorageLive(_61);
+-         _61 = _37;
++         _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_62);
+-         _62 = _39;
+-         _60 = Ge(move _61, move _62);
++         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_62);
+          StorageDead(_61);
+          _59 = Not(move _60);
+          StorageDead(_60);
+          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
+      }
+  
+      bb5: {
+          StorageDead(_59);
+          StorageDead(_58);
+          StorageLive(_63);
+          StorageLive(_64);
+          StorageLive(_65);
+          StorageLive(_66);
+-         _66 = _37;
++         _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_67);
+-         _67 = _39;
+-         _65 = Gt(move _66, move _67);
++         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_67);
+          StorageDead(_66);
+          _64 = Not(move _65);
+          StorageDead(_65);
+          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
+      }
+  
+      bb6: {
+          StorageDead(_64);
+          StorageDead(_63);
+          _0 = const ();
+-         StorageDead(_39);
+-         StorageDead(_37);
++         nop;
++         nop;
+          StorageDead(_33);
+          StorageDead(_29);
+          StorageDead(_25);
+          StorageDead(_21);
+          StorageDead(_17);
+          StorageDead(_13);
+-         StorageDead(_7);
+-         StorageDead(_1);
++         nop;
++         nop;
+          return;
+      }
++ }
++ 
++ ALLOC1 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+  }
+  

From 166fe54eba4b691b9c69b2a3a24e5b82bd9848e3 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Mon, 8 Jan 2024 22:44:38 +0000
Subject: [PATCH 5/6] Explain side-effects from simplify_operand.

---
 compiler/rustc_mir_transform/src/gvn.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index fc14ea2696f..7a8e3b87b9b 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -794,6 +794,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
                 let lhs = lhs?;
                 let rhs = rhs?;
                 if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
@@ -805,6 +807,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
                 let lhs = lhs?;
                 let rhs = rhs?;
                 if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {

From 0cc2102c4a615fa8f259de491675d9e64606b022 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Mon, 8 Jan 2024 22:54:05 +0000
Subject: [PATCH 6/6] Expand match over binops.

---
 compiler/rustc_mir_transform/src/gvn.rs | 33 ++++++++++++++-----------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 7a8e3b87b9b..390ec3e1a36 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -966,12 +966,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         };
 
-        // Represent the values as `Ok(bits)` or `Err(VnIndex)`.
-        let a = as_bits(lhs).ok_or(lhs);
-        let b = as_bits(rhs).ok_or(rhs);
+        // Represent the values as `Left(bits)` or `Right(VnIndex)`.
+        use Either::{Left, Right};
+        let a = as_bits(lhs).map_or(Right(lhs), Left);
+        let b = as_bits(rhs).map_or(Right(rhs), Left);
         let result = match (op, a, b) {
             // Neutral elements.
-            (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Ok(0), Err(p))
+            (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p))
             | (
                 BinOp::Add
                 | BinOp::BitOr
@@ -980,28 +981,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 | BinOp::Offset
                 | BinOp::Shl
                 | BinOp::Shr,
-                Err(p),
-                Ok(0),
+                Right(p),
+                Left(0),
             )
-            | (BinOp::Mul, Ok(1), Err(p))
-            | (BinOp::Mul | BinOp::Div, Err(p), Ok(1)) => p,
+            | (BinOp::Mul, Left(1), Right(p))
+            | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p,
             // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
-            (BinOp::BitAnd, Err(p), Ok(ones)) | (BinOp::BitAnd, Ok(ones), Err(p))
+            (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
                 if ones == layout.size.truncate(u128::MAX)
                     || (layout.ty.is_bool() && ones == 1) =>
             {
                 p
             }
             // Absorbing elements.
-            (BinOp::Mul | BinOp::BitAnd, _, Ok(0))
-            | (BinOp::Rem, _, Ok(1))
+            (BinOp::Mul | BinOp::BitAnd, _, Left(0))
+            | (BinOp::Rem, _, Left(1))
             | (
                 BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr,
-                Ok(0),
+                Left(0),
                 _,
             ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
             // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
-            (BinOp::BitOr, _, Ok(ones)) | (BinOp::BitOr, Ok(ones), _)
+            (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _)
                 if ones == layout.size.truncate(u128::MAX)
                     || (layout.ty.is_bool() && ones == 1) =>
             {
@@ -1015,8 +1016,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             // - if both operands can be computed as bits, just compare the bits;
             // - if we proved that both operands have the same value, we can insert true/false;
             // - otherwise, do nothing, as we do not try to prove inequality.
-            (BinOp::Eq, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a == b),
-            (BinOp::Ne, a, b) if (a.is_ok() && b.is_ok()) || a == b => self.insert_bool(a != b),
+            (BinOp::Eq, Left(a), Left(b)) => self.insert_bool(a == b),
+            (BinOp::Eq, a, b) if a == b => self.insert_bool(true),
+            (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b),
+            (BinOp::Ne, a, b) if a == b => self.insert_bool(false),
             _ => return None,
         };