about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/transform/mod.rs4
-rw-r--r--src/librustc_mir/transform/simplify_try.rs352
-rw-r--r--src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff31
-rw-r--r--src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff31
-rw-r--r--src/test/mir-opt/simplify-arm.rs32
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff45
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff37
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff58
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff45
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff109
-rw-r--r--src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff100
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff53
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir22
-rw-r--r--src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir19
-rw-r--r--src/test/mir-opt/simplify_try_if_let.rs40
-rw-r--r--src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff127
16 files changed, 1032 insertions, 73 deletions
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 220691c1570..7ad5baac205 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -317,12 +317,12 @@ fn run_optimization_passes<'tcx>(
         //   2. It creates additional possibilities for some MIR optimizations to trigger
         // FIXME(#70073): Why is this done here and not in `post_borrowck_cleanup`?
         &deaggregator::Deaggregator,
+        &simplify_try::SimplifyArmIdentity,
+        &simplify_try::SimplifyBranchSame,
         &copy_prop::CopyPropagation,
         &simplify_branches::SimplifyBranches::new("after-copy-prop"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"),
-        &simplify_try::SimplifyArmIdentity,
-        &simplify_try::SimplifyBranchSame,
         &simplify::SimplifyCfg::new("final"),
         &simplify::SimplifyLocals,
     ];
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index d22c2d90600..41ffa659441 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -11,9 +11,12 @@
 
 use crate::transform::{simplify, MirPass, MirSource};
 use itertools::Itertools as _;
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
+use std::iter::{Enumerate, Peekable};
+use std::slice::Iter;
 
 /// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
 ///
@@ -21,7 +24,8 @@ use rustc_target::abi::VariantIdx;
 ///
 /// ```rust
 /// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
-/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
+/// _TMP_2 = _LOCAL_TMP;
+/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2;
 /// discriminant(_LOCAL_0) = VAR_IDX;
 /// ```
 ///
@@ -32,50 +36,320 @@ use rustc_target::abi::VariantIdx;
 /// ```
 pub struct SimplifyArmIdentity;
 
