about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Simulacrum <mark.simulacrum@gmail.com>2018-06-03 18:18:05 -0600
committerGitHub <noreply@github.com>2018-06-03 18:18:05 -0600
commite7ae1b26481664e1cc4b920dba9e59cedb8bd692 (patch)
treedc5b4257a6a733735fa31c4a125d7b01bcfa3fa1
parent79dd148458ba2e4756fcd86c8e48afbb29ece15d (diff)
parent4f4f7dfc00d69b8a94638ed1d9e666ada9911217 (diff)
downloadrust-e7ae1b26481664e1cc4b920dba9e59cedb8bd692.tar.gz
rust-e7ae1b26481664e1cc4b920dba9e59cedb8bd692.zip
Rollup merge of #51323 - nikic:switch-int-lowering, r=nagisa
Generate br for all two target SwitchInts

Instead of only for booleans. This means that `if let` also becomes a br.

Apart from making the IR slightly simpler, this is supported by FastISel (#4353).
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs19
1 files changed, 14 insertions, 5 deletions
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 1669059a760..14d20b6dbe2 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -191,14 +191,23 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
 
             mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
                 let discr = self.codegen_operand(&bx, discr);
-                if switch_ty == bx.tcx().types.bool {
+                if targets.len() == 2 {
+                    // If there are two targets, emit br instead of switch
                     let lltrue = llblock(self, targets[0]);
                     let llfalse = llblock(self, targets[1]);
-                    if let [0] = values[..] {
-                        bx.cond_br(discr.immediate(), llfalse, lltrue);
+                    if switch_ty == bx.tcx().types.bool {
+                        // Don't generate trivial icmps when switching on bool
+                        if let [0] = values[..] {
+                            bx.cond_br(discr.immediate(), llfalse, lltrue);
+                        } else {
+                            assert_eq!(&values[..], &[1]);
+                            bx.cond_br(discr.immediate(), lltrue, llfalse);
+                        }
                     } else {
-                        assert_eq!(&values[..], &[1]);
-                        bx.cond_br(discr.immediate(), lltrue, llfalse);
+                        let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx);
+                        let llval = C_uint_big(switch_llty, values[0]);
+                        let cmp = bx.icmp(llvm::IntEQ, discr.immediate(), llval);
+                        bx.cond_br(cmp, lltrue, llfalse);
                     }
                 } else {
                     let (otherwise, targets) = targets.split_last().unwrap();