about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-15 13:41:05 +0000
committerbors <bors@rust-lang.org>2020-08-15 13:41:05 +0000
commitb9db927b68f4b2e9c3e648be35b412ac1839ec54 (patch)
treeb24c1420b4906c19a153d85e436029d31478ace5
parent80fb3f3139c7dee7f211964c6a0b3ccb04b83d5e (diff)
parentaf9b9e4ec874c4bc5c771841d491e02d02d5636a (diff)
downloadrust-b9db927b68f4b2e9c3e648be35b412ac1839ec54.tar.gz
rust-b9db927b68f4b2e9c3e648be35b412ac1839ec54.zip
Auto merge of #75537 - tmiasko:match-branch-simplify, r=oli-obk
MatchBranchSimplification: fix equal const bool assignments

The match branch simplification is applied when target blocks contain
statements that are either equal or perform a const bool assignment with
different values to the same place.

Previously, when constructing new statements, only statements from a
single block had been examined. This lead to a misoptimization when
statements are equal because the assign the *same* const bool value to
the same place.

Fix the issue by examining statements from both blocks when deciding on
replacement.

Additionally:

* Copy discriminant instead of moving it since it might be necessary to use its
  value more than once.
* Optimize when switching on copy operand

Based on #75508.

r? @oli-obk  / @JulianKnodt
-rw-r--r--src/librustc_index/vec.rs11
-rw-r--r--src/librustc_mir/transform/match_branches.rs116
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit156
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit156
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit26
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit26
-rw-r--r--src/test/mir-opt/matches_reduce_branches.rs29
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit40
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit40
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit40
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit40
-rw-r--r--src/test/mir-opt/matches_u8.rs32
12 files changed, 649 insertions, 63 deletions
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
index 63f63133a2c..2420f82c041 100644
--- a/src/librustc_index/vec.rs
+++ b/src/librustc_index/vec.rs
@@ -680,6 +680,17 @@ impl<I: Idx, T> IndexVec<I, T> {
         }
     }
 
+    /// Returns mutable references to three distinct elements or panics otherwise.
+    #[inline]
+    pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
+        let (ai, bi, ci) = (a.index(), b.index(), c.index());
+        assert!(ai != bi && bi != ci && ci != ai);
+        let len = self.raw.len();
+        assert!(ai < len && bi < len && ci < len);
+        let ptr = self.raw.as_mut_ptr();
+        unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) }
+    }
+
     pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
         IndexVec { raw: self.raw, _marker: PhantomData }
     }
diff --git a/src/librustc_mir/transform/match_branches.rs b/src/librustc_mir/transform/match_branches.rs
index 74da6d5e629..c1d574d6ef2 100644
--- a/src/librustc_mir/transform/match_branches.rs
+++ b/src/librustc_mir/transform/match_branches.rs
@@ -4,10 +4,37 @@ use rustc_middle::ty::TyCtxt;
 
 pub struct MatchBranchSimplification;
 
-// What's the intent of this pass?
-// If one block is found that switches between blocks which both go to the same place
-// AND both of these blocks set a similar const in their ->
-// condense into 1 block based on discriminant AND goto the destination afterwards
+/// If a source block is found that switches between two blocks that are exactly
+/// the same modulo const bool assignments (e.g., one assigns true another false
+/// to the same place), merge a target block statements into the source block,
+/// using Eq / Ne comparison with switch value where const bools value differ.
+///
+/// For example:
+///
+/// ```rust
+/// bb0: {
+///     switchInt(move _3) -> [42_isize: bb1, otherwise: bb2];
+/// }
+///
+/// bb1: {
+///     _2 = const true;
+///     goto -> bb3;
+/// }
+///
+/// bb2: {
+///     _2 = const false;
+///     goto -> bb3;
+/// }
+/// ```
+///
+/// into:
+///
+/// ```rust
+/// bb0: {
+///    _2 = Eq(move _3, const 42_isize);
+///    goto -> bb3;
+/// }
+/// ```
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
@@ -16,12 +43,12 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
         'outer: for bb_idx in bbs.indices() {
             let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
                 TerminatorKind::SwitchInt {
-                    discr: Operand::Move(ref place),
+                    discr: Operand::Copy(ref place) | Operand::Move(ref place),
                     switch_ty,
                     ref targets,
                     ref values,
                     ..
-                } if targets.len() == 2 && values.len() == 1 => {
+                } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => {
                     (place, values[0], switch_ty, targets[0], targets[1])
                 }
                 // Only optimize switch int statements