+#[derive(Debug)]
+struct ArmIdentityInfo<'tcx> {
+    /// Storage location for the variant's field
+    local_temp_0: Local,
+    /// Storage location holding the variant being read from
+    local_1: Local,
+    /// The variant field being read from
+    vf_s0: VarField<'tcx>,
+    /// Index of the statement which loads the variant being read
+    get_variant_field_stmt: usize,
+
+    /// Tracks each assignment to a temporary of the variant's field
+    field_tmp_assignments: Vec<(Local, Local)>,
+
+    /// Storage location holding the variant's field that was read from
+    local_tmp_s1: Local,
+    /// Storage location holding the enum that we are writing to
+    local_0: Local,
+    /// The variant field being written to
+    vf_s1: VarField<'tcx>,
+
+    /// Storage location that the discriminant is being written to
+    set_discr_local: Local,
+    /// The variant being written
+    set_discr_var_idx: VariantIdx,
+
+    /// Index of the statement that should be overwritten as a move
+    stmt_to_overwrite: usize,
+    /// SourceInfo for the new move
+    source_info: SourceInfo,
+
+    /// Indices of matching Storage{Live,Dead} statements encountered.
+    /// (StorageLive index,, StorageDead index, Local)
+    storage_stmts: Vec<(usize, usize, Local)>,
+
+    /// The statements that should be removed (turned into nops)
+    stmts_to_remove: Vec<usize>,
+}
+
+fn get_arm_identity_info<'a, 'tcx>(stmts: &'a [Statement<'tcx>]) -> Option<ArmIdentityInfo<'tcx>> {
+    // This can't possibly match unless there are at least 3 statements in the block
+    // so fail fast on tiny blocks.
+    if stmts.len() < 3 {
+        return None;
+    }
+
+    let mut tmp_assigns = Vec::new();
+    let mut nop_stmts = Vec::new();
+    let mut storage_stmts = Vec::new();
+    let mut storage_live_stmts = Vec::new();
+    let mut storage_dead_stmts = Vec::new();
+
+    type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>;
+
+    fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+        matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_))
+    }
+
+    /// Eats consecutive Statements which match `test`, performing the specified `action` for each.
+    /// The iterator `stmt_iter` is not advanced if none were matched.
+    fn try_eat<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        test: impl Fn(&'a Statement<'tcx>) -> bool,
+        mut action: impl FnMut(usize, &'a Statement<'tcx>) -> (),
+    ) {
+        while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) {
+            let (idx, stmt) = stmt_iter.next().unwrap();
+
+            action(idx, stmt);
+        }
+    }
+
+    /// Eats consecutive `StorageLive` and `StorageDead` Statements.
+    /// The iterator `stmt_iter` is not advanced if none were found.
+    fn try_eat_storage_stmts<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        storage_live_stmts: &mut Vec<(usize, Local)>,
+        storage_dead_stmts: &mut Vec<(usize, Local)>,
+    ) {
+        try_eat(stmt_iter, is_storage_stmt, |idx, stmt| {
+            if let StatementKind::StorageLive(l) = stmt.kind {
+                storage_live_stmts.push((idx, l));
+            } else if let StatementKind::StorageDead(l) = stmt.kind {
+                storage_dead_stmts.push((idx, l));
+            }
+        })
+    }
+
+    fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+        use rustc_middle::mir::StatementKind::Assign;
+        if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind {
+            place.as_local().is_some() && p.as_local().is_some()
+        } else {
+            false
+        }
+    }
+
+    /// Eats consecutive `Assign` Statements.
+    // The iterator `stmt_iter` is not advanced if none were found.
+    fn try_eat_assign_tmp_stmts<'a, 'tcx>(
+        stmt_iter: &mut StmtIter<'a, 'tcx>,
+        tmp_assigns: &mut Vec<(Local, Local)>,
+        nop_stmts: &mut Vec<usize>,
+    ) {
+        try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| {
+            use rustc_middle::mir::StatementKind::Assign;
+            if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) =
+                &stmt.kind
+            {
+                tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap()));
+                nop_stmts.push(idx);
+            }
+        })
+    }
+
+    fn find_storage_live_dead_stmts_for_local<'tcx>(
+        local: Local,
+        stmts: &[Statement<'tcx>],
+    ) -> Option<(usize, usize)> {
+        trace!("looking for {:?}", local);
+        let mut storage_live_stmt = None;
+        let mut storage_dead_stmt = None;
+        for (idx, stmt) in stmts.iter().enumerate() {
+            if stmt.kind == StatementKind::StorageLive(local) {
+                storage_live_stmt = Some(idx);
+            } else if stmt.kind == StatementKind::StorageDead(local) {
+                storage_dead_stmt = Some(idx);
+            }
+        }
+
+        Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX)))
+    }
+
+    // Try to match the expected MIR structure with the basic block we're processing.
+    // We want to see something that looks like:
+    // ```
+    // (StorageLive(_) | StorageDead(_));*
+    // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
+    // (StorageLive(_) | StorageDead(_));*
+    // (tmp_n+1 = tmp_n);*
+    // (StorageLive(_) | StorageDead(_));*
+    // (tmp_n+1 = tmp_n);*
+    // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp;
+    // discriminant(LOCAL_FROM) = VariantIdx;
+    // (StorageLive(_) | StorageDead(_));*
+    // ```
+    let mut stmt_iter = stmts.iter().enumerate().peekable();
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    let (get_variant_field_stmt, stmt) = stmt_iter.next()?;
+    let (local_tmp_s0, local_1, vf_s0) = match_get_variant_field(stmt)?;
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
+
+    let (idx, stmt) = stmt_iter.next()?;
+    let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?;
+    nop_stmts.push(idx);
+
+    let (idx, stmt) = stmt_iter.next()?;
+    let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?;
+    let discr_stmt_source_info = stmt.source_info;
+    nop_stmts.push(idx);
+
+    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
+
+    for (live_idx, live_local) in storage_live_stmts {
+        if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) {
+            let (dead_idx, _) = storage_dead_stmts.swap_remove(i);
+            storage_stmts.push((live_idx, dead_idx, live_local));
+
+            if live_local == local_tmp_s0 {
+                nop_stmts.push(get_variant_field_stmt);
+            }
+        }
+    }
+
+    nop_stmts.sort();
+
+    // Use one of the statements we're going to discard between the point
+    // where the storage location for the variant field becomes live and
+    // is killed.
+    let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?;
+    let stmt_to_overwrite =
+        nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx);
+
+    Some(ArmIdentityInfo {
+        local_temp_0: local_tmp_s0,
+        local_1,
+        vf_s0,
+        get_variant_field_stmt,
+        field_tmp_assignments: tmp_assigns,
+        local_tmp_s1,
+        local_0,
+        vf_s1,
+        set_discr_local,
+        set_discr_var_idx,
+        stmt_to_overwrite: *stmt_to_overwrite?,
+        source_info: discr_stmt_source_info,
+        storage_stmts,
+        stmts_to_remove: nop_stmts,
+    })
+}
+
+fn optimization_applies<'tcx>(
+    opt_info: &ArmIdentityInfo<'tcx>,
+    local_decls: &IndexVec<Local, LocalDecl<'tcx>>,
+) -> bool {
+    trace!("testing if optimization applies...");
+
+    // FIXME(wesleywiser): possibly relax this restriction?
+    if opt_info.local_0 == opt_info.local_1 {
+        trace!("NO: moving into ourselves");
+        return false;
+    } else if opt_info.vf_s0 != opt_info.vf_s1 {
+        trace!("NO: the field-and-variant information do not match");
+        return false;
+    } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty {
+        // FIXME(Centril,oli-obk): possibly relax to same layout?
+        trace!("NO: source and target locals have different types");
+        return false;
+    } else if (opt_info.local_0, opt_info.vf_s0.var_idx)
+        != (opt_info.set_discr_local, opt_info.set_discr_var_idx)
+    {
+        trace!("NO: the discriminants do not match");
+        return false;
+    }
+
+    // Verify the assigment chain consists of the form b = a; c = b; d = c; etc...
+    if opt_info.field_tmp_assignments.len() == 0 {
+        trace!("NO: no assignments found");
+    }
+    let mut last_assigned_to = opt_info.field_tmp_assignments[0].1;
+    let source_local = last_assigned_to;
+    for (l, r) in &opt_info.field_tmp_assignments {
+        if *r != last_assigned_to {
+            trace!("NO: found unexpected assignment {:?} = {:?}", l, r);
+            return false;
+        }
+
+        last_assigned_to = *l;
+    }
+
+    if source_local != opt_info.local_temp_0 {
+        trace!(
+            "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}",
+            source_local,
+            opt_info.local_temp_0
+        );
+        return false;
+    } else if last_assigned_to != opt_info.local_tmp_s1 {
+        trace!(
+            "NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}",
+            last_assigned_to,
+            opt_info.local_tmp_s1
+        );
+        return false;
+    }
+
+    trace!("SUCCESS: optimization applies!");
+    return true;
+}
+
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
-    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        trace!("running SimplifyArmIdentity on {:?}", source);
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for bb in basic_blocks {
-            // Need 3 statements:
-            let (s0, s1, s2) = match &mut *bb.statements {
-                [s0, s1, s2] => (s0, s1, s2),
-                _ => continue,
-            };
+            if let Some(opt_info) = get_arm_identity_info(&bb.statements) {
+                trace!("got opt_info = {:#?}", opt_info);
+                if !optimization_applies(&opt_info, local_decls) {
+                    debug!("optimization skipped for {:?}", source);
+                    continue;
+                }
 
-            // Pattern match on the form we want:
-            let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
-                None => continue,
-                Some(x) => x,
-            };
-            let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
-                None => continue,
-                Some(x) => x,
-            };
-            if local_tmp_s0 != local_tmp_s1
-                // Avoid moving into ourselves.
-                || local_0 == local_1
-                // The field-and-variant information match up.
-                || vf_s0 != vf_s1
-                // Source and target locals have the same type.
-                // FIXME(Centril | oli-obk): possibly relax to same layout?
-                || local_decls[local_0].ty != local_decls[local_1].ty
-                // We're setting the discriminant of `local_0` to this variant.
-                || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
-            {
-                continue;
-            }
+                // Also remove unused Storage{Live,Dead} statements which correspond
+                // to temps used previously.
+                for (live_idx, dead_idx, local) in &opt_info.storage_stmts {
+                    // The temporary that we've read the variant field into is scoped to this block,
+                    // so we can remove the assignment.
+                    if *local == opt_info.local_temp_0 {
+                        bb.statements[opt_info.get_variant_field_stmt].make_nop();
+                    }
 
-            // Right shape; transform!
-            s0.source_info = s2.source_info;
-            match &mut s0.kind {
-                StatementKind::Assign(box (place, rvalue)) => {
-                    *place = local_0.into();
-                    *rvalue = Rvalue::Use(Operand::Move(local_1.into()));
+                    for (left, right) in &opt_info.field_tmp_assignments {
+                        if local == left || local == right {
+                            bb.statements[*live_idx].make_nop();
+                            bb.statements[*dead_idx].make_nop();
+                        }
+                    }
                 }
-                _ => unreachable!(),
+
+                // Right shape; transform
+                for stmt_idx in opt_info.stmts_to_remove {
+                    bb.statements[stmt_idx].make_nop();
+                }
+
+                let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
+                stmt.source_info = opt_info.source_info;
+                stmt.kind = StatementKind::Assign(box (
+                    opt_info.local_0.into(),
+                    Rvalue::Use(Operand::Move(opt_info.local_1.into())),
+                ));
+
+                bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
+
+                trace!("block is now {:?}", bb.statements);
             }
-            s1.make_nop();
-            s2.make_nop();
         }
     }
 }
