From ccecc4f6bf3ba62b0c8be29791a0857ea742ae6b Mon Sep 17 00:00:00 2001
From: Simon Vandel Sillesen <simon.vandel@gmail.com>
Date: Sun, 4 Oct 2020 10:26:29 +0200
Subject: [PATCH 1/3] Drive-by formatting of comment

---
 compiler/rustc_mir/src/transform/simplify_try.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index 05a88828070fb..b42543c04eb3d 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -696,8 +696,8 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
     /// _0 = move _1;           // bb2
     /// ```
     /// In this case the two statements are equal iff
-    /// 1: _0 is an enum where the variant index 0 is fieldless, and
-    /// 2:  bb1 was targeted by a switch where the discriminant of _1 was switched on
+    /// - `_0` is an enum where the variant index 0 is fieldless, and
+    /// -  bb1 was targeted by a switch where the discriminant of `_1` was switched on
     fn statement_equality(
         &self,
         adt_matched_on: Place<'tcx>,

From 1e865709a685952d2fe30a84a9f338d294e8022d Mon Sep 17 00:00:00 2001
From: Simon Vandel Sillesen <simon.vandel@gmail.com>
Date: Sun, 4 Oct 2020 18:12:20 +0200
Subject: [PATCH 2/3] Make MatchBranchSimplification clean up after itself

---
 .../rustc_mir/src/transform/match_branches.rs |  11 +-
 ...ue_59352.num_to_digit.PreCodegen.after.mir |  70 +++++------
 ...s.bar.MatchBranchSimplification.32bit.diff |  39 +++---
 ...s.bar.MatchBranchSimplification.64bit.diff |  39 +++---
 ...s.foo.MatchBranchSimplification.32bit.diff |  36 +++---
 ...s.foo.MatchBranchSimplification.64bit.diff |  36 +++---
 ...ed_if.MatchBranchSimplification.32bit.diff | 113 +++++++++---------
 ...ed_if.MatchBranchSimplification.64bit.diff | 113 +++++++++---------
 .../not_equal_false.opt.InstCombine.diff      |  22 ++--
 9 files changed, 232 insertions(+), 247 deletions(-)

diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index 53eeecc780f6f..d9b004978e777 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -2,6 +2,8 @@ use crate::transform::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
+use super::simplify::simplify_cfg;
+
 pub struct MatchBranchSimplification;
 
 /// If a source block is found that switches between two blocks that are exactly
@@ -42,9 +44,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
             return;
         }
 
-        let param_env = tcx.param_env(body.source.def_id());
         let def_id = body.source.def_id();
+        let param_env = tcx.param_env(def_id);
+        
         let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
+        let mut should_cleanup = false;
         'outer: for bb_idx in bbs.indices() {
             if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) {
                 continue;
@@ -159,6 +163,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
             from.statements
                 .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
             from.terminator_mut().kind = first.terminator().kind.clone();
+            should_cleanup = true;
+        }
+
+        if should_cleanup {
+            simplify_cfg(body);
         }
     }
 }
diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
index 04a8c94e003c4..0f718a720f4cc 100644
--- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
+++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
@@ -3,47 +3,45 @@
 fn num_to_digit(_1: char) -> u32 {
     debug num => _1;                     // in scope 0 at $DIR/issue-59352.rs:12:21: 12:24
     let mut _0: u32;                     // return place in scope 0 at $DIR/issue-59352.rs:12:35: 12:38
-    let mut _2: bool;                    // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23
-    let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41
-    let mut _4: char;                    // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29
-    let mut _5: u32;                     // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23
-    let mut _10: isize;                  // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+    let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41
+    let mut _3: char;                    // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29
+    let mut _4: u32;                     // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+    let mut _9: isize;                   // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23
     scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue-59352.rs:14:8: 14:23
-        debug self => _8;                // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        debug radix => _5;               // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        let mut _6: &std::option::Option<u32>; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        let _7: std::option::Option<u32>; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        let mut _8: char;                // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        debug self => _7;                // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        debug radix => _4;               // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        let mut _5: &std::option::Option<u32>; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        let _6: std::option::Option<u32>; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        let mut _7: char;                // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23
         scope 2 (inlined Option::<u32>::is_some) { // at $DIR/issue-59352.rs:14:8: 14:23
-            debug self => _6;            // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23
+            debug self => _5;            // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23
         }
     }
     scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue-59352.rs:14:26: 14:50
