about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-04-25 00:10:59 +0200
committerGitHub <noreply@github.com>2022-04-25 00:10:59 +0200
commitddbeda130233c27d3a7ef2b1baa730614bc383d4 (patch)
treece178374f7464f710a9c8281a9b159d4cd62a88f
parent76aa9e5202070731aca982ab5d6922f211afd691 (diff)
parent4534188d4ba3d4b7475c5f9e8b275ebec2b810e8 (diff)
downloadrust-ddbeda130233c27d3a7ef2b1baa730614bc383d4.tar.gz
rust-ddbeda130233c27d3a7ef2b1baa730614bc383d4.zip
Rollup merge of #96090 - JakobDegen:mir-tests, r=nagisa
Implement MIR opt unit tests

This implements rust-lang/compiler-team#502 .

There's not much to say here, this implementation does everything as proposed. I also added the flag to a bunch of existing tests (mostly those to which I could add it without causing huge diffs due to changes in line numbers). Summarizing the changes to test outputs:
 - Every time an `MirPatch` is created, it adds a cleanup block to the body if it did not exist already. If this block is unused (as is usually the case), it usually gets removed soon after by some pass calling `SimplifyCFG` for unrelated reasons (in many cases this cycle happens quite a few times for a single body). We now run `SimplifyCFG` less often, so those blocks end up in some of our outputs. I looked at changing `MirPatch` to not do this, but that seemed too complicated for this PR. I may still do that in a follow-up.
 - The `InstCombine` test had set `-C opt-level=0` in its flags and so there were no storage markers. I don't really see a good motivation for doing this, so bringing it back in line with what everything else does seems correct.
 - One of the `EarlyOtherwiseBranch` tests had `UnreachableProp` running on it. Preventing that kind of thing is the goal of this feature, so this seems fine.

For the remaining tests for which this feature might be useful, we can gradually migrate them as opportunities present themselves.

In terms of documentation, I plan on submitting a PR to the rustc dev guide in the near future documenting this and other recent changes to MIR. If there's any other places to update, do let me know

r? `@nagisa`
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs21
-rw-r--r--compiler/rustc_session/src/options.rs19
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.rs2
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff24
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff6
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff6
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff6
-rw-r--r--src/test/mir-opt/early_otherwise_branch.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff6
-rw-r--r--src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff30
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff14
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff12
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.rs2
-rw-r--r--src/test/mir-opt/if-condition-int.rs2
-rw-r--r--src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff4
-rw-r--r--src/test/mir-opt/lower_slice_len.rs2
-rw-r--r--src/test/mir-opt/nrvo-simple.rs2
-rw-r--r--src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff4
-rw-r--r--src/tools/compiletest/src/header.rs7
-rw-r--r--src/tools/compiletest/src/runtest.rs6
30 files changed, 172 insertions, 38 deletions
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 6caa1032ba3..1327bf6fcd4 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -752,6 +752,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
+    tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
     tracked!(mir_opt_level, Some(4));
     tracked!(move_size_limit, Some(4096));
     tracked!(mutable_noalias, Some(true));
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 740a2168b41..2380391d09a 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -77,17 +77,30 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn
     let mut cnt = 0;
 
     let validate = tcx.sess.opts.debugging_opts.validate_mir;
+    let overridden_passes = &tcx.sess.opts.debugging_opts.mir_enable_passes;
+    trace!(?overridden_passes);
 
     if validate {
         validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
     }
 
     for pass in passes {
-        if !pass.is_enabled(&tcx.sess) {
-            continue;
-        }
-
         let name = pass.name();
+
+        if let Some((_, polarity)) = overridden_passes.iter().rev().find(|(s, _)| s == &*name) {
+            trace!(
+                pass = %name,
+                "{} as requested by flag",
+                if *polarity { "Running" } else { "Not running" },
+            );
+            if !polarity {
+                continue;
+            }
+        } else {
+            if !pass.is_enabled(&tcx.sess) {
+                continue;
+            }
+        }
         let dump_enabled = pass.is_mir_dump_enabled();
 
         if dump_enabled {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index df65409a8a0..96f50e57ac4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -368,6 +368,8 @@ mod desc {
     pub const parse_opt_langid: &str = "a language identifier";
     pub const parse_opt_pathbuf: &str = "a path";
     pub const parse_list: &str = "a space-separated list of strings";
+    pub const parse_list_with_polarity: &str =
+        "a comma-separated list of strings, with elements beginning with + or -";
     pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
     pub const parse_number: &str = "a number";
     pub const parse_opt_number: &str = parse_number;
@@ -529,6 +531,19 @@ mod parse {
         }
     }
 
+    crate fn parse_list_with_polarity(slot: &mut Vec<(String, bool)>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                for s in s.split(",") {
+                    let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
+                    slot.push((pass_name.to_string(), &s[..1] == "+"));
+                }
+                true
+            }
+            None => false,
+        }
+    }
+
     crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
         if let Some(v) = v {
             ld.line = false;
@@ -1318,6 +1333,10 @@ options! {
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
+    mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
+        "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+        enabled, overriding all other checks. Passes that are not specified are enabled or \
+        disabled by other flags as usual."),
     mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
         "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
     move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
diff --git a/src/test/mir-opt/combine_clone_of_primitives.rs b/src/test/mir-opt/combine_clone_of_primitives.rs
index 0972d2d68a1..7cc50a86e21 100644
--- a/src/test/mir-opt/combine_clone_of_primitives.rs
+++ b/src/test/mir-opt/combine_clone_of_primitives.rs
@@ -1,4 +1,4 @@
-// compile-flags: -C opt-level=0 -Z inline_mir=no
+// unit-test: InstCombine
 // ignore-wasm32 compiled with panic=abort by default
 
 // EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index 678e965cd67..fdc016a95d5 100644
--- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -23,9 +23,15 @@
       }
   
       bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
           _2 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
           _3 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
           _4 = &((*_1).2: [f32; 3]);       // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 -         _7 = &(*_2);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 -         _6 = &(*_7);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
 +         _7 = _2;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