@@ -42,49 +69,64 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
             }
             for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
                 match (&f.kind, &s.kind) {
-                    // If two statements are exactly the same just ignore them.
-                    (f_s, s_s) if f_s == s_s => (),
+                    // If two statements are exactly the same, we can optimize.
+                    (f_s, s_s) if f_s == s_s => {}
 
+                    // If two statements are const bool assignments to the same place, we can optimize.
                     (
                         StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if lhs_f == lhs_s => {
-                        if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) {
-                            // This should also be a bool because it's writing to the same place
-                            let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
-                            if f_c != s_c {
-                                // have to check this here because f_c & s_c might have
-                                // different spans.
-                                continue;
-                            }
-                        }
-                        continue 'outer;
-                    }
-                    // If there are not exclusively assignments, then ignore this
+                    ) if lhs_f == lhs_s
+                        && f_c.literal.ty.is_bool()
+                        && s_c.literal.ty.is_bool()
+                        && f_c.literal.try_eval_bool(tcx, param_env).is_some()
+                        && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {}
+
+                    // Otherwise we cannot optimize. Try another block.
                     _ => continue 'outer,
                 }
             }
-            // Take owenership of items now that we know we can optimize.
+            // Take ownership of items now that we know we can optimize.
             let discr = discr.clone();
-            let (from, first) = bbs.pick2_mut(bb_idx, first);
 
-            let new_stmts = first.statements.iter().cloned().map(|mut s| {
-                if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind {
-                    if let Rvalue::Use(Operand::Constant(c)) = rhs {
-                        let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                        let const_cmp = Operand::const_from_scalar(
-                            tcx,
-                            switch_ty,
-                            crate::interpret::Scalar::from_uint(val, size),
-                            rustc_span::DUMMY_SP,
-                        );
-                        if let Some(c) = c.literal.try_eval_bool(tcx, param_env) {
-                            let op = if c { BinOp::Eq } else { BinOp::Ne };
-                            *rhs = Rvalue::BinaryOp(op, Operand::Move(discr), const_cmp);
+            // We already checked that first and second are different blocks,
+            // and bb_idx has a different terminator from both of them.
+            let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
+
+            let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| {
+                match (&f.kind, &s.kind) {
+                    (f_s, s_s) if f_s == s_s => (*f).clone(),
+
+                    (
+                        StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
+                        StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
+                    ) => {
+                        // From earlier loop we know that we are dealing with bool constants only:
+                        let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
+                        let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
+                        if f_b == s_b {
+                            // Same value in both blocks. Use statement as is.
+                            (*f).clone()
+                        } else {
+                            // Different value between blocks. Make value conditional on switch condition.
+                            let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                            let const_cmp = Operand::const_from_scalar(
+                                tcx,
+                                switch_ty,
+                                crate::interpret::Scalar::from_uint(val, size),
+                                rustc_span::DUMMY_SP,
+                            );
+                            let op = if f_b { BinOp::Eq } else { BinOp::Ne };
+                            let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp);
+                            Statement {
+                                source_info: f.source_info,
+                                kind: StatementKind::Assign(box (*lhs, rhs)),
+                            }
                         }
                     }
+
+                    _ => unreachable!(),
                 }
-                s
             });
             from.statements.extend(new_stmts);
             from.terminator_mut().kind = first.terminator().kind.clone();
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit
new file mode 100644
index 00000000000..968890e3a29
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit
@@ -0,0 +1,156 @@
+- // MIR for `bar` before MatchBranchSimplification
++ // MIR for `bar` after MatchBranchSimplification
+  
+  fn bar(_1: i32) -> (bool, bool, bool, bool) {
+      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9
+      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43
+      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+      scope 1 {
+          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          scope 2 {
+              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              scope 3 {
+                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  scope 4 {
+                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+-         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
++         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000007))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) }
++         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000007))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) }
++         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
+      }
+  
+      bb1: {
+          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:26:17: 26:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:27:17: 27:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:28:17: 28:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:29:17: 29:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      }
+  
+      bb2: {
+          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:19:17: 19:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:20:17: 20:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      }
+  
+      bb3: {
+          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7
+          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit
new file mode 100644
index 00000000000..968890e3a29
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit
@@ -0,0 +1,156 @@
+- // MIR for `bar` before MatchBranchSimplification
++ // MIR for `bar` after MatchBranchSimplification
+  
+  fn bar(_1: i32) -> (bool, bool, bool, bool) {
+      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9
+      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43
+      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+      scope 1 {
+          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          scope 2 {
+              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              scope 3 {
+                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  scope 4 {
+                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
+          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+-         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
++         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000007))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) }
++         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
++                                          // ty::Const
++                                          // + ty: i32
++                                          // + val: Value(Scalar(0x00000007))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) }
++         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x00))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
+      }
+  
+      bb1: {
+          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:26:17: 26:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:27:17: 27:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:28:17: 28:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:29:17: 29:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      }
+  
+      bb2: {
+          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:19:17: 19:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:20:17: 20:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+      }
+  
+      bb3: {
+          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7
+          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
+          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
+          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
+          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
+          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
+          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
index df94c897e92..a33db001f44 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
@@ -2,23 +2,23 @@
 + // MIR for `foo` after MatchBranchSimplification
   
   fn foo(_1: std::option::Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
-+         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
++         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
 +                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
       }
   
       bb1: {
@@ -44,23 +44,23 @@
       }
   
       bb3: {
-          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
       }
   
       bb4: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
       }
   
       bb5: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
