about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-05-31 21:36:15 +0200
committerNikita Popov <nikita.ppv@gmail.com>2018-06-02 22:21:01 +0200
commit4f4f7dfc00d69b8a94638ed1d9e666ada9911217 (patch)
treef899b10d36800d8e7a52a29e2723e4792660f67c
parent6de4ec679d7179251bef205427d52d093c40a787 (diff)
downloadrust-4f4f7dfc00d69b8a94638ed1d9e666ada9911217.tar.gz
rust-4f4f7dfc00d69b8a94638ed1d9e666ada9911217.zip
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.
-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();