-        debug self => _3;                // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50
-        let mut _9: isize;               // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50
+        debug self => _2;                // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50
+        let mut _8: isize;               // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50
         scope 4 {
             debug val => _0;             // in scope 4 at $DIR/issue-59352.rs:14:26: 14:50
         }
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
-        _8 = _1;                         // scope 0 at $DIR/issue-59352.rs:14:8: 14:11
-        StorageLive(_5);                 // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
-        _5 = const 8_u32;                // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+        _7 = _1;                         // scope 0 at $DIR/issue-59352.rs:14:8: 14:11
+        StorageLive(_4);                 // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+        _4 = const 8_u32;                // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+        StorageLive(_5);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
         StorageLive(_6);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        StorageLive(_7);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        _7 = char::methods::<impl char>::to_digit(move _8, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        _6 = char::methods::<impl char>::to_digit(move _7, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
                                          // mir::Constant
                                          // + span: $DIR/issue-59352.rs:14:8: 14:23
                                          // + literal: Const { ty: fn(char, u32) -> std::option::Option<u32> {std::char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
-        StorageLive(_3);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:41
-        StorageLive(_4);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:29
-        _4 = _1;                         // scope 0 at $DIR/issue-59352.rs:14:26: 14:29
-        _3 = char::methods::<impl char>::to_digit(move _4, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41
+        StorageLive(_2);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:41
+        StorageLive(_3);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:29
+        _3 = _1;                         // scope 0 at $DIR/issue-59352.rs:14:26: 14:29
+        _2 = char::methods::<impl char>::to_digit(move _3, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41
                                          // mir::Constant
                                          // + span: $DIR/issue-59352.rs:14:30: 14:38
                                          // + literal: Const { ty: fn(char, u32) -> std::option::Option<u32> {std::char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) }
@@ -55,25 +53,23 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb3: {
-        StorageDead(_4);                 // scope 0 at $DIR/issue-59352.rs:14:40: 14:41
-        StorageLive(_9);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:50
-        _9 = discriminant(_3);           // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
-        switchInt(move _9) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
+        StorageDead(_3);                 // scope 0 at $DIR/issue-59352.rs:14:40: 14:41
+        StorageLive(_8);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:50
+        _8 = discriminant(_2);           // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
+        switchInt(move _8) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
     }
 
     bb4: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-59352.rs:14:62: 14:63
         return;                          // scope 0 at $DIR/issue-59352.rs:15:2: 15:2
     }
 
     bb5: {
-        _6 = &_7;                        // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        _10 = discriminant((*_6));       // scope 2 at $DIR/issue-59352.rs:14:8: 14:23
-        _2 = Eq(_10, const 1_isize);     // scope 2 at $DIR/issue-59352.rs:14:8: 14:23
+        _5 = &_6;                        // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
+        _9 = discriminant((*_5));        // scope 2 at $DIR/issue-59352.rs:14:8: 14:23
+        StorageDead(_5);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
         StorageDead(_6);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        StorageDead(_7);                 // scope 1 at $DIR/issue-59352.rs:14:8: 14:23
-        StorageDead(_5);                 // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
-        switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63
+        StorageDead(_4);                 // scope 0 at $DIR/issue-59352.rs:14:8: 14:23
+        switchInt(move _9) -> [1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63
     }
 
     bb6: {
@@ -94,9 +90,9 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb8: {
-        _0 = move ((_3 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
-        StorageDead(_9);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:50
-        StorageDead(_3);                 // scope 0 at $DIR/issue-59352.rs:14:49: 14:50
+        _0 = move ((_2 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50
+        StorageDead(_8);                 // scope 0 at $DIR/issue-59352.rs:14:26: 14:50
+        StorageDead(_2);                 // scope 0 at $DIR/issue-59352.rs:14:49: 14:50
         goto -> bb4;                     // scope 0 at $DIR/issue-59352.rs:14:5: 14:63
     }
 }
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
index d3a29aa5d51c1..94a0b99986364 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
@@ -34,33 +34,30 @@
           StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
           StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
 -         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
+-     }
+- 
+-     bb1: {
+-         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
+-         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+-         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
+-         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-     }
+- 
+-     bb2: {
+-         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
+-         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
 +         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
 +         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
-+         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
-+         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
-+         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-+         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-      }
-  
-      bb1: {
-          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
-          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
-      }
-  
-      bb2: {
-          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
-          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
           _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
           _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
-      }
-  
-      bb3: {
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-     }
+- 
+-     bb3: {
++         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
           StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7
           StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
           _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
index d3a29aa5d51c1..94a0b99986364 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
@@ -34,33 +34,30 @@
           StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
           StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
 -         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
+-     }
+- 
+-     bb1: {
+-         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
+-         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+-         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
+-         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-     }
+- 
+-     bb2: {
+-         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
+-         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
 +         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
 +         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
-+         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
-+         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
-+         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-+         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-      }
-  
-      bb1: {
-          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
-          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
-      }
-  
-      bb2: {
-          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
-          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
           _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
           _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
-      }
-  
-      bb3: {
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-     }
+- 
+-     bb3: {
++         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
           StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7
           StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
           _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
index 20240348230f2..e43ec3de58d2d 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
@@ -16,29 +16,31 @@
 +         _4 = move _3;                    // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 +         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         switchInt(move _2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb1: {
-          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb2: {
-          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb3: {
-          switchInt(move _2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
-      }
-  
-      bb4: {
+-         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb2: {
+-         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb3: {
+-         switchInt(move _2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+-     }
+- 
+-     bb4: {
           _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:9:6: 9:6
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+-         goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
++         goto -> bb2;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
-      bb5: {
+-     bb5: {
++     bb2: {
           StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:5: 9:6
           return;                          // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2
       }
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
index 20240348230f2..e43ec3de58d2d 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
@@ -16,29 +16,31 @@
 +         _4 = move _3;                    // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 +         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         switchInt(move _2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb1: {
-          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb2: {
-          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb3: {
-          switchInt(move _2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
-      }
-  
-      bb4: {
+-         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb2: {
+-         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb3: {
+-         switchInt(move _2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+-     }
+- 
+-     bb4: {
           _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:9:6: 9:6
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+-         goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
++         goto -> bb2;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
-      bb5: {
+-     bb5: {
++     bb2: {
           StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:5: 9:6
           return;                          // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2
       }
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
index 1d895852354c9..68c1161d78457 100644
--- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
@@ -26,87 +26,82 @@
           StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
           _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
 -         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb1: {
+-         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb2: {
+-         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb3: {
 +         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
 +         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
 +         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
 +         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb1: {
-          _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
-          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb2: {
-          _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
-          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb3: {
           StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
 -         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb4: {
+-         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb5: {
+-         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb6: {
 +         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
 +         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
 +         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
 +         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-+         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb4: {
-          _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
-          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb5: {
-          _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
-          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb6: {
           StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
 -         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb7: {
+-         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb8: {
+-         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb9: {
 +         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
 +         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb7: {
-          _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
-          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb8: {
-          _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
-          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb9: {
           StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
 -         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb10: {
 +         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+-         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+-     }
+- 
+-     bb11: {
+-         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+-         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+-     }
+- 
+-     bb12: {
 +         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
 +         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb10: {
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
-          _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
-          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
-      }
-  
-      bb11: {
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
-          _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
-          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
-      }
-  
-      bb12: {
           StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
           _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
           StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
index 1d895852354c9..68c1161d78457 100644
--- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
@@ -26,87 +26,82 @@
           StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
           _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
 -         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb1: {
+-         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb2: {
+-         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+-     }
+- 
+-     bb3: {
 +         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
 +         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
 +         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
 +         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb1: {
-          _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
-          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb2: {
-          _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
-          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
-      }
-  
-      bb3: {
           StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
 -         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb4: {
+-         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb5: {
+-         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+-     }
+- 
+-     bb6: {
 +         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
 +         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
 +         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
 +         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-+         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb4: {
-          _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
-          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb5: {
-          _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
-          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
-      }
-  
-      bb6: {
           StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
 -         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb7: {
+-         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb8: {
+-         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb9: {
 +         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
 +         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb7: {
-          _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
-          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb8: {
-          _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
-          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb9: {
           StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
 -         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+-     }
+- 
+-     bb10: {
 +         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
 +         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+-         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+-     }
+- 
+-     bb11: {
+-         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+-         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+-     }
+- 
+-     bb12: {
 +         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
 +         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-+         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
-      }
-  
-      bb10: {
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
-          _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
-          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
-      }
-  
-      bb11: {
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
-          _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
-          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
-      }
-  
-      bb12: {
           StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
           _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
           StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
index dc3a6a36d9eef..db9313e7822f1 100644
--- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
+++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
@@ -19,7 +19,7 @@
           _6 = move _3;                    // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
           _2 = Eq(_6, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_6);                 // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
-          goto -> bb4;                     // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
   
       bb1: {
@@ -34,20 +34,6 @@
           _7 = move _5;                    // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
           _4 = Eq(_7, const 1_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_7);                 // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
-          goto -> bb5;                     // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
-      }
-  
-      bb3: {
-          StorageDead(_4);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
-          StorageDead(_2);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
-          return;                          // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2
-      }
-  
-      bb4: {
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-      }
-  
-      bb5: {
           StorageLive(_8);                 // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
           _8 = move _4;                    // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
 -         _0 = Ne(_8, const false);        // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
@@ -55,5 +41,11 @@
           StorageDead(_8);                 // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
           goto -> bb3;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
+  
+      bb3: {
+          StorageDead(_4);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
+          StorageDead(_2);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
+          return;                          // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2
+      }
   }
   

From 2d1e0adfe9fbe3e0ebdac3ba80b9781cb4f800f7 Mon Sep 17 00:00:00 2001
From: Simon Vandel Sillesen <simon.vandel@gmail.com>
Date: Sun, 4 Oct 2020 15:52:14 +0200
Subject: [PATCH 3/3] New pass to deduplicate blocks

---
 compiler/rustc_ast/src/ast.rs                 |   4 +-
 compiler/rustc_hir/src/hir.rs                 |  30 ++-
 compiler/rustc_middle/src/mir/coverage.rs     |  17 +-
 compiler/rustc_middle/src/mir/mod.rs          |  44 ++--
 compiler/rustc_middle/src/mir/terminator.rs   |   4 +-
 compiler/rustc_middle/src/ty/adjustment.rs    |   2 +-
 .../src/transform/deduplicate_blocks.rs       | 193 ++++++++++++++++++
 .../rustc_mir/src/transform/match_branches.rs |   2 +-
 compiler/rustc_mir/src/transform/mod.rs       |   2 +
 compiler/rustc_target/src/asm/mod.rs          |  43 +++-
 compiler/rustc_type_ir/src/lib.rs             |   2 +-
 ..._line_doc_comment_2.DeduplicateBlocks.diff | 101 +++++++++
 src/test/mir-opt/deduplicate_blocks.rs        |  13 ++
 .../inline/inline_diverging.h.Inline.diff     |   2 +-
 14 files changed, 422 insertions(+), 37 deletions(-)
 create mode 100644 compiler/rustc_mir/src/transform/deduplicate_blocks.rs
 create mode 100644 src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
 create mode 100644 src/test/mir-opt/deduplicate_blocks.rs

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3550055ac10d3..1d2f1f694cf5b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1979,7 +1979,7 @@ bitflags::bitflags! {
     }
 }
 
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, PartialOrd, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub enum InlineAsmTemplatePiece {
     String(String),
     Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
@@ -2067,7 +2067,7 @@ pub struct InlineAsm {
 /// Inline assembly dialect.
 ///
 /// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)]
 pub enum LlvmAsmDialect {
     Att,
     Intel,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 4df8c44e62b38..61586dd1a1c45 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1281,7 +1281,18 @@ impl Body<'hir> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(
+    Clone,
+    PartialEq,
+    PartialOrd,
+    Eq,
+    Hash,
+    HashStable_Generic,
+    Encodable,
+    Decodable,
+    Debug,
+    Copy
+)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1313,7 +1324,18 @@ impl GeneratorKind {
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(
+    Clone,
+    PartialEq,
+    PartialOrd,
+    Eq,
+    Hash,
+    HashStable_Generic,
+    Encodable,
+    Decodable,
+    Debug,
+    Copy
+)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -2308,7 +2330,7 @@ pub struct InlineAsm<'hir> {
     pub line_spans: &'hir [Span],
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
 pub struct LlvmInlineAsmOutput {
     pub constraint: Symbol,
     pub is_rw: bool,
@@ -2319,7 +2341,7 @@ pub struct LlvmInlineAsmOutput {
 // NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
 // it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
 // arena-allocated slice.
-#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)]
+#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
 pub struct LlvmInlineAsmInner {
     pub asm: Symbol,
     pub asm_str_style: StrStyle,
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 95096d0fb719c..eae02a8cbfcf1 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -92,7 +92,7 @@ impl From<InjectedExpressionId> for ExpressionOperandId {
     }
 }
 
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum CoverageKind {
     Counter {
         function_source_hash: u64,
@@ -148,7 +148,18 @@ impl Debug for CoverageKind {
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(
+    Clone,
+    TyEncodable,
+    TyDecodable,
+    Hash,
+    HashStable,
+    TypeFoldable,
+    PartialEq,
+    Eq,
+    PartialOrd,
+    Ord
+)]
 pub struct CodeRegion {
     pub file_name: Symbol,
     pub start_line: u32,
@@ -167,7 +178,7 @@ impl Debug for CodeRegion {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum Op {
     Subtract,
     Add,
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 718e81c84eddd..84766fc78612d 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -594,7 +594,7 @@ impl SourceInfo {
 // Borrow kinds
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(HashStable)]
+#[derive(Hash, HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     Shared,
@@ -1163,7 +1163,7 @@ pub struct BasicBlockData<'tcx> {
 }
 
 /// Information about an assertion failure.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
     Overflow(BinOp, O, O),
@@ -1174,7 +1174,17 @@ pub enum AssertKind<O> {
     ResumedAfterPanic(GeneratorKind),
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(
+    Clone,
+    Debug,
+    PartialEq,
+    PartialOrd,
+    TyEncodable,
+    TyDecodable,
+    Hash,
+    HashStable,
+    TypeFoldable
+)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -1449,7 +1459,7 @@ impl Statement<'_> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum StatementKind<'tcx> {
     /// Write the RHS Rvalue to the LHS Place.
     Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
@@ -1517,7 +1527,7 @@ impl<'tcx> StatementKind<'tcx> {
 }
 
 /// Describes what kind of retag is to be performed.
-#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
 pub enum RetagKind {
     /// The initial retag when entering a function.
     FnEntry,
@@ -1530,7 +1540,7 @@ pub enum RetagKind {
 }
 
 /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists.
-#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, HashStable, PartialEq)]
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)]
 pub enum FakeReadCause {
     /// Inject a fake read of the borrowed input at the end of each guards
     /// code.
@@ -1572,7 +1582,7 @@ pub enum FakeReadCause {
     ForIndex,
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub struct LlvmInlineAsm<'tcx> {
     pub asm: hir::LlvmInlineAsmInner,
     pub outputs: Box<[Place<'tcx>]>,
@@ -1619,7 +1629,7 @@ impl Debug for Statement<'_> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub struct Coverage {
     pub kind: CoverageKind,
     pub code_region: Option<CodeRegion>,
@@ -1915,7 +1925,7 @@ pub struct SourceScopeLocalData {
 
 /// These are values that can appear inside an rvalue. They are intentionally
 /// limited to prevent rvalues from being nested in one another.
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
     /// Copy: The value must be available for use afterwards.
     ///
@@ -2023,7 +2033,7 @@ impl<'tcx> Operand<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 /// Rvalues
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum Rvalue<'tcx> {
     /// x (either a move or copy, depending on type of x)
     Use(Operand<'tcx>),
@@ -2069,13 +2079,13 @@ pub enum Rvalue<'tcx> {
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CastKind {
     Misc,
     Pointer(PointerCast),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum AggregateKind<'tcx> {
     /// The type is of the element
     Array(Ty<'tcx>),
@@ -2092,7 +2102,7 @@ pub enum AggregateKind<'tcx> {
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum BinOp {
     /// The `+` operator (addition)
     Add,
@@ -2137,7 +2147,7 @@ impl BinOp {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum NullOp {
     /// Returns the size of a value of that type
     SizeOf,
@@ -2145,7 +2155,7 @@ pub enum NullOp {
     Box,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum UnOp {
     /// The `!` operator for logical inversion
     Not,
@@ -2315,7 +2325,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// this does not necessarily mean that they are `==` in Rust. In
 /// particular, one must be wary of `NaN`!
 
-#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2449,7 +2459,7 @@ impl<'tcx> UserTypeProjections {
 /// * `let (x, _): T = ...` -- here, the `projs` vector would contain
 ///   `field[0]` (aka `.0`), indicating that the type of `s` is
 ///   determined by finding the type of the `.0` field from `T`.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct UserTypeProjection {
     pub base: UserTypeAnnotationIndex,
     pub projs: Vec<ProjectionKind>,
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 709ffc3049ab8..b51a87f63b294 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -17,7 +17,7 @@ use std::slice;
 
 pub use super::query::*;
 
-#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
 pub struct SwitchTargets {
     /// Possible values. The locations to branch to in each case
     /// are found in the corresponding indices from the `targets` vector.
@@ -98,7 +98,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
 pub enum TerminatorKind<'tcx> {
     /// Block should have one successor in the graph; we jump there.
     Goto { target: BasicBlock },
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 89d0e13955122..a50dda69a0fcc 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -6,7 +6,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_macros::HashStable;
 use rustc_span::Span;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum PointerCast {
     /// Go from a fn-item type to a fn-pointer type.
     ReifyFnPointer,
diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
new file mode 100644
index 0000000000000..5f09159e91b20
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
@@ -0,0 +1,193 @@
+//! This pass finds basic blocks that are completely equal,
+//! and replaces all uses with just one of them.
+
+use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher};
+
+use crate::transform::MirPass;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::mir::visit::MutVisitor;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+use super::simplify::simplify_cfg;
+
+pub struct DeduplicateBlocks;
+
+impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
+            return;
+        }
+        debug!("Running DeduplicateBlocks on `{:?}`", body.source);
+        let duplicates = find_duplicates(body);
+        let has_opts_to_apply = !duplicates.is_empty();
+
+        if has_opts_to_apply {
+            let mut opt_applier = OptApplier { tcx, duplicates };
+            opt_applier.visit_body(body);
+            simplify_cfg(body);
+        }
+    }
+}
+
+struct OptApplier<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    duplicates: FxHashMap<BasicBlock, BasicBlock>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+        for target in terminator.successors_mut() {
+            if let Some(replacement) = self.duplicates.get(target) {
+                debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement);
+                *target = *replacement;
+            }
+        }
+
+        self.super_terminator(terminator, location);
+    }
+}
+
+fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap<BasicBlock, BasicBlock> {
+    let mut duplicates = FxHashMap::default();
+
+    let bbs_to_go_through =
+        body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count();
+
+    let mut same_hashes =
+        FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default());
+
+    // Go through the basic blocks backwards. This means that in case of duplicates,
+    // we can use the basic block with the highest index as the replacement for all lower ones.
+    // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes.
+    // Then we will see that bb2 is a duplicate of bb3,
+    // and insert bb2 with the replacement bb3 in the duplicates list.
+    // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list
+    // with replacement bb3.
+    // When the duplicates are removed, we will end up with only bb3.
+    for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup)
+    {
+        // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks
+        // that are unlikely to have duplicates, we stop early. The early bail number has been
+        // found experimentally by eprintln while compiling the crates in the rustc-perf suite.
+        if bbd.statements.len() > 10 {
+            continue;
+        }
+
+        let to_hash = BasicBlockHashable { basic_block_data: bbd };
+        let entry = same_hashes.entry(to_hash);
+        match entry {
+            Entry::Occupied(occupied) => {
+                // The basic block was already in the hashmap, which means we have a duplicate
+                let value = *occupied.get();
+                debug!("Inserting {:?} -> {:?}", bb, value);
+                duplicates.insert(bb, value).expect_none("key was already inserted");
+            }
+            Entry::Vacant(vacant) => {
+                vacant.insert(bb);
+            }
+        }
+    }
+
+    duplicates
+}
+
+struct BasicBlockHashable<'tcx, 'a> {
+    basic_block_data: &'a BasicBlockData<'tcx>,
+}
+
+impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        hash_statements(state, self.basic_block_data.statements.iter());
+        // Note that since we only hash the kind, we lose span information if we deduplicate the blocks
+        self.basic_block_data.terminator().kind.hash(state);
+    }
+}
+
+impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {}
+
+impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> {
+    fn eq(&self, other: &Self) -> bool {
+        self.basic_block_data.statements.len() == other.basic_block_data.statements.len()
+            && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind
+            && self
+                .basic_block_data
+                .statements
+                .iter()
+                .zip(&other.basic_block_data.statements)
+                .all(|(x, y)| statement_eq(&x.kind, &y.kind))
+    }
+}
+
+fn hash_statements<'a, 'tcx, H: Hasher>(
+    hasher: &mut H,
+    iter: impl Iterator<Item = &'a Statement<'tcx>>,
+) where
+    'tcx: 'a,
+{
+    for stmt in iter {
+        statement_hash(hasher, &stmt.kind);
+    }
+}
+
+fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) {
+    match stmt {
+        StatementKind::Assign(box (place, rvalue)) => {
+            place.hash(hasher);
+            rvalue_hash(hasher, rvalue)
+        }
+        x => x.hash(hasher),
+    };
+}
+
+fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'tcx>) {
+    match rvalue {
+        Rvalue::Use(op) => operand_hash(hasher, op),
+        x => x.hash(hasher),
+    };
+}
+
+fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'tcx>) {
+    match operand {
+        Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher),
+        x => x.hash(hasher),
+    };
+}
+
+fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool {
+    let res = match (lhs, rhs) {
+        (
+            StatementKind::Assign(box (place, rvalue)),
+            StatementKind::Assign(box (place2, rvalue2)),
+        ) => place == place2 && rvalue_eq(rvalue, rvalue2),
+        (x, y) => x == y,
+    };
+    debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
+    res
+}
+
+fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
+    let res = match (lhs, rhs) {
+        (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2),
+        (x, y) => x == y,
+    };
+    debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
+    res
+}
+
+fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
+    let res = match (lhs, rhs) {
+        (
+            Operand::Constant(box Constant { user_ty: _, literal, span: _ }),
+            Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }),
+        ) => literal == literal2,
+        (x, y) => x == y,
+    };
+    debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
+    res
+}
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index d9b004978e777..92b4ae397ae5b 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -46,7 +46,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
 
         let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
-        
+
         let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
         let mut should_cleanup = false;
         'outer: for bb_idx in bbs.indices() {
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 2786127513d38..6e264240f2eeb 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -25,6 +25,7 @@ pub mod const_debuginfo;
 pub mod const_prop;
 pub mod coverage;
 pub mod deaggregator;
+pub mod deduplicate_blocks;
 pub mod dest_prop;
 pub mod dump_mir;
 pub mod early_otherwise_branch;
@@ -510,6 +511,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &const_debuginfo::ConstDebugInfo,
         &simplify::SimplifyLocals,
         &multiple_return_terminators::MultipleReturnTerminators,
+        &deduplicate_blocks::DeduplicateBlocks,
     ];
 
     // Optimizations to run even if mir optimizations have been disabled.
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 3c65c84b0de41..dfc0989a9f8df 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -13,7 +13,7 @@ macro_rules! def_reg_class {
             $class:ident,
         )*
     }) => {
-        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
         #[allow(non_camel_case_types)]
         pub enum $arch_regclass {
             $($class,)*
@@ -62,7 +62,7 @@ macro_rules! def_regs {
         )*
     }) => {
         #[allow(unreachable_code)]
-        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+        #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
         #[allow(non_camel_case_types)]
         pub enum $arch_reg {
             $($reg,)*
@@ -207,7 +207,18 @@ impl FromStr for InlineAsmArch {
     }
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+#[derive(
+    Copy,
+    Clone,
+    Encodable,
+    Decodable,
+    Debug,
+    Eq,
+    PartialEq,
+    PartialOrd,
+    Hash,
+    HashStable_Generic
+)]
 pub enum InlineAsmReg {
     X86(X86InlineAsmReg),
     Arm(ArmInlineAsmReg),
@@ -313,7 +324,18 @@ impl InlineAsmReg {
     }
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+#[derive(
+    Copy,
+    Clone,
+    Encodable,
+    Decodable,
+    Debug,
+    Eq,
+    PartialEq,
+    PartialOrd,
+    Hash,
+    HashStable_Generic
+)]
 pub enum InlineAsmRegClass {
     X86(X86InlineAsmRegClass),
     Arm(ArmInlineAsmRegClass),
@@ -458,7 +480,18 @@ impl InlineAsmRegClass {
     }
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
+#[derive(
+    Copy,
+    Clone,
+    Encodable,
+    Decodable,
+    Debug,
+    Eq,
+    PartialEq,
+    PartialOrd,
+    Hash,
+    HashStable_Generic
+)]
 pub enum InlineAsmRegOrRegClass {
     Reg(InlineAsmReg),
     RegClass(InlineAsmRegClass),
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 7e70af21c03cd..fccd8b795ef56 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -427,7 +427,7 @@ impl UnifyKey for FloatVid {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable)]
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
new file mode 100644
index 0000000000000..b6e4469e87069
--- /dev/null
+++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
@@ -0,0 +1,101 @@
+- // MIR for `is_line_doc_comment_2` before DeduplicateBlocks
++ // MIR for `is_line_doc_comment_2` after DeduplicateBlocks
+  
+  fn is_line_doc_comment_2(_1: &str) -> bool {
+      debug s => _1;                       // in scope 0 at $DIR/deduplicate_blocks.rs:2:36: 2:37
+      let mut _0: bool;                    // return place in scope 0 at $DIR/deduplicate_blocks.rs:2:48: 2:52
+      let mut _2: &[u8];                   // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23
+      let mut _3: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31
+      let mut _4: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31
+      let mut _5: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37
+      let mut _6: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37
+      scope 1 (inlined core::str::<impl str>::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23
+          debug self => _7;                // in scope 1 at $DIR/deduplicate_blocks.rs:3:11: 3:23
+          let mut _7: &str;                // in scope 1 at $DIR/deduplicate_blocks.rs:3:11: 3:23
+          scope 2 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23
+          _7 = _1;                         // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12
+-         _2 = transmute::<&str, &[u8]>(move _7) -> bb14; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23
++         _2 = transmute::<&str, &[u8]>(move _7) -> bb12; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23
+                                           // mir::Constant
+                                           // + span: $DIR/deduplicate_blocks.rs:3:11: 3:23
+                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {std::intrinsics::transmute::<&str, &[u8]>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:10: 4:14
+      }
+  
+      bb2: {
+          switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:16: 4:20
+      }
+  
+      bb3: {
+          switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:22: 4:26
+      }
+  
+      bb4: {
+-         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:28: 4:32
++         switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:28: 4:32
+      }
+  
+      bb5: {
+          _3 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31
+          _4 = Ge(move _3, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31
+          switchInt(move _4) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31
+      }
+  
+      bb6: {
+          switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:10: 5:14
+      }
+  
+      bb7: {
+          switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:16: 5:20
+      }
+  
+      bb8: {
+-         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:22: 5:26
++         switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:22: 5:26
+      }
+  
+      bb9: {
+-         _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:7:14: 7:19
+-         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
+-     }
+- 
+-     bb10: {
+          _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:4:41: 4:46
+-         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
++         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
+      }
+  
+-     bb11: {
+-         _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:5:35: 5:39
+-         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
+-     }
+- 
+-     bb12: {
++     bb10: {
+          _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:6:35: 6:39
+-         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
++         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6
+      }
+  
+-     bb13: {
++     bb11: {
+          StorageDead(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/deduplicate_blocks.rs:9:2: 9:2
+      }
+  
+-     bb14: {
++     bb12: {
+          _5 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37
+          _6 = Ge(move _5, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37
+          switchInt(move _6) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37
+      }
+  }
+  
diff --git a/src/test/mir-opt/deduplicate_blocks.rs b/src/test/mir-opt/deduplicate_blocks.rs
new file mode 100644
index 0000000000000..f8f7361dc0d0e
--- /dev/null
+++ b/src/test/mir-opt/deduplicate_blocks.rs
@@ -0,0 +1,13 @@
+// EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
+pub const fn is_line_doc_comment_2(s: &str) -> bool {
+    match s.as_bytes() {
+        [b'/', b'/', b'/', b'/', ..] => false,
+        [b'/', b'/', b'/', ..] => true,
+        [b'/', b'/', b'!', ..] => true,
+        _ => false,
+    }
+}
+
+fn main() {
+    is_line_doc_comment_2("asd");
+}
diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
index 07994eb3c1661..e945629b6138b 100644
--- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -46,7 +46,7 @@
 +         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_7);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         _7 = const ();                   // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
-+         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22
++         goto -> bb1;                     // scope 4 at $DIR/inline-diverging.rs:22:5: 22:22
       }
   
       bb1: {