@@ -37,6 +43,10 @@
       }
   
       bb1: {
+          StorageDead(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9
+          StorageLive(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _10 = &(*_3);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _9 = &(*_10);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -         _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
@@ -50,6 +60,10 @@
       }
   
       bb2: {
+          StorageDead(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11
+          StorageLive(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _13 = &(*_4);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _12 = &(*_13);                   // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -         _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
@@ -63,10 +77,20 @@
       }
   
       bb3: {
+          StorageDead(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
           Deinit(_0);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          StorageDead(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
           return;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
       }
   
diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
index e40274dc393..038a1afc58b 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
@@ -68,8 +68,10 @@
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2
-+     }
-+ 
+      }
+  
+-     bb5 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
index 4f2b9696f8c..75549c1b3dd 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
@@ -32,7 +32,7 @@
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
--         switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb7]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
+-         switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
@@ -84,8 +84,8 @@
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2
       }
   
--     bb7: {
--         unreachable;                     // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15
+-     bb7 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2
 +     bb5: {
 +         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
index 96c7e46853f..30726d8621e 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -68,8 +68,10 @@
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2
-+     }
-+ 
+      }
+  
+-     bb5 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:21:1: 26:2
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs
index e0ebcfeebfc..7be9fbd0326 100644
--- a/src/test/mir-opt/early_otherwise_branch.rs
+++ b/src/test/mir-opt/early_otherwise_branch.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>) -> u32 {
     match (x, y) {
diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
index 379d0e9ea48..ddf26ad8ab3 100644
--- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
@@ -90,8 +90,10 @@
 +     bb4: {
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2
-+     }
-+ 
+      }
+  
+-     bb6 (cleanup): {
+-         resume;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2
 +     bb5: {
 +         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
index 8527c01d756..76055e1330f 100644
--- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
+++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 {
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
index 6adc5194aec..4d2db490836 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
@@ -38,25 +38,29 @@
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
       }
   
       bb1: {
           _6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
       }
   
       bb2: {
           _0 = const 3_u32;                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
       }
   
       bb3: {
-          _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
-          switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+          unreachable;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
       }
   
       bb4: {
+          _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
+          switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 8:17
+      }
+  
+      bb5: {
           StorageLive(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
           _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
           StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25
@@ -64,28 +68,32 @@
           _0 = const 0_u32;                // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
           StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
           StorageDead(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
       }
   
-      bb5: {
+      bb6: {
           StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
           _11 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
           _0 = const 1_u32;                // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
           StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
       }
   
-      bb6: {
+      bb7: {
           StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
           _12 = (((_3.1: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
           _0 = const 2_u32;                // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
           StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
-          goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
+          goto -> bb8;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
       }
   
-      bb7: {
+      bb8: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2
       }
+  
+      bb9 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:1: 14:2
+      }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs
index 1f8c59df35f..ef766bbd4a6 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.rs
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // must not optimize as it does not follow the pattern of
 // left and right hand side being the same variant
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
index a2722660662..92a719d997d 100644
--- a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
@@ -19,7 +19,7 @@
   
       bb1: {
           _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
       }
   
       bb2: {
@@ -29,7 +29,7 @@
   
       bb3: {
           _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
       }
   
       bb4: {
@@ -37,7 +37,15 @@
           _5 = (((*_2) as Some).0: i32);   // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
           _0 = _5;                         // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+          goto -> bb5;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+      }
+  
+      bb5: {
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:27:2: 27:2
+      }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:1: 27:2
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
index 56b7c9a2db4..c43b32c7fc6 100644
--- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
@@ -19,12 +19,20 @@
   
       bb2: {
           _0 = const 1_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
       }
   
       bb3: {
           _0 = const 2_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50
-          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:14:2: 14:2
+      }
+  
+      bb5 (cleanup): {
+          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:1: 14:2
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.rs b/src/test/mir-opt/early_otherwise_branch_soundness.rs
index d2513213d79..cd458923245 100644
--- a/src/test/mir-opt/early_otherwise_branch_soundness.rs
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
 
 // Tests various cases that the `early_otherwise_branch` opt should *not* optimize
 
diff --git a/src/test/mir-opt/if-condition-int.rs b/src/test/mir-opt/if-condition-int.rs
index b34389a0ab5..398311e6bb8 100644
--- a/src/test/mir-opt/if-condition-int.rs
+++ b/src/test/mir-opt/if-condition-int.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O
+// unit-test: SimplifyComparisonIntegral
 // EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
 // EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
 // EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
diff --git a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
index dddb7acae2b..319a47367b3 100644
--- a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
@@ -26,5 +26,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:17:25: 17:26
           return;                          // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:16:1: 18:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
index 2ff8386b205..98a6c83cbff 100644
--- a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
@@ -30,5 +30,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:53:34: 53:35
           return;                          // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:52:1: 54:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
index fd4dcb2265e..4019021ede8 100644
--- a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
@@ -54,5 +54,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2
           return;                          // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:43:1: 49:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
index 40de48385f0..d4f100e289f 100644
--- a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:21:32: 21:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:20:1: 22:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
index 28c36aed84c..06d2c666aec 100644
--- a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:25:31: 25:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:24:1: 26:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
index 55932fee960..a7e4edf40a8 100644
--- a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
@@ -61,5 +61,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6
           return;                          // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2
       }
+  
+      bb7 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:32:1: 40:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
index c4574b32a59..47f69b85e89 100644
--- a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:29:32: 29:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:28:1: 30:2
+      }
   }
   
diff --git a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
index 88d9d5622b8..3920627d524 100644
--- a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
@@ -35,5 +35,9 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:12:31: 12:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2
       }
+  
+      bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/if-condition-int.rs:11:1: 13:2
+      }
   }
   
diff --git a/src/test/mir-opt/lower_slice_len.rs b/src/test/mir-opt/lower_slice_len.rs
index f2438e69749..12955aed1fb 100644
--- a/src/test/mir-opt/lower_slice_len.rs
+++ b/src/test/mir-opt/lower_slice_len.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=3
+// unit-test: LowerSliceLenCalls
 
 // EMIT_MIR lower_slice_len.bound.LowerSliceLenCalls.diff
 pub fn bound(index: usize, slice: &[u8]) -> u8 {
diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs
index ab46d7b94c7..5786ae62127 100644
--- a/src/test/mir-opt/nrvo-simple.rs
+++ b/src/test/mir-opt/nrvo-simple.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Zmir-opt-level=1
+// unit-test: RenameReturnPlace
 
 // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
 fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
index f438eaa0027..e07af6d5983 100644
--- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
+++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
@@ -39,5 +39,9 @@
 -         StorageDead(_2);                 // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2
       }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/nrvo-simple.rs:4:1: 8:2
+      }
   }
   
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 858a576dcb4..e6f058569db 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -157,6 +157,8 @@ pub struct TestProps {
     pub should_ice: bool,
     // If true, the stderr is expected to be different across bit-widths.
     pub stderr_per_bitwidth: bool,
+    // The MIR opt to unit test, if any
+    pub mir_unit_test: Option<String>,
 }
 
 mod directives {
@@ -189,6 +191,7 @@ mod directives {
     pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth";
     pub const INCREMENTAL: &'static str = "incremental";
     pub const KNOWN_BUG: &'static str = "known-bug";
+    pub const MIR_UNIT_TEST: &'static str = "unit-test";
     // This isn't a real directive, just one that is probably mistyped often
     pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
 }
@@ -232,6 +235,7 @@ impl TestProps {
             assembly_output: None,
             should_ice: false,
             stderr_per_bitwidth: false,
+            mir_unit_test: None,
         }
     }
 
@@ -392,6 +396,9 @@ impl TestProps {
                 config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth);
                 config.set_name_directive(ln, INCREMENTAL, &mut self.incremental);
                 config.set_name_directive(ln, KNOWN_BUG, &mut self.known_bug);
+                config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| {
+                    s.trim().to_string()
+                });
             });
         }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index aedddedac61..6d94fe3ebb9 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1856,10 +1856,14 @@ impl<'test> TestCx<'test> {
                 rustc.args(&[
                     "-Copt-level=1",
                     "-Zdump-mir=all",
-                    "-Zmir-opt-level=4",
                     "-Zvalidate-mir",
                     "-Zdump-mir-exclude-pass-number",
                 ]);
+                if let Some(pass) = &self.props.mir_unit_test {
+                    rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);
+                } else {
+                    rustc.arg("-Zmir-opt-level=4");
+                }
 
                 let mir_dump_dir = self.get_mir_dump_dir();
                 let _ = fs::remove_dir_all(&mir_dump_dir);