about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-26 09:46:49 -0700
committerbors <bors@rust-lang.org>2013-07-26 09:46:49 -0700
commit544ef6cf35c2fbec9e425ef67bc73d1571b54135 (patch)
treec87f58eab89710de954ac9a4f161bcfd0f1776ff
parent15ab6fde7f37155385b4072f64e89d722b970fd3 (diff)
parent7078ab7324aef0ad04b4a79a514f2c1d59b73fe5 (diff)
downloadrust-544ef6cf35c2fbec9e425ef67bc73d1571b54135.tar.gz
rust-544ef6cf35c2fbec9e425ef67bc73d1571b54135.zip
auto merge of #8041 : dotdash/rust/const_if_else, r=huonw
-rw-r--r--src/librustc/middle/trans/common.rs6
-rw-r--r--src/librustc/middle/trans/controlflow.rs66
2 files changed, 34 insertions, 38 deletions
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 985c1048bc4..690e488d219 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -850,6 +850,12 @@ pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
     }
 }
 
+pub fn is_const(v: ValueRef) -> bool {
+    unsafe {
+        llvm::LLVMIsConstant(v) == True
+    }
+}
+
 pub fn const_to_int(v: ValueRef) -> c_longlong {
     unsafe {
         llvm::LLVMConstIntGetSExtValue(v)
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 2b6c1d82418..8c87766bbbe 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -65,44 +65,36 @@ pub fn trans_if(bcx: @mut Block,
 
     let _icx = push_ctxt("trans_if");
 
-    match cond.node {
-        // `if true` and `if false` can be trans'd more efficiently,
-        // by dropping branches that are known to be impossible.
-        ast::expr_lit(@ref l) => match l.node {
-            ast::lit_bool(true) => {
-                // if true { .. } [else { .. }]
-                let then_bcx_in = scope_block(bcx, thn.info(), "if_true_then");
-                let then_bcx_out = trans_block(then_bcx_in, thn, dest);
-                let then_bcx_out = trans_block_cleanups(then_bcx_out,
-                                                        block_cleanups(then_bcx_in));
-                Br(bcx, then_bcx_in.llbb);
-                return then_bcx_out;
+    let Result {bcx, val: cond_val} =
+        expr::trans_to_datum(bcx, cond).to_result();
+
+    let cond_val = bool_to_i1(bcx, cond_val);
+
+    // Drop branches that are known to be impossible
+    if is_const(cond_val) && !is_undef(cond_val) {
+        if const_to_uint(cond_val) == 1 {
+            // if true { .. } [else { .. }]
+            return do with_scope(bcx, thn.info(), "if_true_then") |bcx| {
+                let bcx_out = trans_block(bcx, thn, dest);
+                trans_block_cleanups(bcx_out, block_cleanups(bcx))
             }
-            ast::lit_bool(false) => {
-                match els {
-                    // if false { .. } else { .. }
-                    Some(elexpr) => {
-                        let (else_bcx_in, else_bcx_out) =
-                            trans_if_else(bcx, elexpr, dest, "if_false_else");
-                        Br(bcx, else_bcx_in.llbb);
-                        return else_bcx_out;
+        } else {
+            match els {
+                // if false { .. } else { .. }
+                Some(elexpr) => {
+                    return do with_scope(bcx, elexpr.info(), "if_false_then") |bcx| {
+                        let bcx_out = trans_if_else(bcx, elexpr, dest);
+                        trans_block_cleanups(bcx_out, block_cleanups(bcx))
                     }
-                    // if false { .. }
-                    None => return bcx,
                 }
+                // if false { .. }
+                None => return bcx,
             }
-            _ => {}
-        },
-        _ => {}
+        }
     }
 
-    let Result {bcx, val: cond_val} =
-        expr::trans_to_datum(bcx, cond).to_result();
-
     let then_bcx_in = scope_block(bcx, thn.info(), "then");
 
-    let cond_val = bool_to_i1(bcx, cond_val);
-
     let then_bcx_out = trans_block(then_bcx_in, thn, dest);
     let then_bcx_out = trans_block_cleanups(then_bcx_out,
                                             block_cleanups(then_bcx_in));
@@ -113,7 +105,8 @@ pub fn trans_if(bcx: @mut Block,
     // 'else' context
     let (else_bcx_in, next_bcx) = match els {
       Some(elexpr) => {
-          let (else_bcx_in, else_bcx_out) = trans_if_else(bcx, elexpr, dest, "else");
+          let else_bcx_in = scope_block(bcx, elexpr.info(), "else");
+          let else_bcx_out = trans_if_else(else_bcx_in, elexpr, dest);
           (else_bcx_in, join_blocks(bcx, [then_bcx_out, else_bcx_out]))
       }
       _ => {
@@ -131,9 +124,8 @@ pub fn trans_if(bcx: @mut Block,
     return next_bcx;
 
     // trans `else [ if { .. } ... | { .. } ]`
-    fn trans_if_else(bcx: @mut Block, elexpr: @ast::expr,
-                     dest: expr::Dest, scope_name: &str) -> (@mut Block, @mut Block) {
-        let else_bcx_in = scope_block(bcx, elexpr.info(), scope_name);
+    fn trans_if_else(else_bcx_in: @mut Block, elexpr: @ast::expr,
+                     dest: expr::Dest) -> @mut Block {
         let else_bcx_out = match elexpr.node {
             ast::expr_if(_, _, _) => {
                 let elseif_blk = ast_util::block_from_expr(elexpr);
@@ -143,11 +135,9 @@ pub fn trans_if(bcx: @mut Block,
                 trans_block(else_bcx_in, blk, dest)
             }
             // would be nice to have a constraint on ifs
-            _ => bcx.tcx().sess.bug("strange alternative in if")
+            _ => else_bcx_in.tcx().sess.bug("strange alternative in if")
         };
-        let else_bcx_out = trans_block_cleanups(else_bcx_out,
-                                                block_cleanups(else_bcx_in));
-        (else_bcx_in, else_bcx_out)
+        trans_block_cleanups(else_bcx_out, block_cleanups(else_bcx_in))
     }
 }