index 06849b4a5d9..3eb5b01fbf4 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
@@ -2,23 +2,23 @@
 + // MIR for `foo` after MatchBranchSimplification
   
   fn foo(_1: std::option::Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
-+         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
++         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x0000000000000000))
 +                                          // mir::Constant
 +                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
       }
   
       bb1: {
@@ -44,23 +44,23 @@
       }
   
       bb3: {
-          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
       }
   
       bb4: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
       }
   
       bb5: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
index 91b6bfc836b..ebc88d2fbd1 100644
--- a/src/test/mir-opt/matches_reduce_branches.rs
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -1,5 +1,6 @@
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
+// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
 
 fn foo(bar: Option<()>) {
     if matches!(bar, None) {
@@ -7,7 +8,35 @@ fn foo(bar: Option<()>) {
     }
 }
 
+fn bar(i: i32) -> (bool, bool, bool, bool) {
+    let a;
+    let b;
+    let c;
+    let d;
+
+    match i {
+        7 => {
+            a = false;
+            b = true;
+            c = false;
+            d = true;
+            ()
+        }
+        _ => {
+            a = true;
+            b = false;
+            c = false;
+            d = true;
+            ()
+        }
+    };
+
+    (a, b, c, d)
+}
+
+
 fn main() {
   let _ = foo(None);
   let _ = foo(Some(()));
+  let _ = bar(0);
 }
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit
new file mode 100644
index 00000000000..c41bd999dc9
--- /dev/null
+++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit
@@ -0,0 +1,40 @@
+- // MIR for `exhaustive_match` before MatchBranchSimplification
++ // MIR for `exhaustive_match` after MatchBranchSimplification
+  
+  fn exhaustive_match(_1: E) -> u8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26
+      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+      }
+  
+      bb1: {
+          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:14:17: 14:18
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:14:17: 14:18
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
+      }
+  
+      bb2: {
+          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:13:17: 13:18
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:13:17: 13:18
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
+      }
+  
+      bb3: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:16:2: 16:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit
new file mode 100644
index 00000000000..c41bd999dc9
--- /dev/null
+++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit
@@ -0,0 +1,40 @@
+- // MIR for `exhaustive_match` before MatchBranchSimplification
++ // MIR for `exhaustive_match` after MatchBranchSimplification
+  
+  fn exhaustive_match(_1: E) -> u8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26
+      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
+      }
+  
+      bb1: {
+          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:14:17: 14:18
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:14:17: 14:18
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
+      }
+  
+      bb2: {
+          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:13:17: 13:18
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:13:17: 13:18
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
+      }
+  
+      bb3: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:16:2: 16:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit
new file mode 100644
index 00000000000..2c4bbc8095e
--- /dev/null
+++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit
@@ -0,0 +1,40 @@
+- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
+  
+  fn exhaustive_match_i8(_1: E) -> i8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29
+      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+      }
+  
+      bb1: {
+          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:22:17: 22:18
+                                           // ty::Const
+                                           // + ty: i8
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:22:17: 22:18
+                                           // + literal: Const { ty: i8, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
+      }
+  
+      bb2: {
+          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:21:17: 21:18
+                                           // ty::Const
+                                           // + ty: i8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:21:17: 21:18
+                                           // + literal: Const { ty: i8, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
+      }
+  
+      bb3: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:24:2: 24:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit
new file mode 100644
index 00000000000..2c4bbc8095e
--- /dev/null
+++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit
@@ -0,0 +1,40 @@
+- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
+  
+  fn exhaustive_match_i8(_1: E) -> i8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29
+      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
+      }
+  
+      bb1: {
+          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:22:17: 22:18
+                                           // ty::Const
+                                           // + ty: i8
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:22:17: 22:18
+                                           // + literal: Const { ty: i8, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
+      }
+  
+      bb2: {
+          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:21:17: 21:18
+                                           // ty::Const
+                                           // + ty: i8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_u8.rs:21:17: 21:18
+                                           // + literal: Const { ty: i8, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
+      }
+  
+      bb3: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:24:2: 24:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_u8.rs b/src/test/mir-opt/matches_u8.rs
new file mode 100644
index 00000000000..78373be48b6
--- /dev/null
+++ b/src/test/mir-opt/matches_u8.rs
@@ -0,0 +1,32 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff
+// EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
+
+pub enum E {
+    A,
+    B,
+}
+
+#[no_mangle]
+pub fn exhaustive_match(e: E) -> u8 {
+    match e {
+        E::A => 0,
+        E::B => 1,
+    }
+}
+
+#[no_mangle]
+pub fn exhaustive_match_i8(e: E) -> i8 {
+    match e {
+        E::A => 0,
+        E::B => 1,
+    }
+}
+
+fn main() {
+  assert_eq!(exhaustive_match(E::A), 0);
+  assert_eq!(exhaustive_match(E::B), 1);
+
+  assert_eq!(exhaustive_match_i8(E::A), 0);
+  assert_eq!(exhaustive_match_i8(E::B), 1);
+}