@@ -129,7 +403,7 @@ fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)>
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
 struct VarField<'tcx> {
     field: Field,
     field_ty: Ty<'tcx>,
diff --git a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
index bf24bfb2c57..6199e2c5662 100644
--- a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
@@ -35,9 +35,38 @@
                                            // mir::Constant
                                            // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
+          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      }
+  
+      bb1: {
+          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25
+      }
+  
+      bb3: {
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
-          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:35: 20:36
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb4: {
           StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
           _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
                                            // ty::Const
diff --git a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
index ff7183e57d2..bf875c6a555 100644
--- a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
@@ -35,9 +35,38 @@
                                            // mir::Constant
                                            // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
+          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      }
+  
+      bb1: {
+          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:24: 19:25
+      }
+  
+      bb3: {
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
-          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:20:35: 20:36
+          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      }
+  
+      bb4: {
           StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
           _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
                                            // ty::Const
diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs
new file mode 100644
index 00000000000..0e3f86501bb
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Z mir-opt-level=1
+// EMIT_MIR rustc.id.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id.SimplifyBranchSame.diff
+// EMIT_MIR rustc.id_result.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id_result.SimplifyBranchSame.diff
+// EMIT_MIR rustc.id_try.SimplifyArmIdentity.diff
+// EMIT_MIR rustc.id_try.SimplifyBranchSame.diff
+
+fn id(o: Option<u8>) -> Option<u8> {
+    match o {
+        Some(v) => Some(v),
+        None => None,
+    }
+}
+
+fn id_result(r: Result<u8, i32>) -> Result<u8, i32> {
+    match r {
+        Ok(x) => Ok(x),
+        Err(y) => Err(y),
+    }
+}
+
+fn id_try(r: Result<u8, i32>) -> Result<u8, i32> {
+    let x = r?;
+    Ok(x)
+}
+
+fn main() {
+    id(None);
+    id_result(Ok(4));
+    id_try(Ok(4));
+}
diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..8d08267d75b
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff
@@ -0,0 +1,45 @@
+- // MIR for `id` before SimplifyArmIdentity
++ // MIR for `id` after SimplifyArmIdentity
+  
+  fn id(_1: std::option::Option<u8>) -> std::option::Option<u8> {
+      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8
+      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
+      scope 1 {
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      }
+  
+      bb1: {
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
+      }
+  
+      bb3: {
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+-         _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+-         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+-         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+-         ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+-         discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:27: 11:28
++         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..23fa9817f80
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff
@@ -0,0 +1,37 @@
+- // MIR for `id` before SimplifyBranchSame
++ // MIR for `id` after SimplifyBranchSame
+  
+  fn id(_1: std::option::Option<u8>) -> std::option::Option<u8> {
+      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8
+      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
+      scope 1 {
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+      }
+  
+      bb1: {
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
+      }
+  
+      bb3: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..e2a12ca5be2
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff
@@ -0,0 +1,58 @@
+- // MIR for `id_result` before SimplifyArmIdentity
++ // MIR for `id_result` after SimplifyArmIdentity
+  
+  fn id_result(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22
+      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+      }
+      scope 2 {
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+          switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      }
+  
+      bb1: {
+-         StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+-         _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+-         StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+-         _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+-         ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25
+-         StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:25: 19:26
++         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
+      }
+  
+      bb3: {
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+-         _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+-         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+-         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+-         ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:23: 18:24
++         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..9d1ff22dc51
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff
@@ -0,0 +1,45 @@
+- // MIR for `id_result` before SimplifyBranchSame
++ // MIR for `id_result` after SimplifyBranchSame
+  
+  fn id_result(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:16:14: 16:15
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:16:37: 16:52
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:18:21: 18:22
+      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+      }
+      scope 2 {
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+-         switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
++         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+      }
+  
+      bb1: {
+-         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+-     }
+- 
+-     bb2: {
+-         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
+-     }
+- 
+-     bb3: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
++         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6
+      }
+  
+-     bb4: {
++     bb2: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..ba6e1ac24cb
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff
@@ -0,0 +1,109 @@
+- // MIR for `id_try` before SimplifyArmIdentity
++ // MIR for `id_try` after SimplifyArmIdentity
+  
+  fn id_try(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+      }
+      scope 2 {
+          debug err => _6;                 // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
+          scope 3 {
+          }
+      }
+      scope 4 {
+          debug val => _10;                // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
+          scope 5 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _3 = const <std::result::Result<u8, i32> as std::ops::Try>::into_result(move _4) -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+                                           // ty::Const
+                                           // + ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      }
+  
+      bb2: {
+-         StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+-         _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+-         _2 = _10;                        // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15
+-         StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
++         _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+-         StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
+-         ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb3: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      }
+  
+      bb4: {
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _9 = _6;                         // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _8 = const <i32 as std::convert::From<i32>>::from(move _9) -> bb5; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:14: 24:15
+                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          StorageDead(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _0 = const <std::result::Result<u8, i32> as std::ops::Try>::from_error(move _8) -> bb6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb6: {
+          StorageDead(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb7: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff
new file mode 100644
index 00000000000..4061c5e74ac
--- /dev/null
+++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff
@@ -0,0 +1,100 @@
+- // MIR for `id_try` before SimplifyBranchSame
++ // MIR for `id_try` after SimplifyBranchSame
+  
+  fn id_try(_1: std::result::Result<u8, i32>) -> std::result::Result<u8, i32> {
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+      }
+      scope 2 {
+          debug err => _6;                 // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
+          scope 3 {
+          }
+      }
+      scope 4 {
+          debug val => _10;                // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
+          scope 5 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
+          _3 = const <std::result::Result<u8, i32> as std::ops::Try>::into_result(move _4) -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+                                           // ty::Const
+                                           // + ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(std::result::Result<u8, i32>) -> std::result::Result<<std::result::Result<u8, i32> as std::ops::Try>::Ok, <std::result::Result<u8, i32> as std::ops::Try>::Error> {<std::result::Result<u8, i32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+      }
+  
+      bb2: {
+          _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb3: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+      }
+  
+      bb4: {
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _9 = _6;                         // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _8 = const <i32 as std::convert::From<i32>>::from(move _9) -> bb5; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:14: 24:15
+                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as std::convert::From<i32>>::from}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          StorageDead(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          _0 = const <std::result::Result<u8, i32> as std::ops::Try>::from_error(move _8) -> bb6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+                                           // ty::Const
+                                           // + ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm.rs:24:13: 24:15
+                                           // + literal: Const { ty: fn(<std::result::Result<u8, i32> as std::ops::Try>::Error) -> std::result::Result<u8, i32> {<std::result::Result<u8, i32> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb6: {
+          StorageDead(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
+          goto -> bb7;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  
+      bb7: {
+          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
index 009153cfd49..58c5313909f 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
@@ -15,16 +15,16 @@
       let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
       let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
       scope 1 {
-          debug y => _10;                  // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+          debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
       }
       scope 2 {
           debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
           scope 3 {
               scope 7 {
-                  debug t => _6;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                  debug t => _9;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
               }
               scope 8 {
-                  debug v => _6;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                  debug v => _8;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
                   let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
               }
           }
@@ -35,31 +35,54 @@
           }
       }
       scope 6 {
-          debug self => _1;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+          debug self => _4;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
       }
   
       bb0: {
-          _5 = discriminant(_1);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+          _3 = move _4;                    // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
           switchInt(move _5) -> [0isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
       }
   
       bb1: {
--         _10 = ((_1 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
--         ((_0 as Ok).0: u32) = move _10;  // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+-         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+-         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+-         _2 = _10;                        // scope 5 at $DIR/simplify_try.rs:6:13: 6:15
+-         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
++         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+-         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:7:8: 7:9
+-         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
 -         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
           goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
       }
   
       bb2: {
--         _6 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
--         ((_0 as Err).0: i32) = move _6;  // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_8);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_9);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         _9 = _6;                         // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         _8 = move _9;                    // scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+-         StorageDead(_9);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageLive(_12);                // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         _12 = move _8;                   // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
 -         discriminant(_0) = 1;            // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         _0 = move _1;                    // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         nop;                             // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
-+         nop;                             // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageDead(_12);                // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+-         StorageDead(_8);                 // scope 3 at $DIR/simplify_try.rs:6:14: 6:15
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
++         _0 = move _3;                    // scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
           goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
       }
   
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
index e5661a47201..be61e5e2a9f 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyBranchSame.after.mir
@@ -14,16 +14,16 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
     let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
     let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9
     scope 1 {
-        debug y => _10;                  // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+        debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
     }
     scope 2 {
         debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
         scope 3 {
             scope 7 {
-                debug t => _6;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                debug t => _9;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
             }
             scope 8 {
-                debug v => _6;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                debug v => _8;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
                 let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15
             }
         }
@@ -34,18 +34,24 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
         }
     }
     scope 6 {
-        debug self => _1;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+        debug self => _4;                // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
     }
 
     bb0: {
-        _5 = discriminant(_1);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:6:13: 6:14
+        _3 = move _4;                    // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
+        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
         goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
     }
 
     bb1: {
-        _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-        nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
-        nop;                             // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:6:15: 6:16
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
         goto -> bb2;                     // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
     }
 
diff --git a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
index 989931ed0ea..b12036f6a03 100644
--- a/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
+++ b/src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyLocals.after.mir
@@ -3,24 +3,27 @@
 fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
     debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18
     let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57
-    let _2: i32;                         // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-    let _3: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
+    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10
+    let _3: i32;                         // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let mut _4: i32;                     // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let mut _5: i32;                     // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+    let _6: u32;                         // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15
     scope 1 {
-        debug y => _3;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
+        debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10
     }
     scope 2 {
-        debug err => _2;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
+        debug err => _3;                 // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15
         scope 3 {
             scope 7 {
-                debug t => _2;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
+                debug t => _5;           // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
             }
             scope 8 {
-                debug v => _2;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
+                debug v => _4;           // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
             }
         }
     }
     scope 4 {
-        debug val => _3;                 // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
+        debug val => _6;                 // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15
         scope 5 {
         }
     }
@@ -29,7 +32,9 @@ fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i
     }
 
     bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:6:9: 6:10
         _0 = move _1;                    // scope 1 at $DIR/simplify_try.rs:7:5: 7:10
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:8:1: 8:2
         return;                          // scope 0 at $DIR/simplify_try.rs:8:2: 8:2
     }
 }
diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs
new file mode 100644
index 00000000000..daa961c3c8c
--- /dev/null
+++ b/src/test/mir-opt/simplify_try_if_let.rs
@@ -0,0 +1,40 @@
+// compile-flags: -Zmir-opt-level=1
+// EMIT_MIR rustc.{{impl}}-append.SimplifyArmIdentity.diff
+
+use std::ptr::NonNull;
+
+pub struct LinkedList {
+    head: Option<NonNull<Node>>,
+    tail: Option<NonNull<Node>>,
+}
+
+pub struct Node {
+    next: Option<NonNull<Node>>,
+}
+
+impl LinkedList {
+    pub fn new() -> Self {
+        Self { head: None, tail: None }
+    }
+
+    pub fn append(&mut self, other: &mut Self) {
+        match self.tail {
+            None => { },
+            Some(mut tail) => {
+                // `as_mut` is okay here because we have exclusive access to the entirety
+                // of both lists.
+                if let Some(other_head) = other.head.take() {
+                    unsafe {
+                        tail.as_mut().next = Some(other_head);
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn main() {
+    let mut one = LinkedList::new();
+    let mut two = LinkedList::new();
+    one.append(&mut two);
+}
diff --git a/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff
new file mode 100644
index 00000000000..6ccec937b9b
--- /dev/null
+++ b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff
@@ -0,0 +1,127 @@
+- // MIR for `<impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append` before SimplifyArmIdentity
++ // MIR for `<impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append` after SimplifyArmIdentity
+  
+  fn <impl at $DIR/simplify_try_if_let.rs:15:1: 34:2>::append(_1: &mut LinkedList, _2: &mut LinkedList) -> () {
+      debug self => _1;                    // in scope 0 at $DIR/simplify_try_if_let.rs:20:19: 20:28
+      debug other => _2;                   // in scope 0 at $DIR/simplify_try_if_let.rs:20:30: 20:35
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_try_if_let.rs:20:48: 20:48
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+      let mut _4: std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+      let mut _5: std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+      let mut _6: &mut std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+      let mut _7: isize;                   // in scope 0 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+      let mut _9: std::option::Option<std::ptr::NonNull<Node>>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+      let mut _10: std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+      let mut _11: &mut Node;              // in scope 0 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+      let mut _12: &mut std::ptr::NonNull<Node>; // in scope 0 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+      scope 1 {
+          debug tail => _4;                // in scope 1 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          let _8: std::ptr::NonNull<Node>; // in scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          scope 2 {
+              debug other_head => _8;      // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          _3 = discriminant(((*_1).1: std::option::Option<std::ptr::NonNull<Node>>)); // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+          switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+      }
+  
+      bb1: {
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          _4 = ((((*_1).1: std::option::Option<std::ptr::NonNull<Node>>) as Some).0: std::ptr::NonNull<Node>); // scope 0 at $DIR/simplify_try_if_let.rs:23:18: 23:26
+          StorageLive(_5);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+          StorageLive(_6);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+          _6 = &mut ((*_2).0: std::option::Option<std::ptr::NonNull<Node>>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53
+          _5 = const std::option::Option::<std::ptr::NonNull<Node>>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60
+                                           // ty::Const
+                                           // + ty: for<'r> fn(&'r mut std::option::Option<std::ptr::NonNull<Node>>) -> std::option::Option<std::ptr::NonNull<Node>> {std::option::Option::<std::ptr::NonNull<Node>>::take}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:26:54: 26:58
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::option::Option<std::ptr::NonNull<Node>>) -> std::option::Option<std::ptr::NonNull<Node>> {std::option::Option::<std::ptr::NonNull<Node>>::take}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:15: 21:24
+      }
+  
+      bb3: {
+          _0 = const ();                   // scope 0 at $DIR/simplify_try_if_let.rs:22:21: 22:24
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:22:21: 22:24
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb9;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:9: 32:10
+      }
+  
+      bb4: {
+          StorageDead(_6);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:59: 26:60
+          _7 = discriminant(_5);           // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+          switchInt(move _7) -> [1isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+      }
+  
+      bb5: {
+          _0 = const ();                   // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:26:17: 30:18
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb8;                     // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+      }
+  
+      bb6: {
+          StorageLive(_8);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          _8 = ((_5 as Some).0: std::ptr::NonNull<Node>); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39
+          StorageLive(_9);                 // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         StorageLive(_10);                // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+-         _10 = _8;                        // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61
+-         ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         discriminant(_9) = 1;            // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+-         StorageDead(_10);                // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62
++         _9 = move _5;                    // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62
+          StorageLive(_11);                // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+          StorageLive(_12);                // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+          _12 = &mut _4;                   // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29
+          _11 = const std::ptr::NonNull::<Node>::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38
+                                           // ty::Const
+                                           // + ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull<Node>) -> &'r mut Node {std::ptr::NonNull::<Node>::as_mut}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:28:30: 28:36
+                                           // + literal: Const { ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull<Node>) -> &'r mut Node {std::ptr::NonNull::<Node>::as_mut}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb7: {
+          StorageDead(_12);                // scope 3 at $DIR/simplify_try_if_let.rs:28:37: 28:38
+          ((*_11).0: std::option::Option<std::ptr::NonNull<Node>>) = move _9; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:62
+          StorageDead(_9);                 // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62
+          StorageDead(_11);                // scope 3 at $DIR/simplify_try_if_let.rs:28:62: 28:63
+          _0 = const ();                   // scope 3 at $DIR/simplify_try_if_let.rs:27:21: 29:22
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_try_if_let.rs:27:21: 29:22
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_8);                 // scope 1 at $DIR/simplify_try_if_let.rs:30:17: 30:18
+          goto -> bb8;                     // scope 1 at $DIR/simplify_try_if_let.rs:26:17: 30:18
+      }
+  
+      bb8: {
+          StorageDead(_5);                 // scope 1 at $DIR/simplify_try_if_let.rs:31:13: 31:14
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try_if_let.rs:32:9: 32:10
+          goto -> bb9;                     // scope 0 at $DIR/simplify_try_if_let.rs:21:9: 32:10
+      }
+  
+      bb9: {
+          return;                          // scope 0 at $DIR/simplify_try_if_let.rs:33:6: 33:6
+      }
+  }
+