about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2023-02-24 16:32:59 -0500
committerBen Kimock <kimockb@gmail.com>2023-03-18 14:29:13 -0400
commit2a628bd99c39b69e88b24c622e3d246dd5573353 (patch)
treefb44fcfc03e7e5c6d89d7a13b40f0239a679ebe4
parent41eda69516dd3ee217ae07c0efa369d31f630405 (diff)
downloadrust-2a628bd99c39b69e88b24c622e3d246dd5573353.tar.gz
rust-2a628bd99c39b69e88b24c622e3d246dd5573353.zip
Remove duplicate switch targets
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs16
-rw-r--r--tests/mir-opt/instcombine_duplicate_switch_targets.assert_zero.InstCombine.diff21
-rw-r--r--tests/mir-opt/instcombine_duplicate_switch_targets.rs27
3 files changed, 63 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index 4182da1957e..c926390aa2b 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -4,7 +4,7 @@ use crate::MirPass;
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
     BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
-    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
+    SourceInfo, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, UnOp,
 };
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
@@ -44,6 +44,7 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
                 &mut block.terminator.as_mut().unwrap(),
                 &mut block.statements,
             );
+            ctx.combine_duplicate_switch_targets(&mut block.terminator.as_mut().unwrap());
         }
     }
 }
@@ -217,6 +218,19 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
         terminator.kind = TerminatorKind::Goto { target: destination_block };
     }
 
+    fn combine_duplicate_switch_targets(&self, terminator: &mut Terminator<'tcx>) {
+        let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind
+        else { return };
+
+        let otherwise = targets.otherwise();
+        if targets.iter().any(|t| t.1 == otherwise) {
+            *targets = SwitchTargets::new(
+                targets.iter().filter(|t| t.1 != otherwise),
+                targets.otherwise(),
+            );
+        }
+    }
+
     fn combine_intrinsic_assert(
         &self,
         terminator: &mut Terminator<'tcx>,
diff --git a/tests/mir-opt/instcombine_duplicate_switch_targets.assert_zero.InstCombine.diff b/tests/mir-opt/instcombine_duplicate_switch_targets.assert_zero.InstCombine.diff
new file mode 100644
index 00000000000..e04079453d2
--- /dev/null
+++ b/tests/mir-opt/instcombine_duplicate_switch_targets.assert_zero.InstCombine.diff
@@ -0,0 +1,21 @@
+- // MIR for `assert_zero` before InstCombine
++ // MIR for `assert_zero` after InstCombine
+  
+  fn assert_zero(_1: u8) -> u8 {
+      let mut _0: u8;                      // return place in scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+0:37: +0:39
+  
+      bb0: {
+-         switchInt(_1) -> [0: bb2, 1: bb1, otherwise: bb1]; // scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+3:13: +7:14
++         switchInt(_1) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+3:13: +7:14
+      }
+  
+      bb1: {
+          unreachable;                     // scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+10:13: +10:26
+      }
+  
+      bb2: {
+          _0 = _1;                         // scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+13:13: +13:20
+          return;                          // scope 0 at $DIR/instcombine_duplicate_switch_targets.rs:+14:13: +14:21
+      }
+  }
+  
diff --git a/tests/mir-opt/instcombine_duplicate_switch_targets.rs b/tests/mir-opt/instcombine_duplicate_switch_targets.rs
new file mode 100644
index 00000000000..ef3b487afa3
--- /dev/null
+++ b/tests/mir-opt/instcombine_duplicate_switch_targets.rs
@@ -0,0 +1,27 @@
+#![feature(custom_mir, core_intrinsics)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+// unit-test: InstCombine
+
+// EMIT_MIR instcombine_duplicate_switch_targets.assert_zero.InstCombine.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub unsafe fn assert_zero(x: u8) -> u8 {
+    mir!(
+        {
+            match x {
+                0 => retblock,
+                1 => unreachable,
+                _ => unreachable,
+            }
+        }
+        unreachable = {
+            Unreachable()
+        }
+        retblock = {
+            RET = x;
+            Return()
+        }
+    )
+}